linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* 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 17:51 [PATCH][2.6][5/5]Support for HPET based timer Pallipadi, Venkatesh
@ 2003-08-21  8:25 ` Vojtech Pavlik
  0 siblings, 0 replies; 12+ messages in thread
From: Vojtech Pavlik @ 2003-08-21  8:25 UTC (permalink / raw)
  To: Pallipadi, Venkatesh
  Cc: Vojtech Pavlik, linux-kernel, torvalds, Nakajima, Jun, Mallick, Asit K

On Wed, Aug 20, 2003 at 10:51:39AM -0700, Pallipadi, Venkatesh wrote:

> 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.

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?

> > 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).

Well, the number of interrupts if you have IO-APICs (or SAPICs) is
almost unlimited ... and usually on the IO-APIC that handles the PC
legacy there are some spare pins. Nevermind, I don't think it'd be a
huge problem to share the timer interrupt pin with some device.

> > 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.

Well, the driver is supposed to reenable the interrupt as soon as it can
(possibly disabling the card itself from generating further interrupts),
so it's back to bad drivers even in this 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.

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. 

(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.)

-- 
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-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  1:28 Pallipadi, Venkatesh
@ 2003-08-20  8:10 ` Vojtech Pavlik
  0 siblings, 0 replies; 12+ messages in thread
From: Vojtech Pavlik @ 2003-08-20  8:10 UTC (permalink / raw)
  To: Pallipadi, Venkatesh
  Cc: Vojtech Pavlik, linux-kernel, torvalds, Nakajima, Jun, Mallick, Asit K

On Tue, Aug 19, 2003 at 06:28:40PM -0700, Pallipadi, Venkatesh wrote:
> 
> 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.

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.

> 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.

Well, the APIC should have quite a number of free pins, which means that
the HPET shouldn't need to share an interrupt. 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.

> 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
> > 
> 

-- 
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  1:04       ` Jamie Lokier
@ 2003-08-20  8:05         ` Vojtech Pavlik
  0 siblings, 0 replies; 12+ messages in thread
From: Vojtech Pavlik @ 2003-08-20  8:05 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: Andi Kleen, linux-kernel, vojtech

On Wed, Aug 20, 2003 at 02:04:24AM +0100, Jamie Lokier wrote:

> Andi Kleen wrote:
> > Jamie Lokier <jamie@shareable.org> writes:
> > > Even on those machines where APIC interrupts are not usable?
> > > (E.g. due to interactions with the SMM BIOS).
> > 
> > On those you can always use the old style PIT.
> 
> Let me put the question better.  Is it worth using the new style HPET,
> on systems which cannot use APIC interrupts because of BIOS problems
> (e.g. IBM laptops)?

Those don't have a HPET. Easy.

-- 
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  0:08   ` Jamie Lokier
@ 2003-08-20  8:03     ` Vojtech Pavlik
  0 siblings, 0 replies; 12+ messages in thread
From: Vojtech Pavlik @ 2003-08-20  8:03 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Vojtech Pavlik, Pallipadi, Venkatesh, linux-kernel, torvalds,
	Nakajima, Jun, Mallick, Asit K

On Wed, Aug 20, 2003 at 01:08:56AM +0100, Jamie Lokier wrote:
> Vojtech Pavlik wrote:
> > 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.
> 
> Even on those machines where APIC interrupts are not usable?
> (E.g. due to interactions with the SMM BIOS).

Well, I suspect the machines with HPET should better have usable APIC
interrupts, because you won't be able to use all the HPET timers then -
only two can be routed via the timer and RTC interrupts, the other need
to use APIC or direct FSB delivery.

-- 
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  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

* Re: [PATCH][2.6][5/5]Support for HPET based timer
  2003-08-20  0:31     ` Andi Kleen
@ 2003-08-20  1:04       ` Jamie Lokier
  2003-08-20  8:05         ` Vojtech Pavlik
  0 siblings, 1 reply; 12+ messages in thread
From: Jamie Lokier @ 2003-08-20  1:04 UTC (permalink / raw)
  To: Andi Kleen; +Cc: linux-kernel, vojtech

Andi Kleen wrote:
> Jamie Lokier <jamie@shareable.org> writes:
> > Even on those machines where APIC interrupts are not usable?
> > (E.g. due to interactions with the SMM BIOS).
> 
> On those you can always use the old style PIT.

Let me put the question better.  Is it worth using the new style HPET,
on systems which cannot use APIC interrupts because of BIOS problems
(e.g. IBM laptops)?

-- Jamie

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

* Re: [PATCH][2.6][5/5]Support for HPET based timer
       [not found]   ` <moRP.2r8.11@gated-at.bofh.it>
@ 2003-08-20  0:31     ` Andi Kleen
  2003-08-20  1:04       ` Jamie Lokier
  0 siblings, 1 reply; 12+ messages in thread
From: Andi Kleen @ 2003-08-20  0:31 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: linux-kernel, vojtech

Jamie Lokier <jamie@shareable.org> writes:

> Even on those machines where APIC interrupts are not usable?
> (E.g. due to interactions with the SMM BIOS).

On those you can always use the old style PIT.

-Andi

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

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

Vojtech Pavlik wrote:
> 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.

Even on those machines where APIC interrupts are not usable?
(E.g. due to interactions with the SMM BIOS).

-- Jamie

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

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

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 --
2003-08-20 17:51 [PATCH][2.6][5/5]Support for HPET based timer Pallipadi, Venkatesh
2003-08-21  8:25 ` Vojtech Pavlik
  -- strict thread matches above, loose matches on Subject: below --
2003-08-21 20:56 Pallipadi, Venkatesh
2003-08-20  1:28 Pallipadi, Venkatesh
2003-08-20  8:10 ` Vojtech Pavlik
     [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     ` Andi Kleen
2003-08-20  1:04       ` Jamie Lokier
2003-08-20  8:05         ` 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;
as well as URLs for NNTP newsgroup(s).