public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* RE: [PATCH][2.6][5/5]Support for HPET based timer
@ 2003-08-21 20:56 Pallipadi, Venkatesh
  0 siblings, 0 replies; 12+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-21 20:56 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: linux-kernel, torvalds, Nakajima, Jun, Mallick, Asit K




> -----Original Message-----
> From: Vojtech Pavlik [mailto:vojtech@suse.cz] 
> Indeed. The main problem, however, for me was to decide which 
> IRQ to use
> for the HPET. The HPET has a big mask of allowable IRQs, the APIC has
> many pins - so how to decide which one to use and if possible 
> not share
> it with a PCI device?

This possibly can be done by selecting the pin that is not already
programmed by 
setup_IO_APIC_irqs(), and do a manual setup_IO_APIC_irqs() on that, for
HPET
usage.

> That'd work probably. I don't believe there will ever be systems with
> HPET and without a working IOAPIC. But, well, insane things do happen.
> 
> As for the user disabling it, we could disable HPET then, 
> too. Anyway, I
> agree with your proposal of first going for legacy mode and 
> doing native
> mode later. 

Thanks for all the comments/suggestions. I will work on using early
ioremap in 
place of fixmap and resend the patch.

> (PS. It's a pretty stupid thing in the HPET spec to only be able to
>  gobble up BOTH the PIT and RTC interrupts and not separately.)

I totally agree with you. Just one additional bit would have solved the 
these problems. Also, I do not understand why RTC interrupts were
overridden 
at all, when HPET cannot provide complete RTC functionality and it does
not 
know anything about RTC time.


Thanks,
-Venkatesh



> -- 
> Vojtech Pavlik
> SuSE Labs, SuSE CR
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread
* RE: [PATCH][2.6][5/5]Support for HPET based timer
@ 2003-08-20 17:51 Pallipadi, Venkatesh
  2003-08-21  8:25 ` Vojtech Pavlik
  0 siblings, 1 reply; 12+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-20 17:51 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: linux-kernel, torvalds, Nakajima, Jun, Mallick, Asit K



> -----Original Message-----
> From: Vojtech Pavlik [mailto:vojtech@suse.cz] 
> On Tue, Aug 19, 2003 at 06:28:40PM -0700, Pallipadi, Venkatesh wrote:
> > 
> Yes, that is a problem. We could do some switchover from PIT 
> to HPET (or
> from legacy to IOAPIC IRQs) after APICs are initialized, 
> though I don't
> like the idea very much. Best would be to remove the dependence on the
> timer interrupt ticking so early. Or moving APIC detection earlier.

I agree. Depending both on PIT and HPET is not a clean solution. Also, I
am not that 
comfortable with moving APIC detection earlier, as it can possibly break
different
things on different platforms. It will surely need lot more testing. 

The way I got standard mode to work was by removing the dependency on
the early timer tick.
IIRC, the dependency is basically coming from Bogomips calculation and
also halt_works_ok
check. We can try and delay this until IOAPIC initialization.

> Well, the APIC should have quite a number of free pins, which 
> means that
> the HPET shouldn't need to share an interrupt. 

We interacted with some server folks, and they were of the opinion that
they may not be able to give a dedicated interrupt for HPET, as already
they have too many devices sitting on PCI these days. If they have to
give a dedicated IRQ for HPET, they may have to share some other
devices, which may result in performance loss. Another reason against it
was, if they give a dedicated IRQ and the OS decides against using HPET
(or older version of OS), then an IRQ will be needlessly wasted (kind of
a chicken and egg problem).

> Regarding lost and late
> delivered timer interrupts - that happens nevertheless with drivers
> disabling interrupts for a long time. The kernel timekeeping code can
> cope with that.

I agree that kernel can cope with the timer interrupt inaccuracy. But,
IMO, delays due to driver disabling the interrupts is more of an
exception case. With timer in shared interrupt, this will become more of
a common case.

Our thinking was to have a two phased approach. Have the legacy mode
enabled first. Make sure that the code around HPET interrupts is fully
optimized and is working fine. This mode is any way _required_ for
systems without IOAPIC and systems running UP kernels / with IOAPIC
disabled. Later we can add an option to use HPET standard mode.

Thanks,
-Venkatesh 



^ permalink raw reply	[flat|nested] 12+ messages in thread
* RE: [PATCH][2.6][5/5]Support for HPET based timer
@ 2003-08-20  1:28 Pallipadi, Venkatesh
  2003-08-20  8:10 ` Vojtech Pavlik
  0 siblings, 1 reply; 12+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-20  1:28 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: linux-kernel, torvalds, Nakajima, Jun, Mallick, Asit K


