HPET rtc emulation

2013-04-30 Thread Christian Gmeiner
Hi.

I am working with a platform that has a problem with the RTC alarm
interrupt - tested with rtctest from /Documentation/rtc.txt.
So I thought that I could use the HPET emulation. As far as I
understand in the HPET emulation mode no RTC irq will be used --> RTC
alarm interrupt is done via HPET.
Is this a correct assumption?

root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:28 AM CEST  -0.511012 seconds
root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:29 AM CEST  -0.511016 seconds
root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:30 AM CEST  -0.526659 seconds
root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:31 AM CEST  -0.620384 seconds
root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:32 AM CEST  -0.604838 seconds
root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:33 AM CEST  -0.651638 seconds
root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:34 AM CEST  -0.682915 seconds
root@OT:/home/vis# hwclock
Tue 30 Apr 2013 09:24:35 AM CEST  -0.026708 seconds
root@OT:/home/vis# hwclock
select() to /dev/rtc to wait for clock tick timed ou


Doing some quite simple tests indicates that HPET emulation does not emulate
RTC alarm interrupts or my HPET has some problems.

thanks
--
Christian Gmeiner, MSc
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[patch 3/3] Add HPET RTC emulation to RTC_DRV_CMOS

2007-12-20 Thread Bernhard Walle
That 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.


Signed-off-by: Bernhard Walle <[EMAIL PROTECTED]>

---
 arch/x86/Kconfig   |2 -
 drivers/rtc/rtc-cmos.c |   79 -
 2 files changed, 67 insertions(+), 14 deletions(-)

--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -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.
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -35,10 +35,22 @@
 #include 
 #include 
 #include 
+#include 
 
 /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
 #include 
 
