Skip to content

Commit

Permalink
[PATCH] time: x86_64: convert x86_64 to use GENERIC_TIME
Browse files Browse the repository at this point in the history
This patch converts x86_64 to use the GENERIC_TIME infrastructure and adds
clocksource structures for both TSC and HPET (ACPI PM is shared w/ i386).

[akpm@osdl.org: fix printk timestamps]
[akpm@osdl.org: fix printk ckeanups]
[akpm@osdl.org: hpet build fix]
Signed-off-by: John Stultz <johnstul@us.ibm.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Andi Kleen <ak@muc.de>
Cc: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
john stultz authored and Linus Torvalds committed Feb 16, 2007
1 parent c37e7bb commit 1489939
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 415 deletions.
4 changes: 4 additions & 0 deletions arch/x86_64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ config X86
bool
default y

config GENERIC_TIME
bool
default y

config ZONE_DMA32
bool
default y
Expand Down
2 changes: 1 addition & 1 deletion arch/x86_64/kernel/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ static void setup_APIC_timer(unsigned int clocks)
/* Turn off PIT interrupt if we use APIC timer as main timer.
Only works with the PM timer right now
TBD fix it for HPET too. */
if (vxtime.mode == VXTIME_PMTMR &&
if ((pmtmr_ioport != 0) &&
smp_processor_id() == boot_cpu_id &&
apic_runs_main_timer == 1 &&
!cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
Expand Down
64 changes: 58 additions & 6 deletions arch/x86_64/kernel/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ unsigned long hpet_tick; /* HPET clocks / interrupt */
int hpet_use_timer; /* Use counter of hpet for time keeping,
* otherwise PIT
*/
unsigned int do_gettimeoffset_hpet(void)
{
/* cap counter read to one tick to avoid inconsistencies */
unsigned long counter = hpet_readl(HPET_COUNTER) - vxtime.last;
return (min(counter,hpet_tick) * vxtime.quot) >> US_SCALE;
}

#ifdef CONFIG_HPET
static __init int late_hpet_init(void)
Expand Down Expand Up @@ -451,3 +445,61 @@ static int __init nohpet_setup(char *s)

__setup("nohpet", nohpet_setup);

#define HPET_MASK 0xFFFFFFFF
#define HPET_SHIFT 22

/* FSEC = 10^-15 NSEC = 10^-9 */
#define FSEC_PER_NSEC 1000000

static void *hpet_ptr;

static cycle_t read_hpet(void)
{
return (cycle_t)readl(hpet_ptr);
}

struct clocksource clocksource_hpet = {
.name = "hpet",
.rating = 250,
.read = read_hpet,
.mask = (cycle_t)HPET_MASK,
.mult = 0, /* set below */
.shift = HPET_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};

static int __init init_hpet_clocksource(void)
{
unsigned long hpet_period;
void __iomem *hpet_base;
u64 tmp;

if (!hpet_address)
return -ENODEV;

/* calculate the hpet address: */
hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
hpet_ptr = hpet_base + HPET_COUNTER;

/* calculate the frequency: */
hpet_period = readl(hpet_base + HPET_PERIOD);

/*
* hpet period is in femto seconds per cycle
* so we need to convert this to ns/cyc units
* aproximated by mult/2^shift
*
* fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
* fsec/cyc * 1ns/1000000fsec * 2^shift = mult
* fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
* (fsec/cyc << shift)/1000000 = mult
* (hpet_period << shift)/FSEC_PER_NSEC = mult
*/
tmp = (u64)hpet_period << HPET_SHIFT;
do_div(tmp, FSEC_PER_NSEC);
clocksource_hpet.mult = (u32)tmp;

return clocksource_register(&clocksource_hpet);
}

module_init(init_hpet_clocksource);
58 changes: 0 additions & 58 deletions arch/x86_64/kernel/pmtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@
#include <asm/msr.h>
#include <asm/vsyscall.h>

/* The I/O port the PMTMR resides at.
* The location is detected during setup_arch(),
* in arch/i386/kernel/acpi/boot.c */
u32 pmtmr_ioport __read_mostly;

/* value of the Power timer at last timer interrupt */
static u32 offset_delay;
static u32 last_pmtmr_tick;

#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */

static inline u32 cyc2us(u32 cycles)
Expand All @@ -48,38 +39,6 @@ static inline u32 cyc2us(u32 cycles)
return (cycles >> 10);
}

int pmtimer_mark_offset(void)
{
static int first_run = 1;
unsigned long tsc;
u32 lost;

u32 tick = inl(pmtmr_ioport);
u32 delta;

delta = cyc2us((tick - last_pmtmr_tick) & ACPI_PM_MASK);

last_pmtmr_tick = tick;
monotonic_base += delta * NSEC_PER_USEC;

delta += offset_delay;

lost = delta / (USEC_PER_SEC / HZ);
offset_delay = delta % (USEC_PER_SEC / HZ);

rdtscll(tsc);
vxtime.last_tsc = tsc - offset_delay * (u64)cpu_khz / 1000;

/* don't calculate delay for first run,
or if we've got less then a tick */
if (first_run || (lost < 1)) {
first_run = 0;
offset_delay = 0;
}

return lost - 1;
}

static unsigned pmtimer_wait_tick(void)
{
u32 a, b;
Expand All @@ -101,23 +60,6 @@ void pmtimer_wait(unsigned us)
} while (cyc2us(b - a) < us);
}

void pmtimer_resume(void)
{
last_pmtmr_tick = inl(pmtmr_ioport);
}

unsigned int do_gettimeoffset_pm(void)
{
u32 now, offset, delta = 0;

offset = last_pmtmr_tick;
now = inl(pmtmr_ioport);
delta = (now - offset) & ACPI_PM_MASK;

return offset_delay + cyc2us(delta);
}


static int __init nopmtimer_setup(char *s)
{
pmtmr_ioport = 0;
Expand Down
1 change: 0 additions & 1 deletion arch/x86_64/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,6 @@ void __init smp_cpus_done(unsigned int max_cpus)
smp_cleanup_boot();
setup_ioapic_dest();
check_nmi_watchdog();
time_init_gtod();
}

#ifdef CONFIG_HOTPLUG_CPU
Expand Down
Loading

0 comments on commit 1489939

Please sign in to comment.