linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH][2.6][2/5]Support for HPET based timer
       [not found] ` <20030820080513.GB17793@ucw.cz.suse.lists.linux.kernel>
@ 2003-08-20 10:01   ` Andi Kleen
  2003-08-20 10:47     ` Mikael Pettersson
  2003-08-20 17:09     ` Dave Hansen
  0 siblings, 2 replies; 16+ messages in thread
From: Andi Kleen @ 2003-08-20 10:01 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: linux-kernel, venkatesh.pallipadi

Vojtech Pavlik <vojtech@suse.cz> writes:

> On Tue, Aug 19, 2003 at 05:18:50PM -0700, Pallipadi, Venkatesh wrote:
> 
> > Fixmap is for HPET memory map address access. As the timer
> > initialization happen 
> > early in the boot sequence (before vm initialization), we need to have
> > fixmap() 
> > and fix_to_virt() to access HPET memory map address.
> 
> Ahh, yes, you're right. You can't use ioremap at that time. Actually I
> did the same on x86_64 not only because of vsyscalls.

iirc i386 has an ioremap_early or somesuch.

-Andi

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

* Re: [PATCH][2.6][2/5]Support for HPET based timer
  2003-08-20 10:01   ` [PATCH][2.6][2/5]Support for HPET based timer Andi Kleen
@ 2003-08-20 10:47     ` Mikael Pettersson
  2003-08-20 17:09     ` Dave Hansen
  1 sibling, 0 replies; 16+ messages in thread
From: Mikael Pettersson @ 2003-08-20 10:47 UTC (permalink / raw)
  To: Andi Kleen; +Cc: Vojtech Pavlik, linux-kernel, venkatesh.pallipadi

Andi Kleen writes:
 > Vojtech Pavlik <vojtech@suse.cz> writes:
 > 
 > > On Tue, Aug 19, 2003 at 05:18:50PM -0700, Pallipadi, Venkatesh wrote:
 > > 
 > > > Fixmap is for HPET memory map address access. As the timer
 > > > initialization happen 
 > > > early in the boot sequence (before vm initialization), we need to have
 > > > fixmap() 
 > > > and fix_to_virt() to access HPET memory map address.
 > > 
 > > Ahh, yes, you're right. You can't use ioremap at that time. Actually I
 > > did the same on x86_64 not only because of vsyscalls.
 > 
 > iirc i386 has an ioremap_early or somesuch.

bt_ioremap(). I wrote it to support early DMI scan so DMI data
could be used to blacklist BIOSen that break local APICs.
This was done pretty much just to handle Dell laptops.

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

* Re: [PATCH][2.6][2/5]Support for HPET based timer
  2003-08-20 10:01   ` [PATCH][2.6][2/5]Support for HPET based timer Andi Kleen
  2003-08-20 10:47     ` Mikael Pettersson
@ 2003-08-20 17:09     ` Dave Hansen
  1 sibling, 0 replies; 16+ messages in thread
From: Dave Hansen @ 2003-08-20 17:09 UTC (permalink / raw)
  To: Andi Kleen; +Cc: Vojtech Pavlik, Linux Kernel Mailing List, venkatesh.pallipadi

On Wed, 2003-08-20 at 03:01, Andi Kleen wrote:
> Vojtech Pavlik <vojtech@suse.cz> writes:
> 
> > On Tue, Aug 19, 2003 at 05:18:50PM -0700, Pallipadi, Venkatesh wrote:
> > 
> > > Fixmap is for HPET memory map address access. As the timer
> > > initialization happen 
> > > early in the boot sequence (before vm initialization), we need to have
> > > fixmap() 
> > > and fix_to_virt() to access HPET memory map address.
> > 
> > Ahh, yes, you're right. You can't use ioremap at that time. Actually I
> > did the same on x86_64 not only because of vsyscalls.
> 
> iirc i386 has an ioremap_early or somesuch.

Yep, we have boot_ioremap().  It's used to do ioremap() even while we're
still using the original early boot pagetables (before paging_init()):
arch/i386/mm/boot_ioremap.c

-- 
Dave Hansen
haveblue@us.ibm.com


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

* RE: [PATCH][2.6][2/5]Support for HPET based timer
@ 2003-08-26 23:50 Pallipadi, Venkatesh
  0 siblings, 0 replies; 16+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-26 23:50 UTC (permalink / raw)
  To: john stultz, Andrew Morton
  Cc: vojtech, Andi Kleen, Dave H, mikpe, Nakajima, Jun, Siddha,
	Suresh B, lkml



> -----Original Message-----
> From: john stultz [mailto:johnstul@us.ibm.com] 
> 
> Well, the difficult part is deciding in time_init() if we are going to
> use HPET without touching the hardware (to say, check if its actually
> there).
> 

Yes. But, currently we are using ACPI early table parse to look at HPET.
So we should be OK here.
Even if accessing HPET hardware fails later, in the late_time_init(), 
we can fallback to PIT, as long as calibrate_delay() is done after 
late_time_init().

> We could pick a simple time source (ie: PIT) that would get us through
> early boot, then choose the real time source in late_time_init(). That
> would also make implementing the ACPI PM time-source much simpler as
we
> could wait until after ACPI is up, letting us avoid having to parse
the
> tables by hand.
> 
> However I'm not sure it would be trivial and bug free. ;)
> 

Depending on multiple time sources may not be good idea, IMO. May be, 
one day we will have a fully-legacy-free system with no PIT. :)

Thanks,
-Venkatesh

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

* Re: [PATCH][2.6][2/5]Support for HPET based timer
  2003-08-26 18:55   ` Andrew Morton
@ 2003-08-26 23:20     ` john stultz
  0 siblings, 0 replies; 16+ messages in thread
From: john stultz @ 2003-08-26 23:20 UTC (permalink / raw)
  To: Andrew Morton
  Cc: venkatesh.pallipadi, vojtech, Andi Kleen, Dave H, mikpe,
	jun.nakajima, suresh.b.siddha, lkml

On Tue, 2003-08-26 at 11:55, Andrew Morton wrote:
> So I suggest you look at the latter option:
> 
> - change time_init() so that it doesn't actually touch the HPET hardware
>   in the HPET timer case.

Well, the difficult part is deciding in time_init() if we are going to
use HPET without touching the hardware (to say, check if its actually
there).

> - add late_time_init() after mem_init().
> 
> - then do calibrate_delay().
> 
> Or whatever.  The bottom line is that init/main.c is fragile, but not
> inviolable ;)


We could pick a simple time source (ie: PIT) that would get us through
early boot, then choose the real time source in late_time_init(). That
would also make implementing the ACPI PM time-source much simpler as we
could wait until after ACPI is up, letting us avoid having to parse the
tables by hand.

However I'm not sure it would be trivial and bug free. ;)

-john


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

* RE: [PATCH][2.6][2/5]Support for HPET based timer
@ 2003-08-26 21:43 Mikael Pettersson
  0 siblings, 0 replies; 16+ messages in thread
From: Mikael Pettersson @ 2003-08-26 21:43 UTC (permalink / raw)
  To: ak, akpm, haveblue, mikpe, venkatesh.pallipadi, vojtech
  Cc: jun.nakajima, linux-kernel, suresh.b.siddha

On Tue, 26 Aug 2003 11:31:16 -0700, "Pallipadi, Venkatesh" wrote:
>  This is an update on the option of using some sort of early_ioremap in
>place of fixmap for 
>HPET timers.
>
>Problem Description:
>  The requirement from HPET side is, we need to map HPET physical
>address during timer_init() 
>routine and also during any read/write HPET addresses. We need to have
>this mapping kind of
>permanently, as  we will do HPET reads/writes during every timer
>interrupt and also during 
>every gettimeofday (if we don't use tsc timer).
>  And the timer_init() happens before mem_init() (but after paging
>init()), so we cannot 
>directly use ioremap(). Current implementation is using a separate
>fixmap region for HPET.
...
>The question I have is,
>- Is it really worth to move from the current fixmap implementation to
>bt_ioremap/ioremap 
>combination, given all the changes that is required?
>- Isn't current implementation (using own fixmap) a cleaner way to do
>it? Only drawback 
>I see is it consumes one page in virtual memory when HPET is configured,
>irrespective of 
>HPET is used at run time or not.

As long as you _must_ map the HPET before ioremap() is working,
and you also must have a permanent mapping, then grabbing a fixmap
page is IMO the cleanest solution. This is for example how the
local APIC mapping is handled. boot/bt ioremap are as you noticed
for temporary mappings only.

However, dynamically migrating the timer to HPET after mem_init()
would be even better, since that avoids the problem altogether.

/Mikael

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

* Re: [PATCH][2.6][2/5]Support for HPET based timer
  2003-08-26 18:51 ` Andrew Morton
@ 2003-08-26 18:55   ` Andrew Morton
  2003-08-26 23:20     ` john stultz
  0 siblings, 1 reply; 16+ messages in thread
From: Andrew Morton @ 2003-08-26 18:55 UTC (permalink / raw)
  To: venkatesh.pallipadi, vojtech, ak, haveblue, mikpe, jun.nakajima,
	suresh.b.siddha, linux-kernel

Andrew Morton <akpm@osdl.org> wrote:
>
> I doubt if we really need the timer running that early, apart from for
>  calibrate_delay().
> 
>  You can probably move the time_init() and calibrate_delay() so they occur
>  after mem_init().  A close review would be needed to see if that is likely
>  to break anything.  If it is, then consider creating a new late_time_init()
>  thing, and call that and calibrate_delay() after mem_init().
> 

Actually, I think some platforms (ppc64) will explode if we do the
local_irq_enable() prior to time_init().

So I suggest you look at the latter option:

- change time_init() so that it doesn't actually touch the HPET hardware
  in the HPET timer case.

- add late_time_init() after mem_init().

- then do calibrate_delay().

Or whatever.  The bottom line is that init/main.c is fragile, but not
inviolable ;)



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

* Re: [PATCH][2.6][2/5]Support for HPET based timer
  2003-08-26 18:31 Pallipadi, Venkatesh
@ 2003-08-26 18:51 ` Andrew Morton
  2003-08-26 18:55   ` Andrew Morton
  0 siblings, 1 reply; 16+ messages in thread
From: Andrew Morton @ 2003-08-26 18:51 UTC (permalink / raw)
  To: Pallipadi, Venkatesh
  Cc: vojtech, ak, haveblue, mikpe, jun.nakajima, suresh.b.siddha,
	linux-kernel

"Pallipadi, Venkatesh" <venkatesh.pallipadi@intel.com> wrote:
>
> Problem Description:
>    The requirement from HPET side is, we need to map HPET physical
>  address during timer_init() 
>  routine and also during any read/write HPET addresses. We need to have
>  this mapping kind of
>  permanently, as  we will do HPET reads/writes during every timer
>  interrupt and also during 
>  every gettimeofday (if we don't use tsc timer).
>    And the timer_init() happens before mem_init() (but after paging
>  init()), so we cannot 
>  directly use ioremap(). Current implementation is using a separate
>  fixmap region for HPET.

I doubt if we really need the timer running that early, apart from for
calibrate_delay().

You can probably move the time_init() and calibrate_delay() so they occur
after mem_init().  A close review would be needed to see if that is likely
to break anything.  If it is, then consider creating a new late_time_init()
thing, and call that and calibrate_delay() after mem_init().




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

* RE: [PATCH][2.6][2/5]Support for HPET based timer
@ 2003-08-26 18:31 Pallipadi, Venkatesh
  2003-08-26 18:51 ` Andrew Morton
  0 siblings, 1 reply; 16+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-26 18:31 UTC (permalink / raw)
  To: Vojtech Pavlik, Andi Kleen, haveblue, Andrew Morton, mikpe
  Cc: Nakajima, Jun, Siddha, Suresh B, linux-kernel


Hi,

  This is an update on the option of using some sort of early_ioremap in
place of fixmap for 
HPET timers.

Problem Description:
  The requirement from HPET side is, we need to map HPET physical
address during timer_init() 
routine and also during any read/write HPET addresses. We need to have
this mapping kind of
permanently, as  we will do HPET reads/writes during every timer
interrupt and also during 
every gettimeofday (if we don't use tsc timer).
  And the timer_init() happens before mem_init() (but after paging
init()), so we cannot 
directly use ioremap(). Current implementation is using a separate
fixmap region for HPET.
 
Possible alternatives:
1) boot_ioremap - This looks like a temporary and very short time use
mapping. We may not be 
able to use it forever, for HPET purposes, as someone else can do the
mapping and overwrite 
HPET mapping anytime. Will need significant changes to supports multiple
users doing 
mapping/unmapping.
2) bt_ioremap - Even this seems to be aiming at temporary mapping.
Currently, this supports 
only one user at any time. This can be changed to support multiple users
and map and unmap 
depending on the address. But, bt_ioremap uses fixmap in its
implementation, and the fixmap 
is boot time only. So, we need to transparently switch to ioremap, at
some place before 
all inits are done.