I experimented with HPET in native APIC routing mode. But, there 
are couple of issues in that space:

1) During boot up kernel expects to receive timer interrupt much before
the 
IO-APIC initialization is done. If HPET uses native mode, it cannot
generate 
timer interrupts till IOAPICs are initialized. So, we need to have some
sort of 
Workarounds in generic kernel to avoid dependency on timer interrupt
during the 
early boot.

2) More important question is, do we really want to share timer
interrupt with 
other PCI devices? This potentially can add some delay in the timer
interrupt 
processing, and thus we may end up getting inaccurate time (and
inaccurate 
timer interrupts) in the kernel.

Thanks,
-Venkatesh
> -----Original Message-----
> From: Vojtech Pavlik [mailto:vojtech@suse.cz] 
> Sent: Tuesday, August 19, 2003 3:41 PM
> To: Pallipadi, Venkatesh
> Cc: linux-kernel@vger.kernel.org; torvalds@osdl.org; 
> Nakajima, Jun; Mallick, Asit K
> Subject: Re: [PATCH][2.6][5/5]Support for HPET based timer
> 
> 
> On Tue, Aug 19, 2003 at 12:20:22PM -0700, Pallipadi, Venkatesh wrote:
> 
> > 5/5 - hpet5.patch - This can be a standalone patch. Without this
> >                     patch we loose interrupt generation capability
> >                     of RTC (/dev/rtc), due to HPET. With this patch
> >                     we basically try to emulate RTC interrupt
> >                     functions in software using HPET counter 1.
> > 
> 
> This is very wrong IMO. We shouldn't try to emulate the RTC interrupt
> for the kernel, instead the HPET should use native APIC interrupt
> routing. This way the RTC will keep working and the 'legacy mode' of
> HPET doesn't need to be used. I must admit I was a bit lazy when I was
> implementing the x86_64 variant and the native IRQ for HPET 
> is still on
> my to-do list.
> 
> -- 
> Vojtech Pavlik
> SuSE Labs, SuSE CR
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread
* [PATCH][2.6][5/5]Support for HPET based timer
@ 2003-08-19 19:20 Pallipadi, Venkatesh
  2003-08-19 22:41 ` Vojtech Pavlik
  0 siblings, 1 reply; 12+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-19 19:20 UTC (permalink / raw)
  To: linux-kernel; +Cc: torvalds, Nakajima, Jun, Mallick, Asit K

[-- Attachment #1: Type: text/plain, Size: 14402 bytes --]

5/5 - hpet5.patch - This can be a standalone patch. Without this
                    patch we loose interrupt generation capability
                    of RTC (/dev/rtc), due to HPET. With this patch
                    we basically try to emulate RTC interrupt
                    functions in software using HPET counter 1.






diff -purN linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c linux-2.6.0-test1-hpet-rtc/arch/i386/kernel/time_hpet.c
--- linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c	2003-08-18 20:22:06.000000000 -0700
+++ linux-2.6.0-test1-hpet-rtc/arch/i386/kernel/time_hpet.c	2003-08-18 20:25:14.000000000 -0700
@@ -151,3 +151,225 @@ static int __init hpet_setup(char* str)
 
 __setup("hpet=", hpet_setup);
 
+#ifdef CONFIG_HPET_EMULATE_RTC
+/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET 
+ * is enabled, we support RTC interrupt functionality in software. 
+ * RTC has 3 kinds of interrupts:
+ * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
+ *    is updated
+ * 2) Alarm Interrupt - generate an interrupt at a specific time of day
+ * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
+ *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
+ * (1) and (2) above are implemented using polling at a frequency of 
+ * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
+ * overhead. (DEFAULT_RTC_INT_FREQ)
+ * For (3), we use interrupts at 64Hz or user specified periodic 
+ * frequency, whichever is higher.
+ */
+#include <linux/mc146818rtc.h>
+#include <linux/rtc.h>
+
+extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern void get_rtc_time(struct rtc_time *rtc_tm);
+
+#define DEFAULT_RTC_INT_FREQ 	64
+#define RTC_NUM_INTS 		1
+
+static unsigned long UIE_on;
+static unsigned long prev_update_sec;
+
+static unsigned long AIE_on;
+static struct rtc_time alarm_time;
+
+static unsigned long PIE_on;
+static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;
+static unsigned long PIE_count;
+
+static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */
+
+/*
+ * Timer 1 for RTC, we do not use periodic interrupt feature, 
+ * even if HPET supports periodic interrupts on Timer 1.
+ * The reason being, to set up a periodic interrupt in HPET, we need to 
+ * stop the main counter. And if we do that everytime someone diables/enables
+ * RTC, we will have adverse effect on main kernel timer running on Timer 0.
+ * So, for the time being, simulate the periodic interrupt in software.
+ * 
+ * hpet_rtc_timer_init() is called for the first time and during subsequent 
+ * interuppts reinit happens through hpet_rtc_timer_reinit().
+ */
+int hpet_rtc_timer_init(void)
+{
+	unsigned int cfg, cnt;
+	unsigned long flags;
+
+	if (!is_hpet_enabled())
+		return 0;
+	/*
+	 * Stop the timers and reset the main counter.
+	 */
+	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
+		hpet_rtc_int_freq = PIE_freq;
+	else
+		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+	local_irq_save(flags);
+	cnt = hpet_readl(HPET_COUNTER);
+	cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
+	hpet_writel(cnt, HPET_T1_CMP);
+	local_irq_restore(flags);
+
+	cfg = hpet_readl(HPET_T1_CFG);
+	cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT;
+	hpet_writel(cfg, HPET_T1_CFG);
+
+	return 1;
+}
+
+static void hpet_rtc_timer_reinit(void)
+{
+	unsigned int cfg, cnt;
+
+	if (!(PIE_on | AIE_on | UIE_on))
+		return;
+
+	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
+		hpet_rtc_int_freq = PIE_freq;
+	else
+		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
+
+	/* It is more accurate to use the comparator value than current count.*/
+	cnt = hpet_readl(HPET_T1_CMP);
+	cnt += hpet_tick*HZ/hpet_rtc_int_freq;
+	hpet_writel(cnt, HPET_T1_CMP);
+
+	cfg = hpet_readl(HPET_T1_CFG);
+	cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT;
+	hpet_writel(cfg, HPET_T1_CFG);
+
+	return;
+}
+
+/* 
+ * The functions below are called from rtc driver. 
+ * Return 0 if HPET is not being used.
+ * Otherwise do the necessary changes and return 1.
+ */
+int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	if (bit_mask & RTC_UIE)
+		UIE_on = 0;
+	if (bit_mask & RTC_PIE)
+		PIE_on = 0;
+	if (bit_mask & RTC_AIE)
+		AIE_on = 0;
+
+	return 1;
+}
+
+int hpet_set_rtc_irq_bit(unsigned long bit_mask)
+{
+	int timer_init_reqd = 0;
+
+	if (!is_hpet_enabled())
+		return 0;
+
+	if (!(PIE_on | AIE_on | UIE_on))
+		timer_init_reqd = 1;
+
+	if (bit_mask & RTC_UIE) {
+		UIE_on = 1;
+	}
+	if (bit_mask & RTC_PIE) {
+		PIE_on = 1;
+		PIE_count = 0;
+	}
+	if (bit_mask & RTC_AIE) {
+		AIE_on = 1;
+	}
+
+	if (timer_init_reqd)
+		hpet_rtc_timer_init();
+
+	return 1;
+}
+
+int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	alarm_time.tm_hour = hrs;
+	alarm_time.tm_min = min;
+	alarm_time.tm_sec = sec;
+
+	return 1;
+}
+
+int hpet_set_periodic_freq(unsigned long freq)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	PIE_freq = freq;
+	PIE_count = 0;
+
+	return 1;
+}
+
+int hpet_rtc_dropped_irq(void)
+{
+	if (!is_hpet_enabled())
+		return 0;
+
+	return 1;
+}
+
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct rtc_time curr_time;
+	unsigned long rtc_int_flag = 0;
+	int call_rtc_interrupt = 0;
+
+	hpet_rtc_timer_reinit();
+
+	if (UIE_on | AIE_on) {
+		get_rtc_time(&curr_time);
+	}
+	if (UIE_on) {
+		if (curr_time.tm_sec != prev_update_sec) {
+			/* Set update int info, call real rtc int routine */
+			call_rtc_interrupt = 1;
+			rtc_int_flag = RTC_UF;
+			prev_update_sec = curr_time.tm_sec;
+		}
+	}
+	if (PIE_on) {
+		PIE_count++;
+		if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {
+			/* Set periodic int info, call real rtc int routine */
+			call_rtc_interrupt = 1;
+			rtc_int_flag |= RTC_PF;
+			PIE_count = 0;
+		}
+	}
+	if (AIE_on) {
+		if ((curr_time.tm_sec == alarm_time.tm_sec) &&
+		    (curr_time.tm_min == alarm_time.tm_min) &&
+		    (curr_time.tm_hour == alarm_time.tm_hour)) {
+			/* Set alarm int info, call real rtc int routine */
+			call_rtc_interrupt = 1;
+			rtc_int_flag |= RTC_AF;
+		}
+	}
+	if (call_rtc_interrupt) {
+		rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
+		rtc_interrupt(rtc_int_flag, dev_id, regs);
+	}
+	return IRQ_HANDLED;
+}
+#endif
+
diff -purN linux-2.6.0-test1-hpet/include/asm-i386/hpet.h linux-2.6.0-test1-hpet-rtc/include/asm-i386/hpet.h
--- linux-2.6.0-test1-hpet/include/asm-i386/hpet.h	2003-08-18 20:22:40.000000000 -0700
+++ linux-2.6.0-test1-hpet-rtc/include/asm-i386/hpet.h	2003-08-18 20:25:32.000000000 -0700
@@ -100,5 +100,15 @@ extern unsigned long hpet_virt_address;	
 extern int hpet_enable(void);
 extern int is_hpet_enabled(void);
 
+#ifdef CONFIG_RTC
+#define CONFIG_HPET_EMULATE_RTC 	1
+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, unsigned char sec);
+extern int hpet_set_periodic_freq(unsigned long freq);
+extern int hpet_rtc_dropped_irq(void);
+extern int hpet_rtc_timer_init(void);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+#endif /* CONFIG_RTC */
 #endif /* CONFIG_HPET_TIMER */
 #endif /* _I386_HPET_H */
diff -purN linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h linux-2.6.0-test1-hpet-rtc/include/asm-i386/mc146818rtc.h
--- linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h	2003-08-18 20:23:43.000000000 -0700
+++ linux-2.6.0-test1-hpet-rtc/include/asm-i386/mc146818rtc.h	2003-08-18 20:25:44.000000000 -0700
@@ -24,10 +24,6 @@ outb_p((addr),RTC_PORT(0)); \
 outb_p((val),RTC_PORT(1)); \
 })
 
-#ifdef CONFIG_HPET_TIMER
 #define RTC_IRQ 0
-#else
-#define RTC_IRQ 8
-#endif
 
 #endif /* _ASM_MC146818RTC_H */
diff -purN linux-2.6.0-test1/drivers/char/rtc.c linux-2.6.0-test1-hpet/drivers/char/rtc.c
--- linux-2.6.0-test1/drivers/char/rtc.c	2003-07-13 20:33:12.000000000 -0700
+++ linux-2.6.0-test1-hpet/drivers/char/rtc.c	2003-08-18 20:08:12.000000000 -0700
@@ -43,6 +43,8 @@
  *	1.10e	Maciej W. Rozycki: Handle DECstation's year weirdness.
  *      1.11    Takashi Iwai: Kernel access functions
  *			      rtc_register/rtc_unregister/rtc_control
+ *              Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
+ *              CONFIG_HPET_EMULATE_RTC
  */
 
 #define RTC_VERSION		"1.11"
@@ -78,6 +80,10 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+#if defined(__i386__)
+#include <asm/hpet.h>
+#endif
+
 #ifdef __sparc__
 #include <linux/pci.h>
 #include <asm/ebus.h>
@@ -118,7 +124,7 @@ static int rtc_ioctl(struct inode *inode
 static unsigned int rtc_poll(struct file *file, poll_table *wait);
 #endif
 
-static void get_rtc_time (struct rtc_time *rtc_tm);
+void get_rtc_time (struct rtc_time *rtc_tm);
 static void get_rtc_alm_time (struct rtc_time *alm_tm);
 #if RTC_IRQ
 static void rtc_dropped_irq(unsigned long data);
@@ -180,7 +186,7 @@ static const unsigned char days_in_mo[] 
  *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
  */
 
-static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	/*
 	 *	Can be an alarm interrupt, update complete interrupt,
@@ -192,7 +198,19 @@ static irqreturn_t rtc_interrupt(int irq
 	spin_lock (&rtc_lock);
 	rtc_irq_data += 0x100;
 	rtc_irq_data &= ~0xff;
-	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+#ifdef CONFIG_HPET_EMULATE_RTC
+	if (is_hpet_enabled()) {
+		/*
+		 * In this case it is HPET RTC interrupt handler
+		 * calling us, with the interrupt information
+		 * passed as arg1, instead of irq.
+		 */
+		rtc_irq_data |= (unsigned long)irq & 0xF0;
+	} else
+#endif
+	{
+		rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+	}
 
 	if (rtc_status & RTC_TIMER_ON)
 		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
@@ -427,6 +445,14 @@ static int rtc_do_ioctl(unsigned int cmd
 		sec = alm_tm.tm_sec;
 
 		spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_HPET_EMULATE_RTC
+		if (hpet_set_alarm_time(hrs, min, sec)) {
+			/*
+			 * Fallthru and set alarm time in CMOS too, 
+			 * so that we will get proper value in RTC_ALM_READ
+			 */
+		}
+#endif
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
 		    RTC_ALWAYS_BCD)
 		{
@@ -580,6 +606,12 @@ static int rtc_do_ioctl(unsigned int cmd
 			return -EINVAL;
 
 		spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_HPET_EMULATE_RTC
+		if (hpet_set_periodic_freq(arg)) {
+			spin_unlock_irq(&rtc_lock);
+			return 0;
+		}
+#endif
 		rtc_freq = arg;
 
 		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
@@ -665,6 +697,9 @@ static int rtc_release(struct inode *ino
 	 */
 
 	spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_HPET_EMULATE_RTC
+	hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE);
+#endif
 	tmp = CMOS_READ(RTC_CONTROL);
 	tmp &=  ~RTC_PIE;
 	tmp &=  ~RTC_AIE;
@@ -754,6 +789,9 @@ int rtc_unregister(rtc_task_t *task)
 	unsigned char tmp;
 
 	spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_HPET_EMULATE_RTC
+	hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE);
+#endif
 	spin_lock(&rtc_task_lock);
 	if (rtc_callback != task) {
 		spin_unlock(&rtc_task_lock);
@@ -820,6 +858,8 @@ static struct miscdevice rtc_dev=
 	&rtc_fops
 };
 
+static irqreturn_t (*rtc_int_handler_ptr)(int irq, void *dev_id, struct pt_regs *regs);
+
 static int __init rtc_init(void)
 {
 #if defined(__alpha__) || defined(__mips__)
@@ -888,17 +928,30 @@ no_irq:
 	}
 
 #if RTC_IRQ
-	if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
+#ifdef CONFIG_HPET_EMULATE_RTC
+	if (is_hpet_enabled()) {
+		rtc_int_handler_ptr = hpet_rtc_interrupt;
+	} else
+#endif
+	{
+		rtc_int_handler_ptr = rtc_interrupt;
+	}
+	
+	if(request_irq(RTC_IRQ, rtc_int_handler_ptr, SA_INTERRUPT, "rtc", NULL))
 	{
 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
 		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
 		release_region(RTC_PORT(0), RTC_IO_EXTENT);
 		return -EIO;
 	}
+#ifdef CONFIG_HPET_EMULATE_RTC
+	hpet_rtc_timer_init();
+#endif
 #endif
 
 #endif /* __sparc__ vs. others */
 
+	printk("rtc_timier_init() init\n");
 	if (misc_register(&rtc_dev))
 		{
 #if RTC_IRQ
@@ -961,8 +1014,11 @@ no_irq:
 	spin_lock_irq(&rtc_lock);
 	/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
-	spin_unlock_irq(&rtc_lock);
 	rtc_freq = 1024;
+#ifdef CONFIG_HPET_EMULATE_RTC
+	hpet_set_periodic_freq(rtc_freq);
+#endif
+	spin_unlock_irq(&rtc_lock);
 no_irq2:
 #endif
 
@@ -1013,6 +1069,13 @@ static void rtc_dropped_irq(unsigned lon
 
 	spin_lock_irq (&rtc_lock);
 
+#ifdef CONFIG_HPET_EMULATE_RTC
+	if (hpet_rtc_dropped_irq()) {
+		spin_unlock_irq(&rtc_lock);
+		return;
+	}
+#endif
+
 	/* Just in case someone disabled the timer from behind our back... */
 	if (rtc_status & RTC_TIMER_ON)
 		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
@@ -1142,7 +1205,7 @@ static inline unsigned char rtc_is_updat
 	return uip;
 }
 
-static void get_rtc_time(struct rtc_time *rtc_tm)
+void get_rtc_time(struct rtc_time *rtc_tm)
 {
 	unsigned long uip_watchdog = jiffies;
 	unsigned char ctrl;
@@ -1248,6 +1311,12 @@ static void mask_rtc_irq_bit(unsigned ch
 	unsigned char val;
 
 	spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_HPET_EMULATE_RTC
+	if (hpet_mask_rtc_irq_bit(bit)) {
+		spin_unlock_irq(&rtc_lock);
+		return;
+	}
+#endif
 	val = CMOS_READ(RTC_CONTROL);
 	val &=  ~bit;
 	CMOS_WRITE(val, RTC_CONTROL);
@@ -1262,6 +1331,12 @@ static void set_rtc_irq_bit(unsigned cha
 	unsigned char val;
 
 	spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_HPET_EMULATE_RTC
+	if (hpet_set_rtc_irq_bit(bit)) {
+		spin_unlock_irq(&rtc_lock);
+		return;
+	}
+#endif
 	val = CMOS_READ(RTC_CONTROL);
 	val |= bit;
 	CMOS_WRITE(val, RTC_CONTROL);



[-- Attachment #2: hpet5.ZIP --]
[-- Type: application/x-zip-compressed, Size: 4201 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2003-08-21 20:56 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <mmGp.wp.3@gated-at.bofh.it>
     [not found] ` <mnsM.1eL.13@gated-at.bofh.it>
     [not found]   ` <moRP.2r8.11@gated-at.bofh.it>
2003-08-20  0:31     ` [PATCH][2.6][5/5]Support for HPET based timer Andi Kleen
2003-08-20  1:04       ` Jamie Lokier
2003-08-20  8:05         ` Vojtech Pavlik
2003-08-21 20:56 Pallipadi, Venkatesh
  -- strict thread matches above, loose matches on Subject: below --
2003-08-20 17:51 Pallipadi, Venkatesh
2003-08-21  8:25 ` Vojtech Pavlik
2003-08-20  1:28 Pallipadi, Venkatesh
2003-08-20  8:10 ` Vojtech Pavlik
2003-08-19 19:20 Pallipadi, Venkatesh
2003-08-19 22:41 ` Vojtech Pavlik
2003-08-20  0:08   ` Jamie Lokier
2003-08-20  8:03     ` Vojtech Pavlik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox