aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2008-07-24 00:30:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:34 -0400
commit35d3fdd5f304c06654c940921fc045c60df34693 (patch)
treeda28110f8634d4c933ea5666257ee1b1ce1e87a4
parentc68d07b2da54c941bb36c9d6d35fe8f263ee10ef (diff)
rtc-cmos: improve HPET IRQ glue
Resolve http://bugzilla.kernel.org/show_bug.cgi?id=11051 and other bugs related to the way the HPET glue code in rtc-cmos was incomplete and inconsistent: * Switch the approach so that the basic driver code flow isn't changed by having HPET ... instead, just have HPET shadow the RTC_CONTROL irq enables and RTC_FREQ_SELECT data. It's only coping with IRQ thievery, after all. * Do that consistently (!!) to avoid problems when the HPET code is out of sync with the real RTC intent. Examples include: - cmos_procfs(), which now reports correct data - cmos_irq_set_state() ... also removing the previous PIE_{ON,OFF} ioctl support so only one code path manages "periodic" IRQs - cmos_do_shutdown() ... currently a "just in case" change. - cmos_suspend() and cmos_resume() ... also handling a bug that was specific to HPET's IRQ thievery, where the alarm wasn't disabled after waking the system * Always call that HPET code under the RTC spinlock (it doesn't do its own locking) Also clean up the HPET glue: * Add some comments explaining what's going on. * Switch to having just one #ifdef for the HPET glue, and inline functions (not #defines) to avoid some compiler warnings. * Have the probe message also report when HPET IRQs are involved This still leaves various holes in the HPET glue, like the emulated update IRQs being out of sync with the RTC, alarms never using day or month matches, and many extra IRQs (at 64 Hz). [akpm@linux-foundation.org: fix build] Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: Tomas Janousek <tomi@nomi.cz> Cc: Bernhard Walle <bwalle@suse.de> Cc: Carlos R. Mafra <crmafra@ift.unesp.br> Acked-by: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rtc/rtc-cmos.c193
1 files changed, 131 insertions, 62 deletions
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 94b89a2d9c2e..e9984650ea95 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -36,28 +36,9 @@
36#include <linux/platform_device.h> 36#include <linux/platform_device.h>
37#include <linux/mod_devicetable.h> 37#include <linux/mod_devicetable.h>
38 38
39#ifdef CONFIG_HPET_EMULATE_RTC
40#include <asm/hpet.h>
41#endif
42
43/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ 39/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
44#include <asm-generic/rtc.h> 40#include <asm-generic/rtc.h>
45 41
46#ifndef CONFIG_HPET_EMULATE_RTC
47#define is_hpet_enabled() 0
48#define hpet_set_alarm_time(hrs, min, sec) do { } while (0)
49#define hpet_set_periodic_freq(arg) 0
50#define hpet_mask_rtc_irq_bit(arg) do { } while (0)
51#define hpet_set_rtc_irq_bit(arg) do { } while (0)
52#define hpet_rtc_timer_init() do { } while (0)
53#define hpet_register_irq_handler(h) 0
54#define hpet_unregister_irq_handler(h) do { } while (0)
55static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
56{
57 return 0;
58}
59#endif
60
61struct cmos_rtc { 42struct cmos_rtc {
62 struct rtc_device *rtc; 43 struct rtc_device *rtc;
63 struct device *dev; 44 struct device *dev;
@@ -96,6 +77,72 @@ static inline int is_intr(u8 rtc_intr)
96 77
97/*----------------------------------------------------------------*/ 78/*----------------------------------------------------------------*/
98 79
80/* Much modern x86 hardware has HPETs (10+ MHz timers) which, because
81 * many BIOS programmers don't set up "sane mode" IRQ routing, are mostly
82 * used in a broken "legacy replacement" mode. The breakage includes
83 * HPET #1 hijacking the IRQ for this RTC, and being unavailable for
84 * other (better) use.
85 *
86 * When that broken mode is in use, platform glue provides a partial
87 * emulation of hardware RTC IRQ facilities using HPET #1. We don't
88 * want to use HPET for anything except those IRQs though...
89 */
90#ifdef CONFIG_HPET_EMULATE_RTC
91#include <asm/hpet.h>
92#else
93
94static inline int is_hpet_enabled(void)
95{
96 return 0;
97}
98
99static inline int hpet_mask_rtc_irq_bit(unsigned long mask)
100{
101 return 0;
102}
103
104static inline int hpet_set_rtc_irq_bit(unsigned long mask)
105{
106 return 0;
107}
108
109static inline int
110hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
111{
112 return 0;
113}
114
115static inline int hpet_set_periodic_freq(unsigned long freq)
116{
117 return 0;
118}
119
120static inline int hpet_rtc_dropped_irq(void)
121{
122 return 0;
123}
124
125static inline int hpet_rtc_timer_init(void)
126{
127 return 0;
128}
129
130extern irq_handler_t hpet_rtc_interrupt;
131
132static inline int hpet_register_irq_handler(irq_handler_t handler)
133{
134 return 0;
135}
136
137static inline int hpet_unregister_irq_handler(irq_handler_t handler)
138{
139 return 0;
140}
141
142#endif
143
144/*----------------------------------------------------------------*/
145
99static int cmos_read_time(struct device *dev, struct rtc_time *t) 146static int cmos_read_time(struct device *dev, struct rtc_time *t)
100{ 147{
101 /* REVISIT: if the clock has a "century" register, use 148 /* REVISIT: if the clock has a "century" register, use
@@ -216,13 +263,14 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
216 sec = t->time.tm_sec; 263 sec = t->time.tm_sec;
217 sec = (sec < 60) ? BIN2BCD(sec) : 0xff; 264 sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
218 265
219 hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
220 spin_lock_irq(&rtc_lock); 266 spin_lock_irq(&rtc_lock);
221 267
222 /* next rtc irq must not be from previous alarm setting */ 268 /* next rtc irq must not be from previous alarm setting */
223 rtc_control = CMOS_READ(RTC_CONTROL); 269 rtc_control = CMOS_READ(RTC_CONTROL);
224 rtc_control &= ~RTC_AIE; 270 rtc_control &= ~RTC_AIE;
225 CMOS_WRITE(rtc_control, RTC_CONTROL); 271 CMOS_WRITE(rtc_control, RTC_CONTROL);
272 hpet_mask_rtc_irq_bit(RTC_AIE);
273
226 rtc_intr = CMOS_READ(RTC_INTR_FLAGS); 274 rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
227 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; 275 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
228 if (is_intr(rtc_intr)) 276 if (is_intr(rtc_intr))
@@ -240,9 +288,16 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
240 CMOS_WRITE(mon, cmos->mon_alrm); 288 CMOS_WRITE(mon, cmos->mon_alrm);
241 } 289 }
242 290
291 /* FIXME the HPET alarm glue currently ignores day_alrm
292 * and mon_alrm ...
293 */
294 hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
295
243 if (t->enabled) { 296 if (t->enabled) {
244 rtc_control |= RTC_AIE; 297 rtc_control |= RTC_AIE;
245 CMOS_WRITE(rtc_control, RTC_CONTROL); 298 CMOS_WRITE(rtc_control, RTC_CONTROL);
299 hpet_set_rtc_irq_bit(RTC_AIE);
300
246 rtc_intr = CMOS_READ(RTC_INTR_FLAGS); 301 rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
247 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; 302 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
248 if (is_intr(rtc_intr)) 303 if (is_intr(rtc_intr))
@@ -270,8 +325,8 @@ static int cmos_irq_set_freq(struct device *dev, int freq)
270 f = 16 - f; 325 f = 16 - f;
271 326
272 spin_lock_irqsave(&rtc_lock, flags); 327 spin_lock_irqsave(&rtc_lock, flags);
273 if (!hpet_set_periodic_freq(freq)) 328 hpet_set_periodic_freq(freq);
274 CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); 329 CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
275 spin_unlock_irqrestore(&rtc_lock, flags); 330 spin_unlock_irqrestore(&rtc_lock, flags);
276 331
277 return 0; 332 return 0;
@@ -289,11 +344,13 @@ static int cmos_irq_set_state(struct device *dev, int enabled)
289 spin_lock_irqsave(&rtc_lock, flags); 344 spin_lock_irqsave(&rtc_lock, flags);
290 rtc_control = CMOS_READ(RTC_CONTROL); 345 rtc_control = CMOS_READ(RTC_CONTROL);
291 346
292 if (enabled) 347 if (enabled) {
293 rtc_control |= RTC_PIE; 348 rtc_control |= RTC_PIE;
294 else 349 hpet_set_rtc_irq_bit(RTC_PIE);
350 } else {
295 rtc_control &= ~RTC_PIE; 351 rtc_control &= ~RTC_PIE;
296 352 hpet_mask_rtc_irq_bit(RTC_PIE);
353 }
297 CMOS_WRITE(rtc_control, RTC_CONTROL); 354 CMOS_WRITE(rtc_control, RTC_CONTROL);
298 355
299 rtc_intr = CMOS_READ(RTC_INTR_FLAGS); 356 rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
@@ -319,11 +376,10 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
319 case RTC_AIE_ON: 376 case RTC_AIE_ON:
320 case RTC_UIE_OFF: 377 case RTC_UIE_OFF:
321 case RTC_UIE_ON: 378 case RTC_UIE_ON:
322 case RTC_PIE_OFF:
323 case RTC_PIE_ON:
324 if (!is_valid_irq(cmos->irq)) 379 if (!is_valid_irq(cmos->irq))
325 return -EINVAL; 380 return -EINVAL;
326 break; 381 break;
382 /* PIE ON/OFF is handled by cmos_irq_set_state() */
327 default: 383 default:
328 return -ENOIOCTLCMD; 384 return -ENOIOCTLCMD;
329 } 385 }
@@ -347,17 +403,8 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
347 rtc_control |= RTC_UIE; 403 rtc_control |= RTC_UIE;
348 hpet_set_rtc_irq_bit(RTC_UIE); 404 hpet_set_rtc_irq_bit(RTC_UIE);
349 break; 405 break;
350 case RTC_PIE_OFF: /* periodic off */
351 rtc_control &= ~RTC_PIE;
352 hpet_mask_rtc_irq_bit(RTC_PIE);
353 break;
354 case RTC_PIE_ON: /* periodic on */
355 rtc_control |= RTC_PIE;
356 hpet_set_rtc_irq_bit(RTC_PIE);
357 break;
358 } 406 }
359 if (!is_hpet_enabled()) 407 CMOS_WRITE(rtc_control, RTC_CONTROL);
360 CMOS_WRITE(rtc_control, RTC_CONTROL);
361 408
362 rtc_intr = CMOS_READ(RTC_INTR_FLAGS); 409 rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
363 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; 410 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
@@ -505,18 +552,19 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
505 u8 rtc_control; 552 u8 rtc_control;
506 553
507 spin_lock(&rtc_lock); 554 spin_lock(&rtc_lock);
508 /* 555
509 * In this case it is HPET RTC interrupt handler 556 /* When the HPET interrupt handler calls us, the interrupt
510 * calling us, with the interrupt information 557 * status is passed as arg1 instead of the irq number. But
511 * passed as arg1, instead of irq. 558 * always clear irq status, even when HPET is in the way.
559 *
560 * Note that HPET and RTC are almost certainly out of phase,
561 * giving different IRQ status ...
512 */ 562 */
563 irqstat = CMOS_READ(RTC_INTR_FLAGS);
564 rtc_control = CMOS_READ(RTC_CONTROL);
513 if (is_hpet_enabled()) 565 if (is_hpet_enabled())
514 irqstat = (unsigned long)irq & 0xF0; 566 irqstat = (unsigned long)irq & 0xF0;
515 else { 567 irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
516 irqstat = CMOS_READ(RTC_INTR_FLAGS);
517 rtc_control = CMOS_READ(RTC_CONTROL);
518 irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
519 }
520 568
521 /* All Linux RTC alarms should be treated as if they were oneshot. 569 /* All Linux RTC alarms should be treated as if they were oneshot.
522 * Similar code may be needed in system wakeup paths, in case the 570 * Similar code may be needed in system wakeup paths, in case the
@@ -526,6 +574,8 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
526 rtc_control = CMOS_READ(RTC_CONTROL); 574 rtc_control = CMOS_READ(RTC_CONTROL);
527 rtc_control &= ~RTC_AIE; 575 rtc_control &= ~RTC_AIE;
528 CMOS_WRITE(rtc_control, RTC_CONTROL); 576 CMOS_WRITE(rtc_control, RTC_CONTROL);
577 hpet_mask_rtc_irq_bit(RTC_AIE);
578
529 CMOS_READ(RTC_INTR_FLAGS); 579 CMOS_READ(RTC_INTR_FLAGS);
530 } 580 }
531 spin_unlock(&rtc_lock); 581 spin_unlock(&rtc_lock);
@@ -632,8 +682,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
632 * do something about other clock frequencies. 682 * do something about other clock frequencies.
633 */ 683 */
634 cmos_rtc.rtc->irq_freq = 1024; 684 cmos_rtc.rtc->irq_freq = 1024;
635 if (!hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq)) 685 hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
636 CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); 686 CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
637 687
638 /* disable irqs. 688 /* disable irqs.
639 * 689 *
@@ -643,6 +693,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
643 rtc_control = CMOS_READ(RTC_CONTROL); 693 rtc_control = CMOS_READ(RTC_CONTROL);
644 rtc_control &= ~(RTC_PIE | RTC_AIE | RTC_UIE); 694 rtc_control &= ~(RTC_PIE | RTC_AIE | RTC_UIE);
645 CMOS_WRITE(rtc_control, RTC_CONTROL); 695 CMOS_WRITE(rtc_control, RTC_CONTROL);
696 hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE);
697
646 CMOS_READ(RTC_INTR_FLAGS); 698 CMOS_READ(RTC_INTR_FLAGS);
647 699
648 spin_unlock_irq(&rtc_lock); 700 spin_unlock_irq(&rtc_lock);
@@ -690,7 +742,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
690 goto cleanup2; 742 goto cleanup2;
691 } 743 }
692 744
693 pr_info("%s: alarms up to one %s%s\n", 745 pr_info("%s: alarms up to one %s%s%s\n",
694 cmos_rtc.rtc->dev.bus_id, 746 cmos_rtc.rtc->dev.bus_id,
695 is_valid_irq(rtc_irq) 747 is_valid_irq(rtc_irq)
696 ? (cmos_rtc.mon_alrm 748 ? (cmos_rtc.mon_alrm
@@ -698,8 +750,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
698 : (cmos_rtc.day_alrm 750 : (cmos_rtc.day_alrm
699 ? "month" : "day")) 751 ? "month" : "day"))
700 : "no", 752 : "no",
701 cmos_rtc.century ? ", y3k" : "" 753 cmos_rtc.century ? ", y3k" : "",
702 ); 754 is_hpet_enabled() ? ", hpet irqs" : "");
703 755
704 return 0; 756 return 0;
705 757
@@ -720,8 +772,10 @@ static void cmos_do_shutdown(void)
720 772
721 spin_lock_irq(&rtc_lock); 773 spin_lock_irq(&rtc_lock);
722 rtc_control = CMOS_READ(RTC_CONTROL); 774 rtc_control = CMOS_READ(RTC_CONTROL);
723 rtc_control &= ~(RTC_PIE|RTC_AIE|RTC_UIE); 775 rtc_control &= ~RTC_IRQMASK;
724 CMOS_WRITE(rtc_control, RTC_CONTROL); 776 CMOS_WRITE(rtc_control, RTC_CONTROL);
777 hpet_mask_rtc_irq_bit(RTC_IRQMASK);
778
725 CMOS_READ(RTC_INTR_FLAGS); 779 CMOS_READ(RTC_INTR_FLAGS);
726 spin_unlock_irq(&rtc_lock); 780 spin_unlock_irq(&rtc_lock);
727} 781}
@@ -764,12 +818,16 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
764 cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL); 818 cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL);
765 if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { 819 if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
766 unsigned char irqstat; 820 unsigned char irqstat;
821 unsigned char mask;
767 822
768 if (do_wake) 823 if (do_wake)
769 tmp &= ~(RTC_PIE|RTC_UIE); 824 mask = RTC_IRQMASK & ~RTC_AIE;
770 else 825 else
771 tmp &= ~(RTC_PIE|RTC_AIE|RTC_UIE); 826 mask = RTC_IRQMASK;
827 tmp &= ~mask;
772 CMOS_WRITE(tmp, RTC_CONTROL); 828 CMOS_WRITE(tmp, RTC_CONTROL);
829 hpet_mask_rtc_irq_bit(mask);
830
773 irqstat = CMOS_READ(RTC_INTR_FLAGS); 831 irqstat = CMOS_READ(RTC_INTR_FLAGS);
774 irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF; 832 irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF;
775 if (is_intr(irqstat)) 833 if (is_intr(irqstat))
@@ -799,7 +857,8 @@ static int cmos_resume(struct device *dev)
799 unsigned char tmp = cmos->suspend_ctrl; 857 unsigned char tmp = cmos->suspend_ctrl;
800 858
801 /* re-enable any irqs previously active */ 859 /* re-enable any irqs previously active */
802 if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { 860 if (tmp & RTC_IRQMASK) {
861 unsigned char mask;
803 862
804 if (cmos->enabled_wake) { 863 if (cmos->enabled_wake) {
805 if (cmos->wake_off) 864 if (cmos->wake_off)
@@ -810,18 +869,28 @@ static int cmos_resume(struct device *dev)
810 } 869 }
811 870
812 spin_lock_irq(&rtc_lock); 871 spin_lock_irq(&rtc_lock);
813 CMOS_WRITE(tmp, RTC_CONTROL); 872 do {
814 tmp = CMOS_READ(RTC_INTR_FLAGS); 873 CMOS_WRITE(tmp, RTC_CONTROL);
815 tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF; 874 hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK);
816 if (is_intr(tmp)) 875
817 rtc_update_irq(cmos->rtc, 1, tmp); 876 mask = CMOS_READ(RTC_INTR_FLAGS);
877 mask &= (tmp & RTC_IRQMASK) | RTC_IRQF;
878 if (!is_intr(mask))
879 break;
880
881 /* force one-shot behavior if HPET blocked
882 * the wake alarm's irq
883 */
884 rtc_update_irq(cmos->rtc, 1, mask);
885 tmp &= ~RTC_AIE;
886 hpet_mask_rtc_irq_bit(RTC_AIE);
887 } while (mask & RTC_AIE);
818 spin_unlock_irq(&rtc_lock); 888 spin_unlock_irq(&rtc_lock);
819 } 889 }
820 890
821 pr_debug("%s: resume, ctrl %02x\n", 891 pr_debug("%s: resume, ctrl %02x\n",
822 cmos_rtc.rtc->dev.bus_id, 892 cmos_rtc.rtc->dev.bus_id,
823 cmos->suspend_ctrl); 893 tmp);
824
825 894
826 return 0; 895 return 0;
827} 896}