Even after changing either boot_ioremap() or bt_ioremap(), we have to
add some more 
hooks to move from early ioremap to regular io_remap() after mem_init()
is done. And HPET 
addresses can get accessed from both process and interrupt context, may
make things slightly
more difficult. Still it is doable as we can move to regular ioremap
before smp_init(), without 
much of a race condition. So, possible changes in this scenario will be:
- Add support for multiple callers using different pages in
bt_ioremap(or  boot_ioremap).
- Add HPET specific hook, somewhere in between mem_init() and
smp_init(), to transparently
move from bt_ioremap to ioremap().

The question I have is,
- Is it really worth to move from the current fixmap implementation to
bt_ioremap/ioremap 
combination, given all the changes that is required?
- Isn't current implementation (using own fixmap) a cleaner way to do
it? Only drawback 
I see is it consumes one page in virtual memory when HPET is configured,
irrespective of 
HPET is used at run time or not.

Let me know your thoughts on this, and correct me if I am missing
anything here.

Thanks,
-Venkatesh


> -----Original Message-----
> From: Pallipadi, Venkatesh 
> Sent: Wednesday, August 20, 2003 10:02 AM
> To: Mikael Pettersson; Andi Kleen
> Cc: Vojtech Pavlik; linux-kernel@vger.kernel.org
> Subject: RE: [PATCH][2.6][2/5]Support for HPET based timer
> 
> 
> 
> Yes. I hadn't thought about early_ioremap option. There seems to be
> multiple ways of doing early ioremap: bt_ioremap() and 
> boot_ioremap(). I
> will look at them closer and work on changing HPET code to use one of
> these in place of fixmap.
> 
> Thanks,
> -Venkatesh  
> 
> > -----Original Message-----
> > From: Mikael Pettersson [mailto:mikpe@csd.uu.se] 
> > Sent: Wednesday, August 20, 2003 3:47 AM
> > To: Andi Kleen
> > Cc: Vojtech Pavlik; linux-kernel@vger.kernel.org; 
> Pallipadi, Venkatesh
> > Subject: Re: [PATCH][2.6][2/5]Support for HPET based timer
> > 
> > 
> > Andi Kleen writes:
> >  > Vojtech Pavlik <vojtech@suse.cz> writes:
> >  > 
> >  > > On Tue, Aug 19, 2003 at 05:18:50PM -0700, Pallipadi, 
> > Venkatesh wrote:
> >  > > 
> >  > > > Fixmap is for HPET memory map address access. As the timer
> >  > > > initialization happen 
> >  > > > early in the boot sequence (before vm initialization), 
> > we need to have
> >  > > > fixmap() 
> >  > > > and fix_to_virt() to access HPET memory map address.
> >  > > 
> >  > > Ahh, yes, you're right. You can't use ioremap at that 
> > time. Actually I
> >  > > did the same on x86_64 not only because of vsyscalls.
> >  > 
> >  > iirc i386 has an ioremap_early or somesuch.
> > 
> > bt_ioremap(). I wrote it to support early DMI scan so DMI data
> > could be used to blacklist BIOSen that break local APICs.
> > This was done pretty much just to handle Dell laptops.
> > 
> -
> To unsubscribe from this list: send the line "unsubscribe 
> linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* RE: [PATCH][2.6][2/5]Support for HPET based timer
@ 2003-08-20 17:01 Pallipadi, Venkatesh
  0 siblings, 0 replies; 16+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-20 17:01 UTC (permalink / raw)
  To: Mikael Pettersson, Andi Kleen; +Cc: Vojtech Pavlik, linux-kernel


Yes. I hadn't thought about early_ioremap option. There seems to be
multiple ways of doing early ioremap: bt_ioremap() and boot_ioremap(). I
will look at them closer and work on changing HPET code to use one of
these in place of fixmap.

Thanks,
-Venkatesh  

> -----Original Message-----
> From: Mikael Pettersson [mailto:mikpe@csd.uu.se] 
> Sent: Wednesday, August 20, 2003 3:47 AM
> To: Andi Kleen
> Cc: Vojtech Pavlik; linux-kernel@vger.kernel.org; Pallipadi, Venkatesh
> Subject: Re: [PATCH][2.6][2/5]Support for HPET based timer
> 
> 
> Andi Kleen writes:
>  > Vojtech Pavlik <vojtech@suse.cz> writes:
>  > 
>  > > On Tue, Aug 19, 2003 at 05:18:50PM -0700, Pallipadi, 
> Venkatesh wrote:
>  > > 
>  > > > Fixmap is for HPET memory map address access. As the timer
>  > > > initialization happen 
>  > > > early in the boot sequence (before vm initialization), 
> we need to have
>  > > > fixmap() 
>  > > > and fix_to_virt() to access HPET memory map address.
>  > > 
>  > > Ahh, yes, you're right. You can't use ioremap at that 
> time. Actually I
>  > > did the same on x86_64 not only because of vsyscalls.
>  > 
>  > iirc i386 has an ioremap_early or somesuch.
> 
> bt_ioremap(). I wrote it to support early DMI scan so DMI data
> could be used to blacklist BIOSen that break local APICs.
> This was done pretty much just to handle Dell laptops.
> 

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

* Re: [PATCH][2.6][2/5]Support for HPET based timer
  2003-08-20  0:18 Pallipadi, Venkatesh
