From 635c265f32d8a3f73402813d6a8dd47f2a363df5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 13 Jun 2009 10:12:59 +0200 Subject: ALSA: ctxfi - Replace atc lock to mutex The spinlock in atc can cause a sleep in lock: Kernel failure message 1: BUG: sleeping function called from invalid context at mm/slub.c:1599 in_atomic(): 0, irqs_disabled(): 1, pid: 2537, name: gstreamer-prope Pid: 2537, comm: gstreamer-prope Tainted: P 2.6.29.4-167.fc11.x86_64 #1 Call Trace: [] __might_sleep+0x10b/0x110 [] __kmalloc+0x73/0x130 [] ? daio_rsc_init+0xaa/0x125 [snd_ctxfi] [] dao_rsc_init+0x55/0x1c0 [snd_ctxfi] [] dao_rsc_reinit+0x55/0x5d [snd_ctxfi] [] ? _spin_lock_irqsave+0x32/0x3b [] atc_spdif_out_passthru+0x92/0x136 [snd_ctxfi] ... Since the lock path is no critical path, it can be gracefully replaced with a mutex. Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctatc.c | 22 +++++++++------------- sound/pci/ctxfi/ctatc.h | 4 ++-- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 80fb2baed7a..b0adc809400 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -259,7 +259,6 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) int n_amixer = apcm->substream->runtime->channels, i = 0; int device = apcm->substream->pcm->device; unsigned int pitch; - unsigned long flags; if (NULL != apcm->src) { /* Prepared pcm playback */ @@ -311,10 +310,10 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; for (i = 0; i < n_amixer; i++) { amixer = apcm->amixers[i]; - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); amixer->ops->setup(amixer, &src->rsc, INIT_VOL, atc->pcm[i+device*2]); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); src = src->ops->next_interleave(src); if (NULL == src) src = apcm->src; @@ -865,7 +864,6 @@ static int spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) { struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); - unsigned long flags; unsigned int rate = apcm->substream->runtime->rate; unsigned int status; int err; @@ -885,7 +883,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) return -ENOENT; } - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); dao->ops->get_spos(dao, &status); if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { status &= ((~IEC958_AES3_CON_FS) << 24); @@ -895,7 +893,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) } if ((rate != atc->pll_rate) && (32000 != rate)) err = atc_pll_init(atc, rate); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); return err; } @@ -908,7 +906,6 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) struct dao *dao; int err; int i; - unsigned long flags; if (NULL != apcm->src) return 0; @@ -934,13 +931,13 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; } /* Connect to SPDIFOO */ - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); dao = container_of(atc->daios[SPDIFOO], struct dao, daio); amixer = apcm->amixers[0]; dao->ops->set_left_input(dao, &amixer->rsc); amixer = apcm->amixers[1]; dao->ops->set_right_input(dao, &amixer->rsc); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); ct_timer_prepare(apcm->timer); @@ -1088,7 +1085,6 @@ static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) { - unsigned long flags; struct dao_desc da_dsc = {0}; struct dao *dao; int err; @@ -1096,7 +1092,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) struct rsc *rscs[2] = {NULL}; unsigned int spos = 0; - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); dao = container_of(atc->daios[SPDIFOO], struct dao, daio); da_dsc.msr = state ? 1 : atc->msr; da_dsc.passthru = state ? 1 : 0; @@ -1114,7 +1110,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) } dao->ops->set_spos(dao, spos); dao->ops->commit_write(dao); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); return err; } @@ -1572,7 +1568,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, atc->msr = msr; atc->chip_type = chip_type; - spin_lock_init(&atc->atc_lock); + mutex_init(&atc->atc_mutex); /* Find card model */ err = atc_identify_card(atc); diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index a03347232e8..9fe620ea5f3 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -19,7 +19,7 @@ #define CTATC_H #include -#include +#include #include #include #include @@ -90,7 +90,7 @@ struct ct_atc { void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index); - spinlock_t atc_lock; + struct mutex atc_mutex; int (*pcm_playback_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm); -- cgit v1.2.3 From e46b0c8c08cd97eb8f9a523986908add3ece0cc6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 13 Jun 2009 10:16:43 +0200 Subject: ALSA: hda - Add quirk for Acer Aspire 6935G Added model=acer-aspire-8930g for Acer Aspire 6935G (1025:0146). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 337d2a59c67..d22b2606801 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9014,6 +9014,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", ALC888_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", + ALC888_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", -- cgit v1.2.3 From f708eb1d71dc8ffb184da9f0bc53461c6dc10653 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jun 2009 12:31:38 +0200 Subject: ALSA: intel8x0 - Fix PCM position craziness The PCM pointer callback sometimes returns invalid positions and this screws up the hw_ptr updater in PCM core. Especially since now the jiffies check is optional with xrun_debug, the invalid position is handled as is, and causes serious sound skips, etc. This patch simplifies the position-fix strategy in intel8x0 to be more robust: - just falls back to the last position if bogus position is detected - another sanity check for the backward move of the position due to a race of register update and the base-index update This patch is applicable also for 2.6.30. Tested-by: David Miller Cc: Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 173bebf9f51..8aa5687f392 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -356,8 +356,6 @@ struct ichdev { unsigned int position; unsigned int pos_shift; unsigned int last_pos; - unsigned long last_pos_jiffies; - unsigned int jiffy_to_bytes; int frags; int lvi; int lvi_frag; @@ -844,7 +842,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; ichdev->last_pos = ichdev->position; - ichdev->last_pos_jiffies = jiffies; break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; @@ -1048,7 +1045,6 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; } snd_intel8x0_setup_periods(chip, ichdev); - ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ; return 0; } @@ -1073,19 +1069,23 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; } while (timeout--); + ptr = ichdev->last_pos; if (ptr1 != 0) { ptr1 <<= ichdev->pos_shift; ptr = ichdev->fragsize1 - ptr1; ptr += position; - ichdev->last_pos = ptr; - ichdev->last_pos_jiffies = jiffies; - } else { - ptr1 = jiffies - ichdev->last_pos_jiffies; - if (ptr1) - ptr1 -= 1; - ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes; - ptr %= ichdev->size; + if (ptr < ichdev->last_pos) { + unsigned int pos_base, last_base; + pos_base = position / ichdev->fragsize1; + last_base = ichdev->last_pos / ichdev->fragsize1; + /* another sanity check; ptr1 can go back to full + * before the base position is updated + */ + if (pos_base == last_base) + ptr = ichdev->last_pos; + } } + ichdev->last_pos = ptr; spin_unlock(&chip->reg_lock); if (ptr >= ichdev->size) return 0; -- cgit v1.2.3 From 8dca419721d188bfee5f19fad45275856c619a5c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jun 2009 14:50:52 +0200 Subject: ALSA: ctxfi - Fix deadlock with xfi-timer The PCM x-fi native update routine can cause deadlocks when the trigger(START) is called while the stream is running. This patch fixes the deadlock by just postponing the pcm period update to the next possible wake-up. Also it adds the flip of ti->running flag (just to be sure as now). Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/cttimer.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index 779c6c3591a..93b0aedc36d 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -180,7 +180,7 @@ static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer) * * call this inside the lock and irq disabled */ -static int ct_xfitimer_reprogram(struct ct_timer *atimer) +static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update) { struct ct_timer_instance *ti; unsigned int min_intr = (unsigned int)-1; @@ -216,6 +216,8 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer) ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + rate - 1, rate); } + if (ti->need_update && !can_update) + min_intr = 0; /* pending to the next irq */ if (ti->frag_count < min_intr) min_intr = ti->frag_count; } @@ -235,7 +237,7 @@ static void ct_xfitimer_check_period(struct ct_timer *atimer) spin_lock_irqsave(&atimer->list_lock, flags); list_for_each_entry(ti, &atimer->instance_head, instance_list) { - if (ti->need_update) { + if (ti->running && ti->need_update) { ti->need_update = 0; ti->apcm->interrupt(ti->apcm); } @@ -252,7 +254,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer) spin_lock_irqsave(&atimer->lock, flags); atimer->irq_handling = 1; do { - update = ct_xfitimer_reprogram(atimer); + update = ct_xfitimer_reprogram(atimer, 1); spin_unlock(&atimer->lock); if (update) ct_xfitimer_check_period(atimer); @@ -265,6 +267,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer) static void ct_xfitimer_prepare(struct ct_timer_instance *ti) { ti->frag_count = ti->substream->runtime->period_size; + ti->running = 0; ti->need_update = 0; } @@ -273,7 +276,6 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti) static void ct_xfitimer_update(struct ct_timer *atimer) { unsigned long flags; - int update; spin_lock_irqsave(&atimer->lock, flags); if (atimer->irq_handling) { @@ -284,10 +286,8 @@ static void ct_xfitimer_update(struct ct_timer *atimer) } ct_xfitimer_irq_stop(atimer); - update = ct_xfitimer_reprogram(atimer); + ct_xfitimer_reprogram(atimer, 0); spin_unlock_irqrestore(&atimer->lock, flags); - if (update) - ct_xfitimer_check_period(atimer); } static void ct_xfitimer_start(struct ct_timer_instance *ti) @@ -298,6 +298,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti) spin_lock_irqsave(&atimer->lock, flags); if (list_empty(&ti->running_list)) atimer->wc = ct_xfitimer_get_wc(atimer); + ti->running = 1; + ti->need_update = 0; list_add(&ti->running_list, &atimer->running_head); spin_unlock_irqrestore(&atimer->lock, flags); ct_xfitimer_update(atimer); @@ -310,7 +312,7 @@ static void ct_xfitimer_stop(struct ct_timer_instance *ti) spin_lock_irqsave(&atimer->lock, flags); list_del_init(&ti->running_list); - ti->need_update = 0; + ti->running = 0; spin_unlock_irqrestore(&atimer->lock, flags); ct_xfitimer_update(atimer); } -- cgit v1.2.3