aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/rtc.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-11-07 05:14:57 -0500
committerJaroslav Kysela <perex@suse.cz>2005-11-07 05:14:57 -0500
commitc3348760aaffd268f7e91b2185999025fdc5607f (patch)
treedc4fd97943a8547189bb025c71321fb67c5fc3c6 /drivers/char/rtc.c
parent1d4ae4a119e5ba711f12b05cdf27f794460add4b (diff)
[PATCH] Fix wrong irq enable via rtc_control()
rtc_control() may be called in the interrupt context in ALSA rtc-timer driver. The patch fixes the wrong irq enable in rtc.c, and also fixes the possible race of bit flags. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'drivers/char/rtc.c')
-rw-r--r--drivers/char/rtc.c65
1 files changed, 38 insertions, 27 deletions
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 63fff7c1244a..a7f099fb7dfe 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -149,8 +149,22 @@ static void get_rtc_alm_time (struct rtc_time *alm_tm);
149#ifdef RTC_IRQ 149#ifdef RTC_IRQ
150static void rtc_dropped_irq(unsigned long data); 150static void rtc_dropped_irq(unsigned long data);
151 151
152static void set_rtc_irq_bit(unsigned char bit); 152static void set_rtc_irq_bit_locked(unsigned char bit);
153static void mask_rtc_irq_bit(unsigned char bit); 153static void mask_rtc_irq_bit_locked(unsigned char bit);
154
155static inline void set_rtc_irq_bit(unsigned char bit)
156{
157 spin_lock_irq(&rtc_lock);
158 set_rtc_irq_bit_locked(bit);
159 spin_unlock_irq(&rtc_lock);
160}
161
162static void mask_rtc_irq_bit(unsigned char bit)
163{
164 spin_lock_irq(&rtc_lock);
165 mask_rtc_irq_bit_locked(bit);
166 spin_unlock_irq(&rtc_lock);
167}
154#endif 168#endif
155 169
156static int rtc_proc_open(struct inode *inode, struct file *file); 170static int rtc_proc_open(struct inode *inode, struct file *file);
@@ -401,18 +415,19 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
401 } 415 }
402 case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ 416 case RTC_PIE_OFF: /* Mask periodic int. enab. bit */
403 { 417 {
404 mask_rtc_irq_bit(RTC_PIE); 418 unsigned long flags; /* can be called from isr via rtc_control() */
419 spin_lock_irqsave (&rtc_lock, flags);
420 mask_rtc_irq_bit_locked(RTC_PIE);
405 if (rtc_status & RTC_TIMER_ON) { 421 if (rtc_status & RTC_TIMER_ON) {
406 spin_lock_irq (&rtc_lock);
407 rtc_status &= ~RTC_TIMER_ON; 422 rtc_status &= ~RTC_TIMER_ON;
408 del_timer(&rtc_irq_timer); 423 del_timer(&rtc_irq_timer);
409 spin_unlock_irq (&rtc_lock);
410 } 424 }
425 spin_unlock_irqrestore (&rtc_lock, flags);
411 return 0; 426 return 0;
412 } 427 }
413 case RTC_PIE_ON: /* Allow periodic ints */ 428 case RTC_PIE_ON: /* Allow periodic ints */
414 { 429 {
415 430 unsigned long flags; /* can be called from isr via rtc_control() */
416 /* 431 /*
417 * We don't really want Joe User enabling more 432 * We don't really want Joe User enabling more
418 * than 64Hz of interrupts on a multi-user machine. 433 * than 64Hz of interrupts on a multi-user machine.
@@ -421,14 +436,14 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
421 (!capable(CAP_SYS_RESOURCE))) 436 (!capable(CAP_SYS_RESOURCE)))
422 return -EACCES; 437 return -EACCES;
423 438
439 spin_lock_irqsave (&rtc_lock, flags);
424 if (!(rtc_status & RTC_TIMER_ON)) { 440 if (!(rtc_status & RTC_TIMER_ON)) {
425 spin_lock_irq (&rtc_lock);
426 rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; 441 rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
427 add_timer(&rtc_irq_timer); 442 add_timer(&rtc_irq_timer);
428 rtc_status |= RTC_TIMER_ON; 443 rtc_status |= RTC_TIMER_ON;
429 spin_unlock_irq (&rtc_lock);
430 } 444 }
431 set_rtc_irq_bit(RTC_PIE); 445 set_rtc_irq_bit_locked(RTC_PIE);
446 spin_unlock_irqrestore (&rtc_lock, flags);
432 return 0; 447 return 0;
433 } 448 }
434 case RTC_UIE_OFF: /* Mask ints from RTC updates. */ 449 case RTC_UIE_OFF: /* Mask ints from RTC updates. */
@@ -609,6 +624,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
609 { 624 {
610 int tmp = 0; 625 int tmp = 0;
611 unsigned char val; 626 unsigned char val;
627 unsigned long flags; /* can be called from isr via rtc_control() */
612 628
613 /* 629 /*
614 * The max we can do is 8192Hz. 630 * The max we can do is 8192Hz.
@@ -631,9 +647,9 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
631 if (arg != (1<<tmp)) 647 if (arg != (1<<tmp))
632 return -EINVAL; 648 return -EINVAL;
633 649
634 spin_lock_irq(&rtc_lock); 650 spin_lock_irqsave(&rtc_lock, flags);
635 if (hpet_set_periodic_freq(arg)) { 651 if (hpet_set_periodic_freq(arg)) {
636 spin_unlock_irq(&rtc_lock); 652 spin_unlock_irqrestore(&rtc_lock, flags);
637 return 0; 653 return 0;
638 } 654 }
639 rtc_freq = arg; 655 rtc_freq = arg;
@@ -641,7 +657,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
641 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; 657 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
642 val |= (16 - tmp); 658 val |= (16 - tmp);
643 CMOS_WRITE(val, RTC_FREQ_SELECT); 659 CMOS_WRITE(val, RTC_FREQ_SELECT);
644 spin_unlock_irq(&rtc_lock); 660 spin_unlock_irqrestore(&rtc_lock, flags);
645 return 0; 661 return 0;
646 } 662 }
647#endif 663#endif
@@ -844,12 +860,15 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
844#ifndef RTC_IRQ 860#ifndef RTC_IRQ
845 return -EIO; 861 return -EIO;
846#else 862#else
847 spin_lock_irq(&rtc_task_lock); 863 unsigned long flags;
864 if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
865 return -EINVAL;
866 spin_lock_irqsave(&rtc_task_lock, flags);
848 if (rtc_callback != task) { 867 if (rtc_callback != task) {
849 spin_unlock_irq(&rtc_task_lock); 868 spin_unlock_irqrestore(&rtc_task_lock, flags);
850 return -ENXIO; 869 return -ENXIO;
851 } 870 }
852 spin_unlock_irq(&rtc_task_lock); 871 spin_unlock_irqrestore(&rtc_task_lock, flags);
853 return rtc_do_ioctl(cmd, arg, 1); 872 return rtc_do_ioctl(cmd, arg, 1);
854#endif 873#endif
855} 874}
@@ -1306,40 +1325,32 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm)
1306 * meddles with the interrupt enable/disable bits. 1325 * meddles with the interrupt enable/disable bits.
1307 */ 1326 */
1308 1327
1309static void mask_rtc_irq_bit(unsigned char bit) 1328static void mask_rtc_irq_bit_locked(unsigned char bit)
1310{ 1329{
1311 unsigned char val; 1330 unsigned char val;
1312 1331
1313 spin_lock_irq(&rtc_lock); 1332 if (hpet_mask_rtc_irq_bit(bit))
1314 if (hpet_mask_rtc_irq_bit(bit)) {
1315 spin_unlock_irq(&rtc_lock);
1316 return; 1333 return;
1317 }
1318 val = CMOS_READ(RTC_CONTROL); 1334 val = CMOS_READ(RTC_CONTROL);
1319 val &= ~bit; 1335 val &= ~bit;
1320 CMOS_WRITE(val, RTC_CONTROL); 1336 CMOS_WRITE(val, RTC_CONTROL);
1321 CMOS_READ(RTC_INTR_FLAGS); 1337 CMOS_READ(RTC_INTR_FLAGS);
1322 1338
1323 rtc_irq_data = 0; 1339 rtc_irq_data = 0;
1324 spin_unlock_irq(&rtc_lock);
1325} 1340}
1326 1341
1327static void set_rtc_irq_bit(unsigned char bit) 1342static void set_rtc_irq_bit_locked(unsigned char bit)
1328{ 1343{
1329 unsigned char val; 1344 unsigned char val;
1330 1345
1331 spin_lock_irq(&rtc_lock); 1346 if (hpet_set_rtc_irq_bit(bit))
1332 if (hpet_set_rtc_irq_bit(bit)) {
1333 spin_unlock_irq(&rtc_lock);
1334 return; 1347 return;
1335 }
1336 val = CMOS_READ(RTC_CONTROL); 1348 val = CMOS_READ(RTC_CONTROL);
1337 val |= bit; 1349 val |= bit;
1338 CMOS_WRITE(val, RTC_CONTROL); 1350 CMOS_WRITE(val, RTC_CONTROL);
1339 CMOS_READ(RTC_INTR_FLAGS); 1351 CMOS_READ(RTC_INTR_FLAGS);
1340 1352
1341 rtc_irq_data = 0; 1353 rtc_irq_data = 0;
1342 spin_unlock_irq(&rtc_lock);
1343} 1354}
1344#endif 1355#endif
1345 1356