@ 2003-08-20  8:05 ` Vojtech Pavlik
  0 siblings, 0 replies; 16+ messages in thread
From: Vojtech Pavlik @ 2003-08-20  8:05 UTC (permalink / raw)
  To: Pallipadi, Venkatesh
  Cc: Vojtech Pavlik, linux-kernel, torvalds, Nakajima, Jun, Mallick, Asit K

On Tue, Aug 19, 2003 at 05:18:50PM -0700, Pallipadi, Venkatesh wrote:

> Fixmap is for HPET memory map address access. As the timer
> initialization happen 
> early in the boot sequence (before vm initialization), we need to have
> fixmap() 
> and fix_to_virt() to access HPET memory map address.

Ahh, yes, you're right. You can't use ioremap at that time. Actually I
did the same on x86_64 not only because of vsyscalls.

> Yes. Most of the code is generic, and can run on other platforms. The
> only reason 
> I have that check is because, I haven't got chance to test this patch on
> other 
> platforms.
> 
> Thanks,
> -Venkatesh 
> 
> > -----Original Message-----
> > From: Vojtech Pavlik [mailto:vojtech@suse.cz] 
> > Sent: Tuesday, August 19, 2003 3:39 PM
> > To: Pallipadi, Venkatesh
> > Cc: linux-kernel@vger.kernel.org; torvalds@osdl.org; 
> > Nakajima, Jun; Mallick, Asit K
> > Subject: Re: [PATCH][2.6][2/5]Support for HPET based timer
> > 
> > 
> > On Tue, Aug 19, 2003 at 12:20:02PM -0700, Pallipadi, Venkatesh wrote:
> > 
> > > 2/5 - hpet2.patch - All the changes required to use HPET in place
> > >                     of PIT as the kernel base-timer at IRQ 0.
> > 
> > What are you using the fixmap() for? i386 doesn't have vsyscalls ...
> > 
> > Why are you limiting the HPET vendor ID to Intel? This code will
> > happily run on other vendor hardware as well ...
> > 
> >  
> > > diff -purN linux-2.6.0-test1/arch/i386/kernel/apic.c 
> > linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c
> > > --- linux-2.6.0-test1/arch/i386/kernel/apic.c	
> > 2003-07-13 20:39:27.000000000 -0700
> > > +++ linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c	
> > 2003-08-13 11:36:24.000000000 -0700
> > > @@ -34,6 +34,7 @@
> > >  #include <asm/pgalloc.h>
> > >  #include <asm/desc.h>
> > >  #include <asm/arch_hooks.h>
> > > +#include <asm/hpet.h>
> > >  
> > >  #include <mach_apic.h>
> > >  
> > > @@ -749,7 +750,8 @@ static unsigned int __init get_8254_time
> > >  	return count;
> > >  }
> > >  
> > > -void __init wait_8254_wraparound(void)
> > > +/* next tick in 8254 can be caught by catching timer wraparound */
> > > +static void __init wait_8254_wraparound(void)
> > >  {
> > >  	unsigned int curr_count, prev_count=~0;
> > >  	int delta;
> > > @@ -771,6 +773,12 @@ void __init wait_8254_wraparound(void)
> > >  }
> > >  
> > >  /*
> > > + * Default initialization for 8254 timers. If we use other 
> > timers like HPET,
> > > + * we override this later 
> > > + */
> > > +void (*wait_timer_tick)(void) = wait_8254_wraparound;
> > > +
> > > +/*
> > >   * This function sets up the local APIC timer, with a timeout of
> > >   * 'clocks' APIC bus clock. During calibration we actually call
> > >   * this function twice on the boot CPU, once with a bogus timeout
> > > @@ -811,7 +819,7 @@ static void setup_APIC_timer(unsigned in
> > >  	/*
> > >  	 * Wait for IRQ0's slice:
> > >  	 */
> > > -	wait_8254_wraparound();
> > > +	wait_timer_tick();
> > >  
> > >  	__setup_APIC_LVTT(clocks);
> > >  
> > > @@ -854,7 +862,7 @@ int __init calibrate_APIC_clock(void)
> > >  	 * (the current tick might have been already half done)
> > >  	 */
> > >  
> > > -	wait_8254_wraparound();
> > > +	wait_timer_tick();
> > >  
> > >  	/*
> > >  	 * We wrapped around just now. Let's start:
> > > @@ -867,7 +875,7 @@ int __init calibrate_APIC_clock(void)
> > >  	 * Let's wait LOOPS wraprounds:
> > >  	 */
> > >  	for (i = 0; i < LOOPS; i++)
> > > -		wait_8254_wraparound();
> > > +		wait_timer_tick();
> > >  
> > >  	tt2 = apic_read(APIC_TMCCT);
> > >  	if (cpu_has_tsc)
> > > diff -purN linux-2.6.0-test1/arch/i386/kernel/time.c 
> > linux-2.6.0-test1-hpet/arch/i386/kernel/time.c
> > > --- linux-2.6.0-test1/arch/i386/kernel/time.c	
> > 2003-07-13 20:34:29.000000000 -0700
> > > +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time.c	
> > 2003-08-18 12:36:25.000000000 -0700
> > > @@ -60,6 +60,8 @@
> > >  #include <linux/timex.h>
> > >  #include <linux/config.h>
> > >  
> > > +#include <asm/hpet.h>
> > > +
> > >  #include <asm/arch_hooks.h>
> > >  
> > >  #include "io_ports.h"
> > > @@ -298,6 +300,12 @@ void __init time_init(void)
> > >  	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
> > >  	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
> > >  
> > > +#ifdef CONFIG_HPET_TIMER
> > > +	if (hpet_enable() >= 0) {
> > > +		printk("Using HPET for base-timer\n");
> > > +	}
> > > +#endif
> > > +
> > >  	cur_timer = select_timer();
> > >  	time_init_hook();
> > >  }
> > > diff -purN linux-2.6.0-test1/arch/i386/kernel/time_hpet.c 
> > linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c
> > > --- linux-2.6.0-test1/arch/i386/kernel/time_hpet.c	
> > 1969-12-31 16:00:00.000000000 -0800
> > > +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c	
> > 2003-08-18 20:22:06.000000000 -0700
> > > @@ -0,0 +1,153 @@
> > > +/*
> > > + *  linux/arch/i386/kernel/time_hpet.c
> > > + *  This code largely copied from arch/x86_64/kernel/time.c
> > > + *  See that file for credits.
> > > + *
> > > + *  2003-06-30    Venkatesh Pallipadi - Additional changes 
> > for HPET support
> > > + */
> > > +
> > > +#include <linux/errno.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/param.h>
> > > +#include <linux/string.h>
> > > +#include <linux/init.h>
> > > +#include <linux/smp.h>
> > > +
> > > +#include <asm/timer.h>
> > > +#include <asm/fixmap.h>
> > > +#include <asm/apic.h>
> > > +
> > > +#include <linux/timex.h>
> > > +#include <linux/config.h>
> > > +
> > > +#include <asm/hpet.h>
> > > +
> > > +unsigned long hpet_period;	/* fsecs / HPET clock */
> > > +unsigned long hpet_tick;	/* hpet clks count per tick */
> > > +unsigned long hpet_address;	/* hpet memory map address */
> > > +
> > > +static int use_hpet; 		/* can be used for 
> > runtime check of hpet */
> > > +static int boot_hpet_disable; 	/* boottime override 
> > for HPET timer */
> > > +
> > > +#define FSEC_TO_USEC (1000000000UL)
> > > +
> > > +#ifdef CONFIG_X86_LOCAL_APIC
> > > +/*
> > > + * HPET counters dont wrap around on every tick. They just 
> > change the 
> > > + * comparator value and continue. Next tick can be caught 
> > by checking 
> > > + * for a change in the comparator value. Used in apic.c.
> > > + */
> > > +void __init wait_hpet_tick(void)
> > > +{
> > > +	unsigned int start_cmp_val, end_cmp_val;
> > > +
> > > +	start_cmp_val = hpet_readl(HPET_T0_CMP);
> > > +	do {
> > > +		end_cmp_val = hpet_readl(HPET_T0_CMP);
> > > +	} while (start_cmp_val == end_cmp_val);
> > > +}
> > > +#endif
> > > +
> > > +/*
> > > + * Check whether HPET was found by ACPI boot parse. If yes 
> > setup HPET 
> > > + * counter 0 for kernel base timer. 
> > > + */
> > > +int __init hpet_enable(void)
> > > +{
> > > +	unsigned int cfg, id;
> > > +	unsigned long tick_fsec_low, tick_fsec_high; /* tick in 
> > femto sec */
> > > +	unsigned long hpet_tick_rem;
> > > +
> > > +	if (boot_hpet_disable)
> > > +		return -1;
> > > +
> > > +	if (!hpet_address) {
> > > +		return -1;
> > > +	}
> > > +	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
> > > +	printk(KERN_INFO "HPET enabled at %#lx\n", hpet_address);
> > > +
> > > +	/*
> > > +	 * Read the period, compute tick and quotient.
> > > +	 */
> > > +	id = hpet_readl(HPET_ID);
> > > +
> > > +	/*
> > > +	 * We are checking for value '1' or more in number field. 
> > > +	 * So, we are OK with HPET_EMULATE_RTC part too, where we need
> > > +	 * to have atleast 2 timers.
> > > +	 */
> > > +	if (!(id & HPET_ID_NUMBER) ||
> > > +	    !(id & HPET_ID_LEGSUP))
> > > +		return -1;
> > > +
> > > +	if (((id & HPET_ID_VENDOR) >> HPET_ID_VENDOR_SHIFT) != 
> > > +				HPET_ID_VENDOR_8086)
> > > +		return -1;
> > > +
> > > +	hpet_period = hpet_readl(HPET_PERIOD);
> > > +	if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > 
> > HPET_MAX_PERIOD))
> > > +		return -1;
> > > +
> > > +	/*
> > > +	 * 64 bit math
> > > +	 * First changing tick into fsec
> > > +	 * Then 64 bit div to find number of hpet clk per tick
> > > +	 */
> > > +	ASM_MUL64_REG(tick_fsec_low, tick_fsec_high, 
> > > +			KERNEL_TICK_USEC, FSEC_TO_USEC);
> > > +	ASM_DIV64_REG(hpet_tick, hpet_tick_rem, 
> > > +			hpet_period, tick_fsec_low, tick_fsec_high);
> > > +
> > > +	if (hpet_tick_rem > (hpet_period >> 1))
> > > +		hpet_tick++; /* rounding the result */
> > > +
> > > +	/*
> > > +	 * Stop the timers and reset the main counter.
> > > +	 */
> > > +	cfg = hpet_readl(HPET_CFG);
> > > +	cfg &= ~HPET_CFG_ENABLE;
> > > +	hpet_writel(cfg, HPET_CFG);
> > > +	hpet_writel(0, HPET_COUNTER);
> > > +	hpet_writel(0, HPET_COUNTER + 4);
> > > +
> > > +	/*
> > > +	 * Set up timer 0, as periodic with first interrupt to 
> > happen at 
> > > +	 * hpet_tick, and period also hpet_tick.
> > > +	 */
> > > +	cfg = hpet_readl(HPET_T0_CFG);
> > > +	cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 
> > > +	       HPET_TN_SETVAL | HPET_TN_32BIT;
> > > +	hpet_writel(cfg, HPET_T0_CFG);
> > > +	hpet_writel(hpet_tick, HPET_T0_CMP);
> > > +
> > > +	/*
> > > + 	 * Go!
> > > + 	 */
> > > +	cfg = hpet_readl(HPET_CFG);
> > > +	cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY;
> > > +	hpet_writel(cfg, HPET_CFG);
> > > +
> > > +	use_hpet = 1;
> > > +#ifdef CONFIG_X86_LOCAL_APIC
> > > +	wait_timer_tick = wait_hpet_tick;
> > > +#endif
> > > +	return 0;
> > > +}
> > > +
> > > +int is_hpet_enabled(void)
> > > +{
> > > +	return use_hpet;
> > > +}
> > > +
> > > +static int __init hpet_setup(char* str)
> > > +{
> > > +	if (str) {
> > > +		if (!strncmp("disable", str, 7))
> > > +			boot_hpet_disable = 1;
> > > +	}
> > > +	return 1;
> > > +}
> > > +
> > > +__setup("hpet=", hpet_setup);
> > > +
> > > diff -purN linux-2.6.0-test1/include/asm-i386/apic.h 
> > linux-2.6.0-test1-hpet/include/asm-i386/apic.h
> > > --- linux-2.6.0-test1/include/asm-i386/apic.h	
> > 2003-07-13 20:38:53.000000000 -0700
> > > +++ linux-2.6.0-test1-hpet/include/asm-i386/apic.h	
> > 2003-08-13 11:34:37.000000000 -0700
> > > @@ -64,6 +64,8 @@ static inline void ack_APIC_irq(void)
> > >  	apic_write_around(APIC_EOI, 0);
> > >  }
> > >  
> > > +extern void (*wait_timer_tick)(void);
> > > +
> > >  extern int get_maxlvt(void);
> > >  extern void clear_local_APIC(void);
> > >  extern void connect_bsp_APIC (void);
> > > diff -purN linux-2.6.0-test1/include/asm-i386/fixmap.h 
> > linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h
> > > --- linux-2.6.0-test1/include/asm-i386/fixmap.h	
> > 2003-07-13 20:29:30.000000000 -0700
> > > +++ linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h	
> > 2003-08-14 13:10:31.000000000 -0700
> > > @@ -44,6 +44,9 @@
> > >  enum fixed_addresses {
> > >  	FIX_HOLE,
> > >  	FIX_VSYSCALL,
> > > +#ifdef CONFIG_HPET_TIMER
> > > +	FIX_HPET_BASE,
> > > +#endif
> > >  #ifdef CONFIG_X86_LOCAL_APIC
> > >  	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for 
> > SMP or not */
> > >  #endif
> > > diff -purN linux-2.6.0-test1/include/asm-i386/hpet.h 
> > linux-2.6.0-test1-hpet/include/asm-i386/hpet.h
> > > --- linux-2.6.0-test1/include/asm-i386/hpet.h	
> > 1969-12-31 16:00:00.000000000 -0800
> > > +++ linux-2.6.0-test1-hpet/include/asm-i386/hpet.h	
> > 2003-08-18 20:22:40.000000000 -0700
> > > @@ -0,0 +1,104 @@
> > > +
> > > +#ifndef _I386_HPET_H
> > > +#define _I386_HPET_H
> > > +
> > > +#ifdef CONFIG_HPET_TIMER
> > > +
> > > +#include <linux/errno.h>
> > > +#include <linux/module.h>
> > > +#include <linux/sched.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/param.h>
> > > +#include <linux/string.h>
> > > +#include <linux/mm.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/time.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/init.h>
> > > +#include <linux/smp.h>
> > > +
> > > +#include <asm/io.h>
> > > +#include <asm/smp.h>
> > > +#include <asm/irq.h>
> > > +#include <asm/msr.h>
> > > +#include <asm/delay.h>
> > > +#include <asm/mpspec.h>
> > > +#include <asm/uaccess.h>
> > > +#include <asm/processor.h>
> > > +
> > > +#include <linux/timex.h>
> > > +#include <linux/config.h>
> > > +
> > > +#include <asm/fixmap.h>
> > > +
> > > +/*
> > > + * Documentation on HPET can be found at:
> > > + *      http://www.intel.com/ial/home/sp/pcmmspec.htm
> > > + *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
> > > + */
> > > +
> > > +#define HPET_ID		0x000
> > > +#define HPET_PERIOD	0x004
> > > +#define HPET_CFG	0x010
> > > +#define HPET_STATUS	0x020
> > > +#define HPET_COUNTER	0x0f0
> > > +#define HPET_T0_CFG	0x100
> > > +#define HPET_T0_CMP	0x108
> > > +#define HPET_T0_ROUTE	0x110
> > > +#define HPET_T1_CFG	0x120
> > > +#define HPET_T1_CMP	0x128
> > > +#define HPET_T1_ROUTE	0x130
> > > +#define HPET_T2_CFG	0x140
> > > +#define HPET_T2_CMP	0x148
> > > +#define HPET_T2_ROUTE	0x150
> > > +
> > > +#define HPET_ID_VENDOR	0xffff0000
> > > +#define HPET_ID_LEGSUP	0x00008000
> > > +#define HPET_ID_NUMBER	0x00001f00
> > > +#define HPET_ID_REV	0x000000ff
> > > +
> > > +#define HPET_ID_VENDOR_SHIFT	16
> > > +#define HPET_ID_VENDOR_8086	0x8086
> > > +
> > > +#define HPET_CFG_ENABLE	0x001
> > > +#define HPET_CFG_LEGACY	0x002
> > > +
> > > +#define HPET_TN_ENABLE		0x004
> > > +#define HPET_TN_PERIODIC	0x008
> > > +#define HPET_TN_PERIODIC_CAP	0x010
> > > +#define HPET_TN_SETVAL		0x040
> > > +#define HPET_TN_32BIT		0x100
> > > +
> > > +/* Use our own asm for 64 bit multiply/divide */
> > > +#define ASM_MUL64_REG(eax_out,edx_out,reg_in,eax_in) 	
> > 		\
> > > +		__asm__ __volatile__("mull %2" 			
> > 	\
> > > +				:"=a" (eax_out), "=d" (edx_out) 
> > 	\
> > > +				:"r" (reg_in), "0" (eax_in))
> > > +
> > > +#define 
> > ASM_DIV64_REG(eax_out,edx_out,reg_in,eax_in,edx_in) 		\
> > > +		__asm__ __volatile__("divl %2" 			
> > 	\
> > > +				:"=a" (eax_out), "=d" (edx_out) 
> > 	\
> > > +				:"r" (reg_in), "0" (eax_in), 
> > "1" (edx_in))
> > > +
> > > +#define hpet_readl(a)		
> > readl(fix_to_virt(FIX_HPET_BASE) + a)
> > > +#define hpet_writel(d,a)	writel(d, 
> > fix_to_virt(FIX_HPET_BASE) + a)
> > > +
> > > +#define KERNEL_TICK_USEC 	(1000000UL/HZ)	/* tick value 
> > in microsec */
> > > +/* Max HPET Period is 10^8 femto sec as in HPET spec */
> > > +#define HPET_MAX_PERIOD (100000000UL)
> > > +/*
> > > + * Min HPET period is 10^5 femto sec just for safety. If 
> > it is less than this, 
> > > + * then 32 bit HPET counter wrapsaround in less than 0.5 sec. 
> > > + */
> > > +#define HPET_MIN_PERIOD (100000UL)
> > > +
> > > +extern unsigned long hpet_period;	/* fsecs / HPET clock */
> > > +extern unsigned long hpet_tick;  	/* hpet clks count per tick */
> > > +extern unsigned long hpet_address;	/* hpet memory map address */
> > > +extern unsigned long hpet_virt_address;	/* hpet kernel 
> > virtual address */
> > > +
> > > +extern int hpet_enable(void);
> > > +extern int is_hpet_enabled(void);
> > > +
> > > +#endif /* CONFIG_HPET_TIMER */
> > > +#endif /* _I386_HPET_H */
> > > diff -purN linux-2.6.0-test1/include/asm-i386/mc146818rtc.h 
> > linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h
> > > --- linux-2.6.0-test1/include/asm-i386/mc146818rtc.h	
> > 2003-07-13 20:36:37.000000000 -0700
> > > +++ linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h	
> > 2003-08-18 20:23:43.000000000 -0700
> > > @@ -24,6 +24,10 @@ 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/Documentation/kernel-parameters.txt 
> > linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt
> > > --- linux-2.6.0-test1/Documentation/kernel-parameters.txt   
> >     2003-07-13 20:39:36.000000000 -0700
> > > +++ 
> > linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt  
> > 2003-08-18 20:37:41.000000000 -0700
> > > @@ -212,7 +212,10 @@ running once the system is up.
> > > 			when calculating gettimeofday(). If 
> > specicified timesource
> > > 			is not avalible, it defaults to PIT. 
> > > 			Format: { pit | tsc | cyclone | ... }
> > > -
> > > +
> > > +	hpet=		[IA-32,HPET] option to disable HPET and use PIT.
> > > +			Format: disable
> > > +
> > > 	cm206=		[HW,CD]
> > > 			Format: { auto | [<io>,][<irq>] }
> > >  
> > > 
> > > 
> > 
> > 
> > 
> > -- 
> > Vojtech Pavlik
> > SuSE Labs, SuSE CR
> > 
> 

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

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

* RE: [PATCH][2.6][2/5]Support for HPET based timer
@ 2003-08-20  1:30 Pallipadi, Venkatesh
  0 siblings, 0 replies; 16+ messages in thread
From: Pallipadi, Venkatesh @ 2003-08-20  1:30 UTC (permalink / raw)
  To: Andi Kleen; +Cc: linux-kernel



The timer stuff in kernel is divided into two levels:
1) Base kernel timer, the one that generates periodic timer interrupt on
IRQ 0. There is also associated initializations like APIC timer
initialization in case of SMP,
which again depends on the timer hardware. As of now, kernel has only
have PIT 
in this level.

2) Various timers under arch/i386/kernel/timers, basically used during
gettimeofday().
we currently have different timers here like, timer_cyclone, timer_tsc
or timer_pit. 
This part has a clean infrastructure to add and/or prioritize different
timers.


With HPET support we are changing stuff at both the levels.
1) We use HPET hardware to generate HZ interrupts on IRQ 0. This is the
change that
is there in PATCH 2/5. Unfortunately, we cannot use the existing timers
infrastructure 
for this part. We tried to keep the changes here as less as possible.
But, still had to
do changes in apic.c as it was assuming PIT for base timer. And the
other change is in
time.c, wherein we have to calibrate/initialize HPET for base timer, in
place of PIT.
The reason we kept timer_hpet.c in arch/i386/kernel is because it has
more to do with
initialization of the base-kernel-timer, than the gettimeofday-timer.

2) The timers for gettimeofday will change too, with HPET. The timer
list will be 
something like, timer_cyclone, timer_hpet, timer_tsc. This change is
there in 
PATCH 3/5. This change uses the exisiting timer infrastructure in 
arch/i386/kernel/timers


Thanks,
-Venkatesh

> -----Original Message-----
> From: Andi Kleen [mailto:ak@muc.de] 
> Sent: Tuesday, August 19, 2003 3:41 PM
> To: Pallipadi, Venkatesh
> Cc: linux-kernel@vger.kernel.org
> Subject: Re: [PATCH][2.6][2/5]Support for HPET based timer
> 
> 
> "Pallipadi, Venkatesh" <venkatesh.pallipadi@intel.com> writes:
> 
> >  /*
> > + * Default initialization for 8254 timers. If we use other 
> timers like HPET,
> > + * we override this later 
> > + */
> > +void (*wait_timer_tick)(void) = wait_8254_wraparound;
> 
> It would be much cleaner to just poll the generic monotonic 
> time source here,
> not add more special cases.
> 
> > diff -purN linux-2.6.0-test1/arch/i386/kernel/time_hpet.c 
> linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c
> > --- linux-2.6.0-test1/arch/i386/kernel/time_hpet.c	
> 1969-12-31 16:00:00.000000000 -0800
> > +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c	
> 2003-08-18 20:22:06.000
> 000000 -0700
> 
> Shouldn't that be in arch/i386/kernel/timers/hpet.c ? 
> 
> Also I suspect it should be made an generic timer object there with
> a timer_ops structure. If some hook for that is missing it 
> could be added to 
> timer_ops and timers/timer.c
> 
> When there is already a generic framework to add new timers 
> it would be a shame
> not to use it.
> 
> -Andi
> 

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

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


Fixmap is for HPET memory map address access. As the timer
initialization happen 
early in the boot sequence (before vm initialization), we need to have
fixmap() 
and fix_to_virt() to access HPET memory map address.

Yes. Most of the code is generic, and can run on other platforms. The
only reason 
I have that check is because, I haven't got chance to test this patch on
other 
platforms.

Thanks,
-Venkatesh 

> -----Original Message-----
> From: Vojtech Pavlik [mailto:vojtech@suse.cz] 
> Sent: Tuesday, August 19, 2003 3:39 PM
> To: Pallipadi, Venkatesh
> Cc: linux-kernel@vger.kernel.org; torvalds@osdl.org; 
> Nakajima, Jun; Mallick, Asit K
> Subject: Re: [PATCH][2.6][2/5]Support for HPET based timer
> 
> 
> On Tue, Aug 19, 2003 at 12:20:02PM -0700, Pallipadi, Venkatesh wrote:
> 
> > 2/5 - hpet2.patch - All the changes required to use HPET in place
> >                     of PIT as the kernel base-timer at IRQ 0.
> 
> What are you using the fixmap() for? i386 doesn't have vsyscalls ...
> 
> Why are you limiting the HPET vendor ID to Intel? This code will
> happily run on other vendor hardware as well ...
> 
>  
> > diff -purN linux-2.6.0-test1/arch/i386/kernel/apic.c 
> linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c
> > --- linux-2.6.0-test1/arch/i386/kernel/apic.c	
> 2003-07-13 20:39:27.000000000 -0700
> > +++ linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c	
> 2003-08-13 11:36:24.000000000 -0700
> > @@ -34,6 +34,7 @@
> >  #include <asm/pgalloc.h>
> >  #include <asm/desc.h>
> >  #include <asm/arch_hooks.h>
> > +#include <asm/hpet.h>
> >  
> >  #include <mach_apic.h>
> >  
> > @@ -749,7 +750,8 @@ static unsigned int __init get_8254_time
> >  	return count;
> >  }
> >  
> > -void __init wait_8254_wraparound(void)
> > +/* next tick in 8254 can be caught by catching timer wraparound */
> > +static void __init wait_8254_wraparound(void)
> >  {
> >  	unsigned int curr_count, prev_count=~0;
> >  	int delta;
> > @@ -771,6 +773,12 @@ void __init wait_8254_wraparound(void)
> >  }
> >  
> >  /*
> > + * Default initialization for 8254 timers. If we use other 
> timers like HPET,
> > + * we override this later 
> > + */
> > +void (*wait_timer_tick)(void) = wait_8254_wraparound;
> > +
> > +/*
> >   * This function sets up the local APIC timer, with a timeout of
> >   * 'clocks' APIC bus clock. During calibration we actually call
> >   * this function twice on the boot CPU, once with a bogus timeout
> > @@ -811,7 +819,7 @@ static void setup_APIC_timer(unsigned in
> >  	/*
> >  	 * Wait for IRQ0's slice:
> >  	 */
> > -	wait_8254_wraparound();
> > +	wait_timer_tick();
> >  
> >  	__setup_APIC_LVTT(clocks);
> >  
> > @@ -854,7 +862,7 @@ int __init calibrate_APIC_clock(void)
> >  	 * (the current tick might have been already half done)
> >  	 */
> >  
> > -	wait_8254_wraparound();
> > +	wait_timer_tick();
> >  
> >  	/*
> >  	 * We wrapped around just now. Let's start:
> > @@ -867,7 +875,7 @@ int __init calibrate_APIC_clock(void)
> >  	 * Let's wait LOOPS wraprounds:
> >  	 */
> >  	for (i = 0; i < LOOPS; i++)
> > -		wait_8254_wraparound();
> > +		wait_timer_tick();
> >  
> >  	tt2 = apic_read(APIC_TMCCT);
> >  	if (cpu_has_tsc)
> > diff -purN linux-2.6.0-test1/arch/i386/kernel/time.c 
> linux-2.6.0-test1-hpet/arch/i386/kernel/time.c
> > --- linux-2.6.0-test1/arch/i386/kernel/time.c	
> 2003-07-13 20:34:29.000000000 -0700
> > +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time.c	
> 2003-08-18 12:36:25.000000000 -0700
> > @@ -60,6 +60,8 @@
> >  #include <linux/timex.h>
> >  #include <linux/config.h>
> >  
> > +#include <asm/hpet.h>
> > +
> >  #include <asm/arch_hooks.h>
> >  
> >  #include "io_ports.h"
> > @@ -298,6 +300,12 @@ void __init time_init(void)
> >  	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
> >  	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
> >  
> > +#ifdef CONFIG_HPET_TIMER
> > +	if (hpet_enable() >= 0) {
> > +		printk("Using HPET for base-timer\n");
> > +	}
> > +#endif
> > +
> >  	cur_timer = select_timer();
> >  	time_init_hook();
> >  }
> > diff -purN linux-2.6.0-test1/arch/i386/kernel/time_hpet.c 
> linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c
> > --- linux-2.6.0-test1/arch/i386/kernel/time_hpet.c	
> 1969-12-31 16:00:00.000000000 -0800
> > +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c	
> 2003-08-18 20:22:06.000000000 -0700
> > @@ -0,0 +1,153 @@
> > +/*
> > + *  linux/arch/i386/kernel/time_hpet.c
> > + *  This code largely copied from arch/x86_64/kernel/time.c
> > + *  See that file for credits.
> > + *
> > + *  2003-06-30    Venkatesh Pallipadi - Additional changes 
> for HPET support
> > + */
> > +
> > +#include <linux/errno.h>
> > +#include <linux/kernel.h>
> > +#include <linux/param.h>
> > +#include <linux/string.h>
> > +#include <linux/init.h>
> > +#include <linux/smp.h>
> > +
> > +#include <asm/timer.h>
> > +#include <asm/fixmap.h>
> > +#include <asm/apic.h>
> > +
> > +#include <linux/timex.h>
> > +#include <linux/config.h>
> > +
> > +#include <asm/hpet.h>
> > +
> > +unsigned long hpet_period;	/* fsecs / HPET clock */
> > +unsigned long hpet_tick;	/* hpet clks count per tick */
> > +unsigned long hpet_address;	/* hpet memory map address */
> > +
> > +static int use_hpet; 		/* can be used for 
> runtime check of hpet */
> > +static int boot_hpet_disable; 	/* boottime override 
> for HPET timer */
> > +
> > +#define FSEC_TO_USEC (1000000000UL)
> > +
> > +#ifdef CONFIG_X86_LOCAL_APIC
> > +/*
> > + * HPET counters dont wrap around on every tick. They just 
> change the 
> > + * comparator value and continue. Next tick can be caught 
> by checking 
> > + * for a change in the comparator value. Used in apic.c.
> > + */
> > +void __init wait_hpet_tick(void)
> > +{
> > +	unsigned int start_cmp_val, end_cmp_val;
> > +
> > +	start_cmp_val = hpet_readl(HPET_T0_CMP);
> > +	do {
> > +		end_cmp_val = hpet_readl(HPET_T0_CMP);
> > +	} while (start_cmp_val == end_cmp_val);
> > +}
> > +#endif
> > +
> > +/*
> > + * Check whether HPET was found by ACPI boot parse. If yes 
> setup HPET 
> > + * counter 0 for kernel base timer. 
> > + */
> > +int __init hpet_enable(void)
> > +{
> > +	unsigned int cfg, id;
> > +	unsigned long tick_fsec_low, tick_fsec_high; /* tick in 
> femto sec */
> > +	unsigned long hpet_tick_rem;
> > +
> > +	if (boot_hpet_disable)
> > +		return -1;
> > +
> > +	if (!hpet_address) {
> > +		return -1;
> > +	}
> > +	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
> > +	printk(KERN_INFO "HPET enabled at %#lx\n", hpet_address);
> > +
> > +	/*
> > +	 * Read the period, compute tick and quotient.
> > +	 */
> > +	id = hpet_readl(HPET_ID);
> > +
> > +	/*
> > +	 * We are checking for value '1' or more in number field. 
> > +	 * So, we are OK with HPET_EMULATE_RTC part too, where we need
> > +	 * to have atleast 2 timers.
> > +	 */
> > +	if (!(id & HPET_ID_NUMBER) ||
> > +	    !(id & HPET_ID_LEGSUP))
> > +		return -1;
> > +
> > +	if (((id & HPET_ID_VENDOR) >> HPET_ID_VENDOR_SHIFT) != 
> > +				HPET_ID_VENDOR_8086)
> > +		return -1;
> > +
> > +	hpet_period = hpet_readl(HPET_PERIOD);
> > +	if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > 
> HPET_MAX_PERIOD))
> > +		return -1;
> > +
> > +	/*
> > +	 * 64 bit math
> > +	 * First changing tick into fsec
> > +	 * Then 64 bit div to find number of hpet clk per tick
> > +	 */
> > +	ASM_MUL64_REG(tick_fsec_low, tick_fsec_high, 
> > +			KERNEL_TICK_USEC, FSEC_TO_USEC);
> > +	ASM_DIV64_REG(hpet_tick, hpet_tick_rem, 
> > +			hpet_period, tick_fsec_low, tick_fsec_high);
> > +
> > +	if (hpet_tick_rem > (hpet_period >> 1))
> > +		hpet_tick++; /* rounding the result */
> > +
> > +	/*
> > +	 * Stop the timers and reset the main counter.
> > +	 */
> > +	cfg = hpet_readl(HPET_CFG);
> > +	cfg &= ~HPET_CFG_ENABLE;
> > +	hpet_writel(cfg, HPET_CFG);
> > +	hpet_writel(0, HPET_COUNTER);
> > +	hpet_writel(0, HPET_COUNTER + 4);
> > +
> > +	/*
> > +	 * Set up timer 0, as periodic with first interrupt to 
> happen at 
> > +	 * hpet_tick, and period also hpet_tick.
> > +	 */
> > +	cfg = hpet_readl(HPET_T0_CFG);
> > +	cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 
> > +	       HPET_TN_SETVAL | HPET_TN_32BIT;
> > +	hpet_writel(cfg, HPET_T0_CFG);
> > +	hpet_writel(hpet_tick, HPET_T0_CMP);
> > +
> > +	/*
> > + 	 * Go!
> > + 	 */
> > +	cfg = hpet_readl(HPET_CFG);
> > +	cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY;
> > +	hpet_writel(cfg, HPET_CFG);
> > +
> > +	use_hpet = 1;
> > +#ifdef CONFIG_X86_LOCAL_APIC
> > +	wait_timer_tick = wait_hpet_tick;
> > +#endif
> > +	return 0;
> > +}
> > +
> > +int is_hpet_enabled(void)
> > +{
> > +	return use_hpet;
> > +}
> > +
> > +static int __init hpet_setup(char* str)
> > +{
> > +	if (str) {
> > +		if (!strncmp("disable", str, 7))
> > +			boot_hpet_disable = 1;
> > +	}
> > +	return 1;
> > +}
> > +
> > +__setup("hpet=", hpet_setup);
> > +
> > diff -purN linux-2.6.0-test1/include/asm-i386/apic.h 
> linux-2.6.0-test1-hpet/include/asm-i386/apic.h
> > --- linux-2.6.0-test1/include/asm-i386/apic.h	
> 2003-07-13 20:38:53.000000000 -0700
> > +++ linux-2.6.0-test1-hpet/include/asm-i386/apic.h	
> 2003-08-13 11:34:37.000000000 -0700
> > @@ -64,6 +64,8 @@ static inline void ack_APIC_irq(void)
> >  	apic_write_around(APIC_EOI, 0);
> >  }
> >  
> > +extern void (*wait_timer_tick)(void);
> > +
> >  extern int get_maxlvt(void);
> >  extern void clear_local_APIC(void);
> >  extern void connect_bsp_APIC (void);
> > diff -purN linux-2.6.0-test1/include/asm-i386/fixmap.h 
> linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h
> > --- linux-2.6.0-test1/include/asm-i386/fixmap.h	
> 2003-07-13 20:29:30.000000000 -0700
> > +++ linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h	
> 2003-08-14 13:10:31.000000000 -0700
> > @@ -44,6 +44,9 @@
> >  enum fixed_addresses {
> >  	FIX_HOLE,
> >  	FIX_VSYSCALL,
> > +#ifdef CONFIG_HPET_TIMER
> > +	FIX_HPET_BASE,
> > +#endif
> >  #ifdef CONFIG_X86_LOCAL_APIC
> >  	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for 
> SMP or not */
> >  #endif
> > diff -purN linux-2.6.0-test1/include/asm-i386/hpet.h 
> linux-2.6.0-test1-hpet/include/asm-i386/hpet.h
> > --- linux-2.6.0-test1/include/asm-i386/hpet.h	
> 1969-12-31 16:00:00.000000000 -0800
> > +++ linux-2.6.0-test1-hpet/include/asm-i386/hpet.h	
> 2003-08-18 20:22:40.000000000 -0700
> > @@ -0,0 +1,104 @@
> > +
> > +#ifndef _I386_HPET_H
> > +#define _I386_HPET_H
> > +
> > +#ifdef CONFIG_HPET_TIMER
> > +
> > +#include <linux/errno.h>
> > +#include <linux/module.h>
> > +#include <linux/sched.h>
> > +#include <linux/kernel.h>
> > +#include <linux/param.h>
> > +#include <linux/string.h>
> > +#include <linux/mm.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/time.h>
> > +#include <linux/delay.h>
> > +#include <linux/init.h>
> > +#include <linux/smp.h>
> > +
> > +#include <asm/io.h>
> > +#include <asm/smp.h>
> > +#include <asm/irq.h>
> > +#include <asm/msr.h>
> > +#include <asm/delay.h>
> > +#include <asm/mpspec.h>
> > +#include <asm/uaccess.h>
> > +#include <asm/processor.h>
> > +
> > +#include <linux/timex.h>
> > +#include <linux/config.h>
> > +
> > +#include <asm/fixmap.h>
> > +
> > +/*
> > + * Documentation on HPET can be found at:
> > + *      http://www.intel.com/ial/home/sp/pcmmspec.htm
> > + *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
> > + */
> > +
> > +#define HPET_ID		0x000
> > +#define HPET_PERIOD	0x004
> > +#define HPET_CFG	0x010
> > +#define HPET_STATUS	0x020
> > +#define HPET_COUNTER	0x0f0
> > +#define HPET_T0_CFG	0x100
> > +#define HPET_T0_CMP	0x108
> > +#define HPET_T0_ROUTE	0x110
> > +#define HPET_T1_CFG	0x120
> > +#define HPET_T1_CMP	0x128
> > +#define HPET_T1_ROUTE	0x130
> > +#define HPET_T2_CFG	0x140
> > +#define HPET_T2_CMP	0x148
> > +#define HPET_T2_ROUTE	0x150
> > +
> > +#define HPET_ID_VENDOR	0xffff0000
> > +#define HPET_ID_LEGSUP	0x00008000
> > +#define HPET_ID_NUMBER	0x00001f00
> > +#define HPET_ID_REV	0x000000ff
> > +
> > +#define HPET_ID_VENDOR_SHIFT	16
> > +#define HPET_ID_VENDOR_8086	0x8086
> > +
> > +#define HPET_CFG_ENABLE	0x001
> > +#define HPET_CFG_LEGACY	0x002
> > +
> > +#define HPET_TN_ENABLE		0x004
> > +#define HPET_TN_PERIODIC	0x008
> > +#define HPET_TN_PERIODIC_CAP	0x010
> > +#define HPET_TN_SETVAL		0x040
> > +#define HPET_TN_32BIT		0x100
> > +
> > +/* Use our own asm for 64 bit multiply/divide */
> > +#define ASM_MUL64_REG(eax_out,edx_out,reg_in,eax_in) 	
> 		\
> > +		__asm__ __volatile__("mull %2" 			
> 	\
> > +				:"=a" (eax_out), "=d" (edx_out) 
> 	\
> > +				:"r" (reg_in), "0" (eax_in))
> > +
> > +#define 
> ASM_DIV64_REG(eax_out,edx_out,reg_in,eax_in,edx_in) 		\
> > +		__asm__ __volatile__("divl %2" 			
> 	\
> > +				:"=a" (eax_out), "=d" (edx_out) 
> 	\
> > +				:"r" (reg_in), "0" (eax_in), 
> "1" (edx_in))
> > +
> > +#define hpet_readl(a)		
> readl(fix_to_virt(FIX_HPET_BASE) + a)
> > +#define hpet_writel(d,a)	writel(d, 
> fix_to_virt(FIX_HPET_BASE) + a)
> > +
> > +#define KERNEL_TICK_USEC 	(1000000UL/HZ)	/* tick value 
> in microsec */
> > +/* Max HPET Period is 10^8 femto sec as in HPET spec */
> > +#define HPET_MAX_PERIOD (100000000UL)
> > +/*
> > + * Min HPET period is 10^5 femto sec just for safety. If 
> it is less than this, 
> > + * then 32 bit HPET counter wrapsaround in less than 0.5 sec. 
> > + */
> > +#define HPET_MIN_PERIOD (100000UL)
> > +
> > +extern unsigned long hpet_period;	/* fsecs / HPET clock */
> > +extern unsigned long hpet_tick;  	/* hpet clks count per tick */
> > +extern unsigned long hpet_address;	/* hpet memory map address */
> > +extern unsigned long hpet_virt_address;	/* hpet kernel 
> virtual address */
> > +
> > +extern int hpet_enable(void);
> > +extern int is_hpet_enabled(void);
> > +
> > +#endif /* CONFIG_HPET_TIMER */
> > +#endif /* _I386_HPET_H */
> > diff -purN linux-2.6.0-test1/include/asm-i386/mc146818rtc.h 
> linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h
> > --- linux-2.6.0-test1/include/asm-i386/mc146818rtc.h	
> 2003-07-13 20:36:37.000000000 -0700
> > +++ linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h	
> 2003-08-18 20:23:43.000000000 -0700
> > @@ -24,6 +24,10 @@ 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/Documentation/kernel-parameters.txt 
> linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt
> > --- linux-2.6.0-test1/Documentation/kernel-parameters.txt   
>     2003-07-13 20:39:36.000000000 -0700
> > +++ 
> linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt  
> 2003-08-18 20:37:41.000000000 -0700
> > @@ -212,7 +212,10 @@ running once the system is up.
> > 			when calculating gettimeofday(). If 
> specicified timesource
> > 			is not avalible, it defaults to PIT. 
> > 			Format: { pit | tsc | cyclone | ... }
> > -
> > +
> > +	hpet=		[IA-32,HPET] option to disable HPET and use PIT.
> > +			Format: disable
> > +
> > 	cm206=		[HW,CD]
> > 			Format: { auto | [<io>,][<irq>] }
> >  
> > 
> > 
> 
> 
> 
> -- 
> Vojtech Pavlik
> SuSE Labs, SuSE CR
> 

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

* Re: [PATCH][2.6][2/5]Support for HPET based timer
       [not found] <mmZK.Q4.11@gated-at.bofh.it>
@ 2003-08-19 22:41 ` Andi Kleen
  0 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2003-08-19 22:41 UTC (permalink / raw)
  To: Pallipadi, Venkatesh; +Cc: linux-kernel

