Implement CONFIG_HPET_EMULATE_RTC for RTC_DRV_CMOS
Subsystems (4)
cover Implement CONFIG_HPET_EMULATE_RTC for RTC_DRV_CMOS
The new rtc-cmos driver misses HPET support. If the hardware has HPET enabled, then interrupts don't work for the rtc-cmos driver which results in RTC_AIE*, RTC_PIE* and RTC_ALM being unusable. This affects hwclock from util-linux-ng at least on i386 since that uses RTC_PIE_ON. (For x86-64, a polling method is used for unknown reasons.)
This patch series now
1. export the functions from arch/x86/kernel/hpet.c that the old char/rtc driver uses to work around that problem,
2. makes it possible to compile the old rtc driver as module, while still having CONFIG_HPET_EMULATE_RTC enabled and
3. makes use of the exported functions in (1) in the new rtc-cmos driver.
The design is not changed. Please review and give me feedback!
This patch series is against 2.6.24-rc5-mm1. It passes the test in Documentation/rtc.txt after http://lkml.org/lkml/2007/12/20/249 is applied.
PATCH 1/3 Make CONFIG_HPET_EMULATE_RTC usable from modules
This patch makes the RTC emulation functions in arch/x86/kernel/hpet.c usable for kernel modules. It
- exports the functions (EXPORT_SYMBOL_GPL()),
- adds an interface to register the interrupt callback function instead of using only a fixed callback function and
- replaces the rtc_get_rtc_time() function which depends on CONFIG_RTC with a call to get_rtc_time() which is defined in include/asm-generic/rtc.h.
The only dependency to CONFIG_RTC is the call to rtc_interrupt() which is removed by the next patch. After this, there's no (code) dependency of this functions to CONFIG_RTC=y any more.
--- arch/x86/kernel/hpet.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- include/asm-x86/hpet.h | 3 +++ 2 files changed, 49 insertions(+), 1 deletion(-)
arch/x86/kernel/hpet.c +46 -1
@@ -107,6 +107,7 @@ int is_hpet_enabled(void) {return is_hpet_capable () && hpet_legacy_int_enabled; } +EXPORT_SYMBOL_GPL (is_hpet_enabled);/* * When the hpet driver (/dev/hpet) is enabled, we need to reserve
@@ -478,6 +479,7 @@ void hpet_disable(void)*/ #include <linux/mc146818rtc.h> #include <linux/rtc.h> +#include <asm/rtc.h> #define DEFAULT_RTC_INT_FREQ 64#define DEFAULT_RTC_SHIFT 6
@@ -492,6 +494,38 @@ static unsigned long hpet_default_delta;static unsigned long hpet_pie_delta;static unsigned long hpet_pie_limit; +static rtc_irq_handler irq_handler; + +/* +* Registers a IRQ handler. +*/ +int hpet_register_irq_handler (rtc_irq_handler handler) +{ +if (!is_hpet_enabled ()) +return -ENODEV ; +if (irq_handler) +return -EBUSY ; + + irq_handler = handler; + +return 0 ; +} +EXPORT_SYMBOL_GPL (hpet_register_irq_handler); + +/* +* Deregisters the IRQ handler registered with hpet_register_irq_handler() +* and does cleanup. +*/ +void hpet_unregister_irq_handler (rtc_irq_handler handler) +{ +if (!is_hpet_enabled ()) +return ; + + irq_handler =NULL ; + hpet_rtc_flags =0 ; +} +EXPORT_SYMBOL_GPL (hpet_unregister_irq_handler); +/* * Timer 1 for RTC emulation. We use one shot mode, as periodic mode * is not supported by all HPET implementations for timer 1.
@@ -533,6 +567,7 @@ int hpet_rtc_timer_init(void)return 1 ; } +EXPORT_SYMBOL_GPL (hpet_rtc_timer_init);/* * The functions below are called from rtc driver.
@@ -547,6 +582,7 @@ int hpet_mask_rtc_irq_bit(unsigned long hpet_rtc_flags &= ~bit_mask;return 1 ; } +EXPORT_SYMBOL_GPL (hpet_mask_rtc_irq_bit);int hpet_set_rtc_irq_bit (unsigned long bit_mask) {
@@ -562,6 +598,7 @@ int hpet_set_rtc_irq_bit(unsigned long breturn 1 ; } +EXPORT_SYMBOL_GPL (hpet_set_rtc_irq_bit);int hpet_set_alarm_time (unsigned char hrs,unsigned char min,unsigned char sec)
@@ -575,6 +612,7 @@ int hpet_set_alarm_time(unsigned char hrreturn 1 ; } +EXPORT_SYMBOL_GPL (hpet_set_alarm_time);int hpet_set_periodic_freq (unsigned long freq) {
@@ -593,11 +631,13 @@ int hpet_set_periodic_freq(unsigned long }return 1 ; } +EXPORT_SYMBOL_GPL (hpet_set_periodic_freq);int hpet_rtc_dropped_irq (void ) {return is_hpet_enabled (); } +EXPORT_SYMBOL_GPL (hpet_rtc_dropped_irq);static void hpet_rtc_timer_reinit (void ) {
@@ -641,9 +681,10 @@ irqreturn_t hpet_rtc_interrupt(int irq,unsigned long rtc_int_flag =0 ;hpet_rtc_timer_reinit (); +memset (&curr_time,0 ,sizeof (struct rtc_time ));if (hpet_rtc_flags & (RTC_UIE |RTC_AIE )) -rtc_get_rtc_time (&curr_time); +get_rtc_time (&curr_time);if (hpet_rtc_flags &RTC_UIE && curr_time.tm_sec != hpet_prev_update_sec) {
@@ -665,8 +706,12 @@ irqreturn_t hpet_rtc_interrupt(int irq,if (rtc_int_flag) { rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS <<8 )); +if (irq_handler) +irq_handler (rtc_int_flag, dev_id); +rtc_interrupt (rtc_int_flag, dev_id); } return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL (hpet_rtc_interrupt);#endif
include/asm-x86/hpet.h +3 -0
@@ -69,6 +69,7 @@ extern void force_hpet_resume(void);#include <linux/interrupt.h> +typedef irqreturn_t (*rtc_irq_handler )(int interrupt,void *cookie);extern int hpet_mask_rtc_irq_bit (unsigned long bit_mask);extern int hpet_set_rtc_irq_bit (unsigned long bit_mask); extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
@@ -77,6 +78,8 @@ extern int hpet_set_periodic_freq(unsignextern int hpet_rtc_dropped_irq (void );extern int hpet_rtc_timer_init (void );extern irqreturn_t hpet_rtc_interrupt (int irq,void *dev_id); +extern int hpet_register_irq_handler (rtc_irq_handler handler); +extern void hpet_unregister_irq_handler (rtc_irq_handler handler);#endif /* CONFIG_HPET_EMULATE_RTC */
PATCH 2/3 Use the IRQ callback interface in (old) RTC driver
In reply to Bernhard WalleThat function uses the new registration callback mechanism which was added in the previous patch in the old RTC driver. It also removes the direct rtc_interrupt() call from arch/x86/kernel/hpetc.c so that there's finally no (code) dependency to CONFIG_RTC in arch/x86/kernel/hpet.c.
Because of this, it's possible to compile the drivers/char/rtc.ko driver as module and still use the HPET emulation functionality. This is also expressed in Kconfig.
--- arch/x86/Kconfig | 2 +- arch/x86/kernel/hpet.c | 2 -- drivers/char/rtc.c | 15 ++++++++++++++- 3 files changed, 15 insertions(+), 4 deletions(-)
arch/x86/Kconfig +1 -1
@@ -405,7 +405,7 @@ config HPET_TIMER config HPET_EMULATE_RTC def_bool y - depends on HPET_TIMER && RTC=y + depends on HPET_TIMER && (RTC=y || RTC=m) # Mark as embedded because too many people got it wrong. # The code disables itself when not needed.
arch/x86/kernel/hpet.c +0 -2
@@ -708,8 +708,6 @@ irqreturn_t hpet_rtc_interrupt(int irq, rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS <<8 ));if (irq_handler)irq_handler (rtc_int_flag, dev_id); - -rtc_interrupt (rtc_int_flag, dev_id); }return IRQ_HANDLED ; }
drivers/char/rtc.c +14 -1
@@ -110,6 +110,8 @@ static int rtc_has_irq = 1;#define hpet_set_rtc_irq_bit (arg) 0#define hpet_rtc_timer_init () do { } while (0)#define hpet_rtc_dropped_irq () 0 +#define hpet_register_irq_handler (h) 0 +#define hpet_unregister_irq_handler (h) 0#ifdef RTC_IRQ static irqreturn_t hpet_rtc_interrupt (int irq,void *dev_id) {
@@ -1027,7 +1029,15 @@ no_irq:#ifdef RTC_IRQ if (is_hpet_enabled ()) { +int err; + rtc_int_handler_ptr = hpet_rtc_interrupt; + err =hpet_register_irq_handler (rtc_interrupt); +if (err !=0 ) { +printk (KERN_WARNING "hpet_register_irq_handler failed " +"in rtc_init()." ); +return err; + } }else { rtc_int_handler_ptr = rtc_interrupt; }
@@ -1050,6 +1060,7 @@ no_irq:if (misc_register (&rtc_dev)) {#ifdef RTC_IRQ free_irq (RTC_IRQ ,NULL ); +hpet_unregister_irq_handler (rtc_interrupt); rtc_has_irq =0 ;#endif rtc_release_region ();
@@ -1141,8 +1152,10 @@ static void __exit rtc_exit(void)#else rtc_release_region ();#ifdef RTC_IRQ -if (rtc_has_irq) +if (rtc_has_irq) {free_irq (RTC_IRQ ,NULL ); +hpet_unregister_irq_handler (hpet_rtc_interrupt); + }#endif #endif /* CONFIG_SPARC32 */ }
PATCH 3/3 Add HPET RTC emulation to RTC_DRV_CMOS
In reply to Bernhard WalleThat patch adds the RTC emulation of the HPET timer to the new RTC_DRV_CMOS. The old drivers/char/rtc.ko driver had that functionality and it's important on new systems.
--- arch/x86/Kconfig | 2 - drivers/rtc/rtc-cmos.c | 79 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 14 deletions(-)
arch/x86/Kconfig +1 -1
@@ -405,7 +405,7 @@ config HPET_TIMER config HPET_EMULATE_RTC def_bool y - depends on HPET_TIMER && (RTC=y || RTC=m) + depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y) # Mark as embedded because too many people got it wrong. # The code disables itself when not needed.
drivers/rtc/rtc-cmos.c +66 -13
162 lines not on this page · raw message