]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Add ALSA soft lockup fix to rtc from Takashi Iwai
authorChris Wright <chrisw@osdl.org>
Mon, 14 Nov 2005 03:26:07 +0000 (19:26 -0800)
committerChris Wright <chrisw@osdl.org>
Mon, 14 Nov 2005 03:26:07 +0000 (19:26 -0800)
queue/fix-soft-lockup-with-ALSA-rtc-timer.patch [new file with mode: 0644]
queue/series

diff --git a/queue/fix-soft-lockup-with-ALSA-rtc-timer.patch b/queue/fix-soft-lockup-with-ALSA-rtc-timer.patch
new file mode 100644 (file)
index 0000000..43cb0c0
--- /dev/null
@@ -0,0 +1,180 @@
+From stable-bounces@linux.kernel.org  Fri Nov 11 10:47:39 2005
+Date: Fri, 11 Nov 2005 19:47:28 +0100
+From: Takashi Iwai <tiwai@suse.de>
+To: stable@kernel.org
+Cc: 
+Subject: [PATCH] Fix soft lockup with ALSA rtc-timer
+
+Fixed the soft lockup of ALSA rtc-timer due to the wrong irq
+handling in rtc_control().  The call of rtc_control() can be atomic.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Chris Wright <chrisw@osdl.org>
+---
+ drivers/char/rtc.c |   65 ++++++++++++++++++++++++++++++-----------------------
+ 1 files changed, 38 insertions(+), 27 deletions(-)
+
+Index: linux-2.6.14.y/drivers/char/rtc.c
+===================================================================
+--- linux-2.6.14.y.orig/drivers/char/rtc.c
++++ linux-2.6.14.y/drivers/char/rtc.c
+@@ -149,8 +149,22 @@ static void get_rtc_alm_time (struct rtc
+ #ifdef RTC_IRQ
+ static void rtc_dropped_irq(unsigned long data);
+-static void set_rtc_irq_bit(unsigned char bit);
+-static void mask_rtc_irq_bit(unsigned char bit);
++static void set_rtc_irq_bit_locked(unsigned char bit);
++static void mask_rtc_irq_bit_locked(unsigned char bit);
++
++static inline void set_rtc_irq_bit(unsigned char bit)
++{
++      spin_lock_irq(&rtc_lock);
++      set_rtc_irq_bit_locked(bit);
++      spin_unlock_irq(&rtc_lock);
++}
++
++static void mask_rtc_irq_bit(unsigned char bit)
++{
++      spin_lock_irq(&rtc_lock);
++      mask_rtc_irq_bit_locked(bit);
++      spin_unlock_irq(&rtc_lock);
++}
+ #endif
+ static int rtc_proc_open(struct inode *inode, struct file *file);
+@@ -401,18 +415,19 @@ static int rtc_do_ioctl(unsigned int cmd
+       }
+       case RTC_PIE_OFF:       /* Mask periodic int. enab. bit */
+       {
+-              mask_rtc_irq_bit(RTC_PIE);
++              unsigned long flags; /* can be called from isr via rtc_control() */
++              spin_lock_irqsave (&rtc_lock, flags);
++              mask_rtc_irq_bit_locked(RTC_PIE);
+               if (rtc_status & RTC_TIMER_ON) {
+-                      spin_lock_irq (&rtc_lock);
+                       rtc_status &= ~RTC_TIMER_ON;
+                       del_timer(&rtc_irq_timer);
+-                      spin_unlock_irq (&rtc_lock);
+               }
++              spin_unlock_irqrestore (&rtc_lock, flags);
+               return 0;
+       }
+       case RTC_PIE_ON:        /* Allow periodic ints          */
+       {
+-
++              unsigned long flags; /* can be called from isr via rtc_control() */
+               /*
+                * We don't really want Joe User enabling more
+                * than 64Hz of interrupts on a multi-user machine.
+@@ -421,14 +436,14 @@ static int rtc_do_ioctl(unsigned int cmd
+                       (!capable(CAP_SYS_RESOURCE)))
+                       return -EACCES;
++              spin_lock_irqsave (&rtc_lock, flags);
+               if (!(rtc_status & RTC_TIMER_ON)) {
+-                      spin_lock_irq (&rtc_lock);
+                       rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
+                       add_timer(&rtc_irq_timer);
+                       rtc_status |= RTC_TIMER_ON;
+-                      spin_unlock_irq (&rtc_lock);
+               }
+-              set_rtc_irq_bit(RTC_PIE);
++              set_rtc_irq_bit_locked(RTC_PIE);
++              spin_unlock_irqrestore (&rtc_lock, flags);
+               return 0;
+       }
+       case RTC_UIE_OFF:       /* Mask ints from RTC updates.  */
+@@ -609,6 +624,7 @@ static int rtc_do_ioctl(unsigned int cmd
+       {
+               int tmp = 0;
+               unsigned char val;
++              unsigned long flags; /* can be called from isr via rtc_control() */
+               /* 
+                * The max we can do is 8192Hz.
+@@ -631,9 +647,9 @@ static int rtc_do_ioctl(unsigned int cmd
+               if (arg != (1<<tmp))
+                       return -EINVAL;
+-              spin_lock_irq(&rtc_lock);
++              spin_lock_irqsave(&rtc_lock, flags);
+               if (hpet_set_periodic_freq(arg)) {
+-                      spin_unlock_irq(&rtc_lock);
++                      spin_unlock_irqrestore(&rtc_lock, flags);
+                       return 0;
+               }
+               rtc_freq = arg;
+@@ -641,7 +657,7 @@ static int rtc_do_ioctl(unsigned int cmd
+               val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
+               val |= (16 - tmp);
+               CMOS_WRITE(val, RTC_FREQ_SELECT);
+-              spin_unlock_irq(&rtc_lock);
++              spin_unlock_irqrestore(&rtc_lock, flags);
+               return 0;
+       }
+ #endif
+@@ -844,12 +860,15 @@ int rtc_control(rtc_task_t *task, unsign
+ #ifndef RTC_IRQ
+       return -EIO;
+ #else
+-      spin_lock_irq(&rtc_task_lock);
++      unsigned long flags;
++      if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
++              return -EINVAL;
++      spin_lock_irqsave(&rtc_task_lock, flags);
+       if (rtc_callback != task) {
+-              spin_unlock_irq(&rtc_task_lock);
++              spin_unlock_irqrestore(&rtc_task_lock, flags);
+               return -ENXIO;
+       }
+-      spin_unlock_irq(&rtc_task_lock);
++      spin_unlock_irqrestore(&rtc_task_lock, flags);
+       return rtc_do_ioctl(cmd, arg, 1);
+ #endif
+ }
+@@ -1306,40 +1325,32 @@ static void get_rtc_alm_time(struct rtc_
+  * meddles with the interrupt enable/disable bits.
+  */
+-static void mask_rtc_irq_bit(unsigned char bit)
++static void mask_rtc_irq_bit_locked(unsigned char bit)
+ {
+       unsigned char val;
+-      spin_lock_irq(&rtc_lock);
+-      if (hpet_mask_rtc_irq_bit(bit)) {
+-              spin_unlock_irq(&rtc_lock);
++      if (hpet_mask_rtc_irq_bit(bit))
+               return;
+-      }
+       val = CMOS_READ(RTC_CONTROL);
+       val &=  ~bit;
+       CMOS_WRITE(val, RTC_CONTROL);
+       CMOS_READ(RTC_INTR_FLAGS);
+       rtc_irq_data = 0;
+-      spin_unlock_irq(&rtc_lock);
+ }
+-static void set_rtc_irq_bit(unsigned char bit)
++static void set_rtc_irq_bit_locked(unsigned char bit)
+ {
+       unsigned char val;
+-      spin_lock_irq(&rtc_lock);
+-      if (hpet_set_rtc_irq_bit(bit)) {
+-              spin_unlock_irq(&rtc_lock);
++      if (hpet_set_rtc_irq_bit(bit))
+               return;
+-      }
+       val = CMOS_READ(RTC_CONTROL);
+       val |= bit;
+       CMOS_WRITE(val, RTC_CONTROL);
+       CMOS_READ(RTC_INTR_FLAGS);
+       rtc_irq_data = 0;
+-      spin_unlock_irq(&rtc_lock);
+ }
+ #endif
index ec6ff0414b95712325a6a7370e5bdf3982b944d9..ab925fe47e594d703c08391d1a9c55d7a0df3f9f 100644 (file)
@@ -1,2 +1,3 @@
 ppc64-memory-model-depends-on-NUMA.patch
 ptrace-auto-reap-fix.patch
+fix-soft-lockup-with-ALSA-rtc-timer.patch