"Pallipadi, Venkatesh" <venkatesh.pallipadi@intel.com> writes:

>  /*
> + * Default initialization for 8254 timers. If we use other timers like HPET,
> + * we override this later 
> + */
> +void (*wait_timer_tick)(void) = wait_8254_wraparound;

It would be much cleaner to just poll the generic monotonic time source here,
not add more special cases.

> diff -purN linux-2.6.0-test1/arch/i386/kernel/time_hpet.c linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c
> --- linux-2.6.0-test1/arch/i386/kernel/time_hpet.c	1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c	2003-08-18 20:22:06.000
000000 -0700

Shouldn't that be in arch/i386/kernel/timers/hpet.c ? 

Also I suspect it should be made an generic timer object there with
a timer_ops structure. If some hook for that is missing it could be added to 
timer_ops and timers/timer.c

When there is already a generic framework to add new timers it would be a shame
not to use it.

-Andi

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

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

On Tue, Aug 19, 2003 at 12:20:02PM -0700, Pallipadi, Venkatesh wrote:

> 2/5 - hpet2.patch - All the changes required to use HPET in place
>                     of PIT as the kernel base-timer at IRQ 0.

What are you using the fixmap() for? i386 doesn't have vsyscalls ...

Why are you limiting the HPET vendor ID to Intel? This code will
happily run on other vendor hardware as well ...

 
> diff -purN linux-2.6.0-test1/arch/i386/kernel/apic.c linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c
> --- linux-2.6.0-test1/arch/i386/kernel/apic.c	2003-07-13 20:39:27.000000000 -0700
> +++ linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c	2003-08-13 11:36:24.000000000 -0700
> @@ -34,6 +34,7 @@
>  #include <asm/pgalloc.h>
>  #include <asm/desc.h>
>  #include <asm/arch_hooks.h>
> +#include <asm/hpet.h>
>  
>  #include <mach_apic.h>
>  
> @@ -749,7 +750,8 @@ static unsigned int __init get_8254_time
>  	return count;
>  }
>  
> -void __init wait_8254_wraparound(void)
> +/* next tick in 8254 can be caught by catching timer wraparound */
> +static void __init wait_8254_wraparound(void)
>  {
>  	unsigned int curr_count, prev_count=~0;
>  	int delta;
> @@ -771,6 +773,12 @@ void __init wait_8254_wraparound(void)
>  }
>  
>  /*
> + * Default initialization for 8254 timers. If we use other timers like HPET,
> + * we override this later 
> + */
> +void (*wait_timer_tick)(void) = wait_8254_wraparound;
> +
> +/*
>   * This function sets up the local APIC timer, with a timeout of
>   * 'clocks' APIC bus clock. During calibration we actually call
>   * this function twice on the boot CPU, once with a bogus timeout
> @@ -811,7 +819,7 @@ static void setup_APIC_timer(unsigned in
>  	/*
>  	 * Wait for IRQ0's slice:
>  	 */
> -	wait_8254_wraparound();
> +	wait_timer_tick();
>  
>  	__setup_APIC_LVTT(clocks);
>  
> @@ -854,7 +862,7 @@ int __init calibrate_APIC_clock(void)
>  	 * (the current tick might have been already half done)
>  	 */
>  
> -	wait_8254_wraparound();
> +	wait_timer_tick();
>  
>  	/*
>  	 * We wrapped around just now. Let's start:
> @@ -867,7 +875,7 @@ int __init calibrate_APIC_clock(void)
>  	 * Let's wait LOOPS wraprounds:
>  	 */
>  	for (i = 0; i < LOOPS; i++)
> -		wait_8254_wraparound();
> +		wait_timer_tick();
>  
>  	tt2 = apic_read(APIC_TMCCT);
>  	if (cpu_has_tsc)
> diff -purN linux-2.6.0-test1/arch/i386/kernel/time.c linux-2.6.0-test1-hpet/arch/i386/kernel/time.c
> --- linux-2.6.0-test1/arch/i386/kernel/time.c	2003-07-13 20:34:29.000000000 -0700
> +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time.c	2003-08-18 12:36:25.000000000 -0700
> @@ -60,6 +60,8 @@
>  #include <linux/timex.h>
>  #include <linux/config.h>
>  
> +#include <asm/hpet.h>
> +
>  #include <asm/arch_hooks.h>
>  
>  #include "io_ports.h"
> @@ -298,6 +300,12 @@ void __init time_init(void)
>  	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
>  	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
>  
> +#ifdef CONFIG_HPET_TIMER
> +	if (hpet_enable() >= 0) {
> +		printk("Using HPET for base-timer\n");
> +	}
> +#endif
> +
>  	cur_timer = select_timer();
>  	time_init_hook();
>  }
> diff -purN linux-2.6.0-test1/arch/i386/kernel/time_hpet.c linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c
> --- linux-2.6.0-test1/arch/i386/kernel/time_hpet.c	1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c	2003-08-18 20:22:06.000000000 -0700
> @@ -0,0 +1,153 @@
> +/*
> + *  linux/arch/i386/kernel/time_hpet.c
> + *  This code largely copied from arch/x86_64/kernel/time.c
> + *  See that file for credits.
> + *
> + *  2003-06-30    Venkatesh Pallipadi - Additional changes for HPET support
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/param.h>
> +#include <linux/string.h>
> +#include <linux/init.h>
> +#include <linux/smp.h>
> +
> +#include <asm/timer.h>
> +#include <asm/fixmap.h>
> +#include <asm/apic.h>
> +
> +#include <linux/timex.h>
> +#include <linux/config.h>
> +
> +#include <asm/hpet.h>
> +
> +unsigned long hpet_period;	/* fsecs / HPET clock */
> +unsigned long hpet_tick;	/* hpet clks count per tick */
> +unsigned long hpet_address;	/* hpet memory map address */
> +
> +static int use_hpet; 		/* can be used for runtime check of hpet */
> +static int boot_hpet_disable; 	/* boottime override for HPET timer */
> +
> +#define FSEC_TO_USEC (1000000000UL)
> +
> +#ifdef CONFIG_X86_LOCAL_APIC
> +/*
> + * HPET counters dont wrap around on every tick. They just change the 
> + * comparator value and continue. Next tick can be caught by checking 
> + * for a change in the comparator value. Used in apic.c.
> + */
> +void __init wait_hpet_tick(void)
> +{
> +	unsigned int start_cmp_val, end_cmp_val;
> +
> +	start_cmp_val = hpet_readl(HPET_T0_CMP);
> +	do {
> +		end_cmp_val = hpet_readl(HPET_T0_CMP);
> +	} while (start_cmp_val == end_cmp_val);
> +}
> +#endif
> +
> +/*
> + * Check whether HPET was found by ACPI boot parse. If yes setup HPET 
> + * counter 0 for kernel base timer. 
> + */
> +int __init hpet_enable(void)
> +{
> +	unsigned int cfg, id;
> +	unsigned long tick_fsec_low, tick_fsec_high; /* tick in femto sec */
> +	unsigned long hpet_tick_rem;
> +
> +	if (boot_hpet_disable)
> +		return -1;
> +
> +	if (!hpet_address) {
> +		return -1;
> +	}
> +	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
> +	printk(KERN_INFO "HPET enabled at %#lx\n", hpet_address);
> +
> +	/*
> +	 * Read the period, compute tick and quotient.
> +	 */
> +	id = hpet_readl(HPET_ID);
> +
> +	/*
> +	 * We are checking for value '1' or more in number field. 
> +	 * So, we are OK with HPET_EMULATE_RTC part too, where we need
> +	 * to have atleast 2 timers.
> +	 */
> +	if (!(id & HPET_ID_NUMBER) ||
> +	    !(id & HPET_ID_LEGSUP))
> +		return -1;
> +
> +	if (((id & HPET_ID_VENDOR) >> HPET_ID_VENDOR_SHIFT) != 
> +				HPET_ID_VENDOR_8086)
> +		return -1;
> +
> +	hpet_period = hpet_readl(HPET_PERIOD);
> +	if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD))
> +		return -1;
> +
> +	/*
> +	 * 64 bit math
> +	 * First changing tick into fsec
> +	 * Then 64 bit div to find number of hpet clk per tick
> +	 */
> +	ASM_MUL64_REG(tick_fsec_low, tick_fsec_high, 
> +			KERNEL_TICK_USEC, FSEC_TO_USEC);
> +	ASM_DIV64_REG(hpet_tick, hpet_tick_rem, 
> +			hpet_period, tick_fsec_low, tick_fsec_high);
> +
> +	if (hpet_tick_rem > (hpet_period >> 1))
> +		hpet_tick++; /* rounding the result */
> +
> +	/*
> +	 * Stop the timers and reset the main counter.
> +	 */
> +	cfg = hpet_readl(HPET_CFG);
> +	cfg &= ~HPET_CFG_ENABLE;
> +	hpet_writel(cfg, HPET_CFG);
> +	hpet_writel(0, HPET_COUNTER);
> +	hpet_writel(0, HPET_COUNTER + 4);
> +
> +	/*
> +	 * Set up timer 0, as periodic with first interrupt to happen at 
> +	 * hpet_tick, and period also hpet_tick.
> +	 */
> +	cfg = hpet_readl(HPET_T0_CFG);
> +	cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 
> +	       HPET_TN_SETVAL | HPET_TN_32BIT;
> +	hpet_writel(cfg, HPET_T0_CFG);
> +	hpet_writel(hpet_tick, HPET_T0_CMP);
> +
> +	/*
> + 	 * Go!
> + 	 */
> +	cfg = hpet_readl(HPET_CFG);
> +	cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY;
> +	hpet_writel(cfg, HPET_CFG);
> +
> +	use_hpet = 1;
> +#ifdef CONFIG_X86_LOCAL_APIC
> +	wait_timer_tick = wait_hpet_tick;
> +#endif
> +	return 0;
> +}
> +
> +int is_hpet_enabled(void)
> +{
> +	return use_hpet;
> +}
> +
> +static int __init hpet_setup(char* str)
> +{
> +	if (str) {
> +		if (!strncmp("disable", str, 7))
> +			boot_hpet_disable = 1;
> +	}
> +	return 1;
> +}
> +
> +__setup("hpet=", hpet_setup);
> +
> diff -purN linux-2.6.0-test1/include/asm-i386/apic.h linux-2.6.0-test1-hpet/include/asm-i386/apic.h
> --- linux-2.6.0-test1/include/asm-i386/apic.h	2003-07-13 20:38:53.000000000 -0700
> +++ linux-2.6.0-test1-hpet/include/asm-i386/apic.h	2003-08-13 11:34:37.000000000 -0700
> @@ -64,6 +64,8 @@ static inline void ack_APIC_irq(void)
>  	apic_write_around(APIC_EOI, 0);
>  }
>  
> +extern void (*wait_timer_tick)(void);
> +
>  extern int get_maxlvt(void);
>  extern void clear_local_APIC(void);
>  extern void connect_bsp_APIC (void);
> diff -purN linux-2.6.0-test1/include/asm-i386/fixmap.h linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h
> --- linux-2.6.0-test1/include/asm-i386/fixmap.h	2003-07-13 20:29:30.000000000 -0700
> +++ linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h	2003-08-14 13:10:31.000000000 -0700
> @@ -44,6 +44,9 @@
>  enum fixed_addresses {
>  	FIX_HOLE,
>  	FIX_VSYSCALL,
> +#ifdef CONFIG_HPET_TIMER
> +	FIX_HPET_BASE,
> +#endif
>  #ifdef CONFIG_X86_LOCAL_APIC
>  	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
>  #endif
> diff -purN linux-2.6.0-test1/include/asm-i386/hpet.h linux-2.6.0-test1-hpet/include/asm-i386/hpet.h
> --- linux-2.6.0-test1/include/asm-i386/hpet.h	1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.0-test1-hpet/include/asm-i386/hpet.h	2003-08-18 20:22:40.000000000 -0700
> @@ -0,0 +1,104 @@
> +
> +#ifndef _I386_HPET_H
> +#define _I386_HPET_H
> +
> +#ifdef CONFIG_HPET_TIMER
> +
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/param.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/interrupt.h>
> +#include <linux/time.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/smp.h>
> +
> +#include <asm/io.h>
> +#include <asm/smp.h>
> +#include <asm/irq.h>
> +#include <asm/msr.h>
> +#include <asm/delay.h>
> +#include <asm/mpspec.h>
> +#include <asm/uaccess.h>
> +#include <asm/processor.h>
> +
> +#include <linux/timex.h>
> +#include <linux/config.h>
> +
> +#include <asm/fixmap.h>
> +
> +/*
> + * Documentation on HPET can be found at:
> + *      http://www.intel.com/ial/home/sp/pcmmspec.htm
> + *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
> + */
> +
> +#define HPET_ID		0x000
> +#define HPET_PERIOD	0x004
> +#define HPET_CFG	0x010
> +#define HPET_STATUS	0x020
> +#define HPET_COUNTER	0x0f0
> +#define HPET_T0_CFG	0x100
> +#define HPET_T0_CMP	0x108
> +#define HPET_T0_ROUTE	0x110
> +#define HPET_T1_CFG	0x120
> +#define HPET_T1_CMP	0x128
> +#define HPET_T1_ROUTE	0x130
> +#define HPET_T2_CFG	0x140
> +#define HPET_T2_CMP	0x148
> +#define HPET_T2_ROUTE	0x150
> +
> +#define HPET_ID_VENDOR	0xffff0000
> +#define HPET_ID_LEGSUP	0x00008000
> +#define HPET_ID_NUMBER	0x00001f00
> +#define HPET_ID_REV	0x000000ff
> +
> +#define HPET_ID_VENDOR_SHIFT	16
> +#define HPET_ID_VENDOR_8086	0x8086
> +
> +#define HPET_CFG_ENABLE	0x001
> +#define HPET_CFG_LEGACY	0x002
> +
> +#define HPET_TN_ENABLE		0x004
> +#define HPET_TN_PERIODIC	0x008
> +#define HPET_TN_PERIODIC_CAP	0x010
> +#define HPET_TN_SETVAL		0x040
> +#define HPET_TN_32BIT		0x100
> +
> +/* Use our own asm for 64 bit multiply/divide */
> +#define ASM_MUL64_REG(eax_out,edx_out,reg_in,eax_in) 			\
> +		__asm__ __volatile__("mull %2" 				\
> +				:"=a" (eax_out), "=d" (edx_out) 	\
> +				:"r" (reg_in), "0" (eax_in))
> +
> +#define ASM_DIV64_REG(eax_out,edx_out,reg_in,eax_in,edx_in) 		\
> +		__asm__ __volatile__("divl %2" 				\
> +				:"=a" (eax_out), "=d" (edx_out) 	\
> +				:"r" (reg_in), "0" (eax_in), "1" (edx_in))
> +
> +#define hpet_readl(a)		readl(fix_to_virt(FIX_HPET_BASE) + a)
> +#define hpet_writel(d,a)	writel(d, fix_to_virt(FIX_HPET_BASE) + a)
> +
> +#define KERNEL_TICK_USEC 	(1000000UL/HZ)	/* tick value in microsec */
> +/* Max HPET Period is 10^8 femto sec as in HPET spec */
> +#define HPET_MAX_PERIOD (100000000UL)
> +/*
> + * Min HPET period is 10^5 femto sec just for safety. If it is less than this, 
> + * then 32 bit HPET counter wrapsaround in less than 0.5 sec. 
> + */
> +#define HPET_MIN_PERIOD (100000UL)
> +
> +extern unsigned long hpet_period;	/* fsecs / HPET clock */
> +extern unsigned long hpet_tick;  	/* hpet clks count per tick */
> +extern unsigned long hpet_address;	/* hpet memory map address */
> +extern unsigned long hpet_virt_address;	/* hpet kernel virtual address */
> +
> +extern int hpet_enable(void);
> +extern int is_hpet_enabled(void);
> +
> +#endif /* CONFIG_HPET_TIMER */
> +#endif /* _I386_HPET_H */
> diff -purN linux-2.6.0-test1/include/asm-i386/mc146818rtc.h linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h
> --- linux-2.6.0-test1/include/asm-i386/mc146818rtc.h	2003-07-13 20:36:37.000000000 -0700
> +++ linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h	2003-08-18 20:23:43.000000000 -0700
> @@ -24,6 +24,10 @@ 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/Documentation/kernel-parameters.txt linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt
> --- linux-2.6.0-test1/Documentation/kernel-parameters.txt       2003-07-13 20:39:36.000000000 -0700
> +++ linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt  2003-08-18 20:37:41.000000000 -0700
> @@ -212,7 +212,10 @@ running once the system is up.
> 			when calculating gettimeofday(). If specicified timesource
> 			is not avalible, it defaults to PIT. 
> 			Format: { pit | tsc | cyclone | ... }
> -
> +
> +	hpet=		[IA-32,HPET] option to disable HPET and use PIT.
> +			Format: disable
> +
> 	cm206=		[HW,CD]
> 			Format: { auto | [<io>,][<irq>] }
>  
> 
> 



-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

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

* [PATCH][2.6][2/5]Support for HPET based timer
@ 2003-08-19 19:20 Pallipadi, Venkatesh
  2003-08-19 22:39 ` Vojtech Pavlik
  0 siblings, 1 reply; 16+ 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: 12574 bytes --]

2/5 - hpet2.patch - All the changes required to use HPET in place
                    of PIT as the kernel base-timer at IRQ 0.




diff -purN linux-2.6.0-test1/arch/i386/kernel/apic.c linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c
--- linux-2.6.0-test1/arch/i386/kernel/apic.c	2003-07-13 20:39:27.000000000 -0700
+++ linux-2.6.0-test1-hpet/arch/i386/kernel/apic.c	2003-08-13 11:36:24.000000000 -0700
@@ -34,6 +34,7 @@
 #include <asm/pgalloc.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
+#include <asm/hpet.h>
 
 #include <mach_apic.h>
 
@@ -749,7 +750,8 @@ static unsigned int __init get_8254_time
 	return count;
 }
 
-void __init wait_8254_wraparound(void)
+/* next tick in 8254 can be caught by catching timer wraparound */
+static void __init wait_8254_wraparound(void)
 {
 	unsigned int curr_count, prev_count=~0;
 	int delta;
@@ -771,6 +773,12 @@ void __init wait_8254_wraparound(void)
 }
 
 /*
+ * Default initialization for 8254 timers. If we use other timers like HPET,
+ * we override this later 
+ */
+void (*wait_timer_tick)(void) = wait_8254_wraparound;
+
+/*
  * This function sets up the local APIC timer, with a timeout of
  * 'clocks' APIC bus clock. During calibration we actually call
  * this function twice on the boot CPU, once with a bogus timeout
@@ -811,7 +819,7 @@ static void setup_APIC_timer(unsigned in
 	/*
 	 * Wait for IRQ0's slice:
 	 */
-	wait_8254_wraparound();
+	wait_timer_tick();
 
 	__setup_APIC_LVTT(clocks);
 
@@ -854,7 +862,7 @@ int __init calibrate_APIC_clock(void)
 	 * (the current tick might have been already half done)
 	 */
 
-	wait_8254_wraparound();
+	wait_timer_tick();
 
 	/*
 	 * We wrapped around just now. Let's start:
@@ -867,7 +875,7 @@ int __init calibrate_APIC_clock(void)
 	 * Let's wait LOOPS wraprounds:
 	 */
 	for (i = 0; i < LOOPS; i++)
-		wait_8254_wraparound();
+		wait_timer_tick();
 
 	tt2 = apic_read(APIC_TMCCT);
 	if (cpu_has_tsc)
diff -purN linux-2.6.0-test1/arch/i386/kernel/time.c linux-2.6.0-test1-hpet/arch/i386/kernel/time.c
--- linux-2.6.0-test1/arch/i386/kernel/time.c	2003-07-13 20:34:29.000000000 -0700
+++ linux-2.6.0-test1-hpet/arch/i386/kernel/time.c	2003-08-18 12:36:25.000000000 -0700
@@ -60,6 +60,8 @@
 #include <linux/timex.h>
 #include <linux/config.h>
 
+#include <asm/hpet.h>
+
 #include <asm/arch_hooks.h>
 
 #include "io_ports.h"
@@ -298,6 +300,12 @@ void __init time_init(void)
 	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
 	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
 
+#ifdef CONFIG_HPET_TIMER
+	if (hpet_enable() >= 0) {
+		printk("Using HPET for base-timer\n");
+	}
+#endif
+
 	cur_timer = select_timer();
 	time_init_hook();
 }
diff -purN linux-2.6.0-test1/arch/i386/kernel/time_hpet.c linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c
--- linux-2.6.0-test1/arch/i386/kernel/time_hpet.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.0-test1-hpet/arch/i386/kernel/time_hpet.c	2003-08-18 20:22:06.000000000 -0700
@@ -0,0 +1,153 @@
+/*
+ *  linux/arch/i386/kernel/time_hpet.c
+ *  This code largely copied from arch/x86_64/kernel/time.c
+ *  See that file for credits.
+ *
+ *  2003-06-30    Venkatesh Pallipadi - Additional changes for HPET support
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/timer.h>
+#include <asm/fixmap.h>
+#include <asm/apic.h>
+
+#include <linux/timex.h>
+#include <linux/config.h>
+
+#include <asm/hpet.h>
+
+unsigned long hpet_period;	/* fsecs / HPET clock */
+unsigned long hpet_tick;	/* hpet clks count per tick */
+unsigned long hpet_address;	/* hpet memory map address */
+
+static int use_hpet; 		/* can be used for runtime check of hpet */
+static int boot_hpet_disable; 	/* boottime override for HPET timer */
+
+#define FSEC_TO_USEC (1000000000UL)
+
+#ifdef CONFIG_X86_LOCAL_APIC
+/*
+ * HPET counters dont wrap around on every tick. They just change the 
+ * comparator value and continue. Next tick can be caught by checking 
+ * for a change in the comparator value. Used in apic.c.
+ */
+void __init wait_hpet_tick(void)
+{
+	unsigned int start_cmp_val, end_cmp_val;
+
+	start_cmp_val = hpet_readl(HPET_T0_CMP);
+	do {
+		end_cmp_val = hpet_readl(HPET_T0_CMP);
+	} while (start_cmp_val == end_cmp_val);
+}
+#endif
+
+/*
+ * Check whether HPET was found by ACPI boot parse. If yes setup HPET 
+ * counter 0 for kernel base timer. 
+ */
+int __init hpet_enable(void)
+{
+	unsigned int cfg, id;
+	unsigned long tick_fsec_low, tick_fsec_high; /* tick in femto sec */
+	unsigned long hpet_tick_rem;
+
+	if (boot_hpet_disable)
+		return -1;
+
+	if (!hpet_address) {
+		return -1;
+	}
+	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
+	printk(KERN_INFO "HPET enabled at %#lx\n", hpet_address);
+
+	/*
+	 * Read the period, compute tick and quotient.
+	 */
+	id = hpet_readl(HPET_ID);
+
+	/*
+	 * We are checking for value '1' or more in number field. 
+	 * So, we are OK with HPET_EMULATE_RTC part too, where we need
+	 * to have atleast 2 timers.
+	 */
+	if (!(id & HPET_ID_NUMBER) ||
+	    !(id & HPET_ID_LEGSUP))
+		return -1;
+
+	if (((id & HPET_ID_VENDOR) >> HPET_ID_VENDOR_SHIFT) != 
+				HPET_ID_VENDOR_8086)
+		return -1;
+
+	hpet_period = hpet_readl(HPET_PERIOD);
+	if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD))
+		return -1;
+
+	/*
+	 * 64 bit math
+	 * First changing tick into fsec
+	 * Then 64 bit div to find number of hpet clk per tick
+	 */
+	ASM_MUL64_REG(tick_fsec_low, tick_fsec_high, 
+			KERNEL_TICK_USEC, FSEC_TO_USEC);
+	ASM_DIV64_REG(hpet_tick, hpet_tick_rem, 
+			hpet_period, tick_fsec_low, tick_fsec_high);
+
+	if (hpet_tick_rem > (hpet_period >> 1))
+		hpet_tick++; /* rounding the result */
+
+	/*
+	 * Stop the timers and reset the main counter.
+	 */
+	cfg = hpet_readl(HPET_CFG);
+	cfg &= ~HPET_CFG_ENABLE;
+	hpet_writel(cfg, HPET_CFG);
+	hpet_writel(0, HPET_COUNTER);
+	hpet_writel(0, HPET_COUNTER + 4);
+
+	/*
+	 * Set up timer 0, as periodic with first interrupt to happen at 
+	 * hpet_tick, and period also hpet_tick.
+	 */
+	cfg = hpet_readl(HPET_T0_CFG);
+	cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 
+	       HPET_TN_SETVAL | HPET_TN_32BIT;
+	hpet_writel(cfg, HPET_T0_CFG);
+	hpet_writel(hpet_tick, HPET_T0_CMP);
+
+	/*
+ 	 * Go!
+ 	 */
+	cfg = hpet_readl(HPET_CFG);
+	cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY;
+	hpet_writel(cfg, HPET_CFG);
+
+	use_hpet = 1;
+#ifdef CONFIG_X86_LOCAL_APIC
+	wait_timer_tick = wait_hpet_tick;
+#endif
+	return 0;
+}
+
+int is_hpet_enabled(void)
+{
+	return use_hpet;
+}
+
+static int __init hpet_setup(char* str)
+{
+	if (str) {
+		if (!strncmp("disable", str, 7))
+			boot_hpet_disable = 1;
+	}
+	return 1;
+}
+
+__setup("hpet=", hpet_setup);
+
diff -purN linux-2.6.0-test1/include/asm-i386/apic.h linux-2.6.0-test1-hpet/include/asm-i386/apic.h
--- linux-2.6.0-test1/include/asm-i386/apic.h	2003-07-13 20:38:53.000000000 -0700
+++ linux-2.6.0-test1-hpet/include/asm-i386/apic.h	2003-08-13 11:34:37.000000000 -0700
@@ -64,6 +64,8 @@ static inline void ack_APIC_irq(void)
 	apic_write_around(APIC_EOI, 0);
 }
 
+extern void (*wait_timer_tick)(void);
+
 extern int get_maxlvt(void);
 extern void clear_local_APIC(void);
 extern void connect_bsp_APIC (void);
diff -purN linux-2.6.0-test1/include/asm-i386/fixmap.h linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h
--- linux-2.6.0-test1/include/asm-i386/fixmap.h	2003-07-13 20:29:30.000000000 -0700
+++ linux-2.6.0-test1-hpet/include/asm-i386/fixmap.h	2003-08-14 13:10:31.000000000 -0700
@@ -44,6 +44,9 @@
 enum fixed_addresses {
 	FIX_HOLE,
 	FIX_VSYSCALL,
+#ifdef CONFIG_HPET_TIMER
+	FIX_HPET_BASE,
+#endif
 #ifdef CONFIG_X86_LOCAL_APIC
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
 #endif
diff -purN linux-2.6.0-test1/include/asm-i386/hpet.h linux-2.6.0-test1-hpet/include/asm-i386/hpet.h
--- linux-2.6.0-test1/include/asm-i386/hpet.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.0-test1-hpet/include/asm-i386/hpet.h	2003-08-18 20:22:40.000000000 -0700
@@ -0,0 +1,104 @@
+
+#ifndef _I386_HPET_H
+#define _I386_HPET_H
+
+#ifdef CONFIG_HPET_TIMER
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/msr.h>
+#include <asm/delay.h>
+#include <asm/mpspec.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+#include <linux/timex.h>
+#include <linux/config.h>
+
+#include <asm/fixmap.h>
+
+/*
+ * Documentation on HPET can be found at:
+ *      http://www.intel.com/ial/home/sp/pcmmspec.htm
+ *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
+ */
+
+#define HPET_ID		0x000
+#define HPET_PERIOD	0x004
+#define HPET_CFG	0x010
+#define HPET_STATUS	0x020
+#define HPET_COUNTER	0x0f0
+#define HPET_T0_CFG	0x100
+#define HPET_T0_CMP	0x108
+#define HPET_T0_ROUTE	0x110
+#define HPET_T1_CFG	0x120
+#define HPET_T1_CMP	0x128
+#define HPET_T1_ROUTE	0x130
+#define HPET_T2_CFG	0x140
+#define HPET_T2_CMP	0x148
+#define HPET_T2_ROUTE	0x150
+
+#define HPET_ID_VENDOR	0xffff0000
+#define HPET_ID_LEGSUP	0x00008000
+#define HPET_ID_NUMBER	0x00001f00
+#define HPET_ID_REV	0x000000ff
+
+#define HPET_ID_VENDOR_SHIFT	16
+#define HPET_ID_VENDOR_8086	0x8086
+
+#define HPET_CFG_ENABLE	0x001
+#define HPET_CFG_LEGACY	0x002
+
+#define HPET_TN_ENABLE		0x004
+#define HPET_TN_PERIODIC	0x008
+#define HPET_TN_PERIODIC_CAP	0x010
+#define HPET_TN_SETVAL		0x040
+#define HPET_TN_32BIT		0x100
+
+/* Use our own asm for 64 bit multiply/divide */
+#define ASM_MUL64_REG(eax_out,edx_out,reg_in,eax_in) 			\
+		__asm__ __volatile__("mull %2" 				\
+				:"=a" (eax_out), "=d" (edx_out) 	\
+				:"r" (reg_in), "0" (eax_in))
+
+#define ASM_DIV64_REG(eax_out,edx_out,reg_in,eax_in,edx_in) 		\
+		__asm__ __volatile__("divl %2" 				\
+				:"=a" (eax_out), "=d" (edx_out) 	\
+				:"r" (reg_in), "0" (eax_in), "1" (edx_in))
+
+#define hpet_readl(a)		readl(fix_to_virt(FIX_HPET_BASE) + a)
+#define hpet_writel(d,a)	writel(d, fix_to_virt(FIX_HPET_BASE) + a)
+
+#define KERNEL_TICK_USEC 	(1000000UL/HZ)	/* tick value in microsec */
+/* Max HPET Period is 10^8 femto sec as in HPET spec */
+#define HPET_MAX_PERIOD (100000000UL)
+/*
+ * Min HPET period is 10^5 femto sec just for safety. If it is less than this, 
+ * then 32 bit HPET counter wrapsaround in less than 0.5 sec. 
+ */
+#define HPET_MIN_PERIOD (100000UL)
+
+extern unsigned long hpet_period;	/* fsecs / HPET clock */
+extern unsigned long hpet_tick;  	/* hpet clks count per tick */
+extern unsigned long hpet_address;	/* hpet memory map address */
+extern unsigned long hpet_virt_address;	/* hpet kernel virtual address */
+
+extern int hpet_enable(void);
+extern int is_hpet_enabled(void);
+
+#endif /* CONFIG_HPET_TIMER */
+#endif /* _I386_HPET_H */
diff -purN linux-2.6.0-test1/include/asm-i386/mc146818rtc.h linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h
--- linux-2.6.0-test1/include/asm-i386/mc146818rtc.h	2003-07-13 20:36:37.000000000 -0700
+++ linux-2.6.0-test1-hpet/include/asm-i386/mc146818rtc.h	2003-08-18 20:23:43.000000000 -0700
@@ -24,6 +24,10 @@ 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/Documentation/kernel-parameters.txt linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt
--- linux-2.6.0-test1/Documentation/kernel-parameters.txt       2003-07-13 20:39:36.000000000 -0700
+++ linux-2.6.0-test1-hpet/Documentation/kernel-parameters.txt  2003-08-18 20:37:41.000000000 -0700
@@ -212,7 +212,10 @@ running once the system is up.
			when calculating gettimeofday(). If specicified timesource
			is not avalible, it defaults to PIT. 
			Format: { pit | tsc | cyclone | ... }
-
+
+	hpet=		[IA-32,HPET] option to disable HPET and use PIT.
+			Format: disable
+
	cm206=		[HW,CD]
			Format: { auto | [<io>,][<irq>] }
 



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

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

end of thread, other threads:[~2003-08-26 23:51 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <C8C38546F90ABF408A5961FC01FDBF1902C7D1C9@fmsmsx405.fm.intel.com.suse.lists.linux.kernel>
     [not found] ` <20030820080513.GB17793@ucw.cz.suse.lists.linux.kernel>
2003-08-20 10:01   ` [PATCH][2.6][2/5]Support for HPET based timer Andi Kleen
2003-08-20 10:47     ` Mikael Pettersson
2003-08-20 17:09     ` Dave Hansen
2003-08-26 23:50 Pallipadi, Venkatesh
  -- strict thread matches above, loose matches on Subject: below --
2003-08-26 21:43 Mikael Pettersson
2003-08-26 18:31 Pallipadi, Venkatesh
2003-08-26 18:51 ` Andrew Morton
2003-08-26 18:55   ` Andrew Morton
2003-08-26 23:20     ` john stultz
2003-08-20 17:01 Pallipadi, Venkatesh
2003-08-20  1:30 Pallipadi, Venkatesh
2003-08-20  0:18 Pallipadi, Venkatesh
2003-08-20  8:05 ` Vojtech Pavlik
     [not found] <mmZK.Q4.11@gated-at.bofh.it>
2003-08-19 22:41 ` Andi Kleen
2003-08-19 19:20 Pallipadi, Venkatesh
2003-08-19 22:39 ` 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).