+#ifndef CONFIG_HPET_EMULATE_RTC
+#define is_hpet_enabled()  0
+#define hpet_set_alarm_time(hrs, min, sec) do { } while (0)
+#define hpet_set_periodic_freq(arg)0
+#define hpet_mask_rtc_irq_bit(arg) do { } while (0)
+#define hpet_set_rtc_irq_bit(arg)  do { } while (0)
+#define hpet_rtc_timer_init()  do { } while (0)
+#define hpet_register_irq_handler(h)   0
+#define hpet_unregister_irq_handler(h) do { } while (0)
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+#endif
 
 struct cmos_rtc {
struct rtc_device   *rtc;
@@ -199,6 +211,7 @@ static int cmos_set_alarm(struct device 
sec = t->time.tm_sec;
sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
 
+   hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
spin_lock_irq(&rtc_lock);
 
/* next rtc irq must not be from previous alarm setting */
@@ -252,7 +265,8 @@ static int cmos_irq_set_freq(struct devi
f = 16 - f;
 
spin_lock_irqsave(&rtc_lock, flags);
-   CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+   if (!hpet_set_periodic_freq(freq))
+   CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
spin_unlock_irqrestore(&rtc_lock, flags);
 
return 0;
@@ -314,28 +328,37 @@ cmos_rtc_ioctl(struct device *dev, unsig
switch (cmd) {
case RTC_AIE_OFF:   /* alarm off */
rtc_control &= ~RTC_AIE;
+   hpet_mask_rtc_irq_bit(RTC_AIE);
break;
case RTC_AIE_ON:/* alarm on */
rtc_control |= RTC_AIE;
+   hpet_set_rtc_irq_bit(RTC_AIE);
break;
case RTC_UIE_OFF:   /* update off */
rtc_control &= ~RTC_UIE;
+   hpet_mask_rtc_irq_bit(RTC_UIE);
break;
case RTC_UIE_ON:/* update on */
rtc_control |= RTC_UIE;
+   hpet_set_rtc_irq_bit(RTC_UIE);
break;
case RTC_PIE_OFF:   /* periodic off */
rtc_control &= ~RTC_PIE;
+   hpet_mask_rtc_irq_bit(RTC_PIE);
break;
case RTC_PIE_ON:/* periodic on */
rtc_control |= RTC_PIE;
+   hpet_set_rtc_irq_bit(RTC_PIE);
break;
}
-   CMOS_WRITE(rtc_control, RTC_CONTROL);
+   if (!is_hpet_enabled())
+   CMOS_WRITE(rtc_control, RTC_CONTROL);
+
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
 }
@@ -475,15 +498,25 @@ static irqreturn_t cmos_interrupt(int ir
u8  rtc_control;
 
spin_lock(&rtc_lock);
-   irqstat = CMOS_READ(RTC_INTR_FLAGS);
-   rtc_control = CMOS_READ(RTC_CONTROL);
-   irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+   /*
+* In this case it is HPET RTC interrupt handler
+* calling us, with the interrupt information
+* passed as arg1, instead of irq.
+*/
+   if (is_hpet_enabled())
+   irqstat = (unsigned long)irq & 0xF0;
+   else {
+   irqstat = CMOS_READ(RTC_INTR_FLAGS);
+   rtc_control = CMOS_READ(RTC_CONTROL);
+   irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+   }
 
/* All Linux RTC alarms should be treated as if they were oneshot.
 * Similar code may be needed in system wakeup paths, in case the
 * alarm woke the system.
 */
if (irqstat & RTC_AIE) {
+   rtc_control = CMOS_READ(RTC_CONTROL);
rtc_control &= ~RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
@@ -591,8 +624,9 @@ cmos_do_probe(struct device *dev, struct
  

[PATCH] Add HPET RTC emulation to RTC_DRV_CMOS

2007-12-20 Thread Bernhard Walle
That 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.


Signed-off-by: Bernhard Walle <[EMAIL PROTECTED]>

---
 arch/x86/Kconfig   |2 -
 drivers/rtc/rtc-cmos.c |   79 -
 2 files changed, 67 insertions(+), 14 deletions(-)

--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -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.
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -35,10 +35,22 @@
 #include 
 #include 
 #include 
+#include 
 
 /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
 #include 
 
+#ifndef CONFIG_HPET_EMULATE_RTC
+#define is_hpet_enabled()  0
+#define hpet_set_alarm_time(hrs, min, sec) do { } while (0)
+#define hpet_set_periodic_freq(arg)0
+#define hpet_mask_rtc_irq_bit(arg) do { } while (0)
+#define hpet_set_rtc_irq_bit(arg)  do { } while (0)
+#define hpet_rtc_timer_init()  do { } while (0)
+#define hpet_register_irq_handler(h)   0
+#define hpet_unregister_irq_handler(h) do { } while (0)
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+#endif
 
 struct cmos_rtc {
struct rtc_device   *rtc;
@@ -199,6 +211,7 @@ static int cmos_set_alarm(struct device 
sec = t->time.tm_sec;
sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
 
+   hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
spin_lock_irq(&rtc_lock);
 
/* next rtc irq must not be from previous alarm setting */
@@ -252,7 +265,8 @@ static int cmos_irq_set_freq(struct devi
f = 16 - f;
 
spin_lock_irqsave(&rtc_lock, flags);
-   CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+   if (!hpet_set_periodic_freq(freq))
+   CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
spin_unlock_irqrestore(&rtc_lock, flags);
 
return 0;
@@ -314,28 +328,37 @@ cmos_rtc_ioctl(struct device *dev, unsig
switch (cmd) {
case RTC_AIE_OFF:   /* alarm off */
rtc_control &= ~RTC_AIE;
+   hpet_mask_rtc_irq_bit(RTC_AIE);
break;
case RTC_AIE_ON:/* alarm on */
rtc_control |= RTC_AIE;
+   hpet_set_rtc_irq_bit(RTC_AIE);
break;
case RTC_UIE_OFF:   /* update off */
rtc_control &= ~RTC_UIE;
+   hpet_mask_rtc_irq_bit(RTC_UIE);
break;
case RTC_UIE_ON:/* update on */
rtc_control |= RTC_UIE;
+   hpet_set_rtc_irq_bit(RTC_UIE);
break;
case RTC_PIE_OFF:   /* periodic off */
rtc_control &= ~RTC_PIE;
+   hpet_mask_rtc_irq_bit(RTC_PIE);
break;
case RTC_PIE_ON:/* periodic on */
rtc_control |= RTC_PIE;
+   hpet_set_rtc_irq_bit(RTC_PIE);
break;
}
-   CMOS_WRITE(rtc_control, RTC_CONTROL);
+   if (!is_hpet_enabled())
+   CMOS_WRITE(rtc_control, RTC_CONTROL);
+
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
 }
@@ -475,15 +498,25 @@ static irqreturn_t cmos_interrupt(int ir
u8  rtc_control;
 
spin_lock(&rtc_lock);
-   irqstat = CMOS_READ(RTC_INTR_FLAGS);
-   rtc_control = CMOS_READ(RTC_CONTROL);
-   irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+   /*
+* In this case it is HPET RTC interrupt handler
+* calling us, with the interrupt information
+* passed as arg1, instead of irq.
+*/
+   if (is_hpet_enabled())
+   irqstat = (unsigned long)irq & 0xF0;
+   else {
+   irqstat = CMOS_READ(RTC_INTR_FLAGS);
+   rtc_control = CMOS_READ(RTC_CONTROL);
+   irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+   }
 
/* All Linux RTC alarms should be treated as if they were oneshot.
 * Similar code may be needed in system wakeup paths, in case the
 * alarm woke the system.
 */
if (irqstat & RTC_AIE) {
+   rtc_control = CMOS_READ(RTC_CONTROL);
rtc_control &= ~RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
@@ -591,8 +624,9 @@ cmos_do_probe(struct device *dev, struct
  

Re: [PATCH] Add HPET RTC emulation to RTC_DRV_CMOS

2007-12-20 Thread Bernhard Walle
* Bernhard Walle <[EMAIL PROTECTED]> [2007-12-20 16:24]:
...


This was an accident. The patch belongs to a patch series that I'll
post later. Please ignore!


Thanks,
   Bernhard
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/