aboutsummaryrefslogtreecommitdiffstats
path: root/sound/oss/au1550_ac97.c
diff options
context:
space:
mode:
authorSergei Shtylylov <sshtylyov@ru.mvista.com>2005-12-15 15:34:30 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-12-15 17:22:45 -0500
commit7b6666530e2736f190a2629c8abe34275054449f (patch)
tree677a4dc1ba95a98c6c6a98949fdcb0bca95ba1cf /sound/oss/au1550_ac97.c
parent2f40fb72a2121da44c35f2588ee9abce1dffa2a9 (diff)
[PATCH] Au1550 AC'97 OSS driver spinlock fixes
We have found some issues with Au1550 AC'97 OSS driver in 2.6 (sound/oss/au1550_ac97.c), though it also should concern 2.4 driver (drivers/sound/au1550_psc.c). start_dac() grabs a spinlock already held by its caller, au1550_write(). This doesn't show up with the standard UP spinlock impelmentation but when the different one (mutex based) is in use, a lockup happens. And the interrupt handlers also didn't grab the spinlock -- that's OK in the usual kernel but not when the IRQ handlers are threaded. So, they're grabbing the spinlock now (as every correct interrupt handler should do). Signed-off-by: Konstantin Baidarov <kbaidarov@ru.mvista.com> Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'sound/oss/au1550_ac97.c')
-rw-r--r--sound/oss/au1550_ac97.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index 6b46a8a4b1cc..b963c550dae6 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -578,17 +578,15 @@ set_recv_slots(int num_channels)
578 } while ((stat & PSC_AC97STAT_DR) == 0); 578 } while ((stat & PSC_AC97STAT_DR) == 0);
579} 579}
580 580
581/* Hold spinlock for both start_dac() and start_adc() calls */
581static void 582static void
582start_dac(struct au1550_state *s) 583start_dac(struct au1550_state *s)
583{ 584{
584 struct dmabuf *db = &s->dma_dac; 585 struct dmabuf *db = &s->dma_dac;
585 unsigned long flags;
586 586
587 if (!db->stopped) 587 if (!db->stopped)
588 return; 588 return;
589 589
590 spin_lock_irqsave(&s->lock, flags);
591
592 set_xmit_slots(db->num_channels); 590 set_xmit_slots(db->num_channels);
593 au_writel(PSC_AC97PCR_TC, PSC_AC97PCR); 591 au_writel(PSC_AC97PCR_TC, PSC_AC97PCR);
594 au_sync(); 592 au_sync();
@@ -598,8 +596,6 @@ start_dac(struct au1550_state *s)
598 au1xxx_dbdma_start(db->dmanr); 596 au1xxx_dbdma_start(db->dmanr);
599 597
600 db->stopped = 0; 598 db->stopped = 0;
601
602 spin_unlock_irqrestore(&s->lock, flags);
603} 599}
604 600
605static void 601static void
@@ -718,7 +714,6 @@ prog_dmabuf_dac(struct au1550_state *s)
718} 714}
719 715
720 716
721/* hold spinlock for the following */
722static void 717static void
723dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) 718dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
724{ 719{
@@ -726,6 +721,8 @@ dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
726 struct dmabuf *db = &s->dma_dac; 721 struct dmabuf *db = &s->dma_dac;
727 u32 ac97c_stat; 722 u32 ac97c_stat;
728 723
724 spin_lock(&s->lock);
725
729 ac97c_stat = au_readl(PSC_AC97STAT); 726 ac97c_stat = au_readl(PSC_AC97STAT);
730 if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) 727 if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
731 pr_debug("AC97C status = 0x%08x\n", ac97c_stat); 728 pr_debug("AC97C status = 0x%08x\n", ac97c_stat);
@@ -747,6 +744,8 @@ dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
747 /* wake up anybody listening */ 744 /* wake up anybody listening */
748 if (waitqueue_active(&db->wait)) 745 if (waitqueue_active(&db->wait))
749 wake_up(&db->wait); 746 wake_up(&db->wait);
747
748 spin_unlock(&s->lock);
750} 749}
751 750
752 751
@@ -758,6 +757,8 @@ adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
758 u32 obytes; 757 u32 obytes;
759 char *obuf; 758 char *obuf;
760 759
760 spin_lock(&s->lock);
761
761 /* Pull the buffer from the dma queue. 762 /* Pull the buffer from the dma queue.
762 */ 763 */
763 au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes); 764 au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes);
@@ -765,6 +766,7 @@ adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
765 if ((dp->count + obytes) > dp->dmasize) { 766 if ((dp->count + obytes) > dp->dmasize) {
766 /* Overrun. Stop ADC and log the error 767 /* Overrun. Stop ADC and log the error
767 */ 768 */
769 spin_unlock(&s->lock);
768 stop_adc(s); 770 stop_adc(s);
769 dp->error++; 771 dp->error++;
770 err("adc overrun"); 772 err("adc overrun");
@@ -787,6 +789,7 @@ adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
787 if (waitqueue_active(&dp->wait)) 789 if (waitqueue_active(&dp->wait))
788 wake_up(&dp->wait); 790 wake_up(&dp->wait);
789 791
792 spin_unlock(&s->lock);
790} 793}
791 794
792static loff_t 795static loff_t
@@ -1048,9 +1051,9 @@ au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
1048 /* wait for samples in ADC dma buffer 1051 /* wait for samples in ADC dma buffer
1049 */ 1052 */
1050 do { 1053 do {
1054 spin_lock_irqsave(&s->lock, flags);
1051 if (db->stopped) 1055 if (db->stopped)
1052 start_adc(s); 1056 start_adc(s);
1053 spin_lock_irqsave(&s->lock, flags);
1054 avail = db->count; 1057 avail = db->count;
1055 if (avail <= 0) 1058 if (avail <= 0)
1056 __set_current_state(TASK_INTERRUPTIBLE); 1059 __set_current_state(TASK_INTERRUPTIBLE);
@@ -1570,15 +1573,19 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
1570 if (get_user(val, (int *) arg)) 1573 if (get_user(val, (int *) arg))
1571 return -EFAULT; 1574 return -EFAULT;
1572 if (file->f_mode & FMODE_READ) { 1575 if (file->f_mode & FMODE_READ) {
1573 if (val & PCM_ENABLE_INPUT) 1576 if (val & PCM_ENABLE_INPUT) {
1577 spin_lock_irqsave(&s->lock, flags);
1574 start_adc(s); 1578 start_adc(s);
1575 else 1579 spin_unlock_irqrestore(&s->lock, flags);
1580 } else
1576 stop_adc(s); 1581 stop_adc(s);
1577 } 1582 }
1578 if (file->f_mode & FMODE_WRITE) { 1583 if (file->f_mode & FMODE_WRITE) {
1579 if (val & PCM_ENABLE_OUTPUT) 1584 if (val & PCM_ENABLE_OUTPUT) {
1585 spin_lock_irqsave(&s->lock, flags);
1580 start_dac(s); 1586 start_dac(s);
1581 else 1587 spin_unlock_irqrestore(&s->lock, flags);
1588 } else
1582 stop_dac(s); 1589 stop_dac(s);
1583 } 1590 }
1584 return 0; 1591 return 0;