[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Add HPET support to Xen. It is quicker to access and more
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID b7e975425dd677520c630f92e2a2d6d2668cb1d5 # Parent 7599a943b39e5eb2ed612d0738cf27913cb78885 Add HPET support to Xen. It is quicker to access and more precise than the PIT. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> diff -r 7599a943b39e -r b7e975425dd6 xen/arch/x86/acpi/boot.c --- a/xen/arch/x86/acpi/boot.c Wed Jul 27 11:20:47 2005 +++ b/xen/arch/x86/acpi/boot.c Wed Jul 27 15:32:44 2005 @@ -382,7 +382,7 @@ return -1; } -#ifdef CONFIG_X86_64 +#if 0/*def CONFIG_X86_64*/ vxtime.hpet_address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32); diff -r 7599a943b39e -r b7e975425dd6 xen/arch/x86/time.c --- a/xen/arch/x86/time.c Wed Jul 27 11:20:47 2005 +++ b/xen/arch/x86/time.c Wed Jul 27 15:32:44 2005 @@ -28,11 +28,18 @@ #include <asm/fixmap.h> #include <asm/mc146818rtc.h> #include <asm/div64.h> +#include <asm/hpet.h> #include <io_ports.h> +/* opt_hpet_force: If true, force HPET configuration via PCI space. */ +/* NB. This is a gross hack. Mainly useful for HPET testing. */ +static int opt_hpet_force = 0; +boolean_param("hpet_force", opt_hpet_force); + #define EPOCH MILLISECS(1000) unsigned long cpu_khz; /* CPU clock frequency in kHz. */ +unsigned long hpet_address; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; int timer_ack = 0; unsigned long volatile jiffies; @@ -58,6 +65,7 @@ static u64 platform_timer_stamp; static struct time_scale platform_timer_scale; static spinlock_t platform_timer_lock = SPIN_LOCK_UNLOCKED; +static u64 (*read_platform_count)(void); static inline u32 down_shift(u64 time, int shift) { @@ -225,8 +233,13 @@ atomic_dec(&tsc_calibrate_gang); } + +/************************************************************ + * PLATFORM TIMER 1: PROGRAMMABLE INTERVAL TIMER (LEGACY PIT) + */ + /* Protected by platform_timer_lock. */ -static u64 platform_pit_counter; +static u64 pit_counter64; static u16 pit_stamp; static struct ac_timer pit_overflow_timer; @@ -246,20 +259,136 @@ spin_lock(&platform_timer_lock); counter = pit_read_counter(); - platform_pit_counter += (u16)(pit_stamp - counter); + pit_counter64 += (u16)(pit_stamp - counter); pit_stamp = counter; spin_unlock(&platform_timer_lock); set_ac_timer(&pit_overflow_timer, NOW() + MILLISECS(20)); } -static void init_platform_timer(void) -{ +static u64 read_pit_count(void) +{ + return pit_counter64 + (u16)(pit_stamp - pit_read_counter()); +} + +static int init_pit(void) +{ + read_platform_count = read_pit_count; + init_ac_timer(&pit_overflow_timer, pit_overflow, NULL, 0); pit_overflow(NULL); - platform_timer_stamp = platform_pit_counter; + platform_timer_stamp = pit_counter64; set_time_scale(&platform_timer_scale, CLOCK_TICK_RATE); -} + + return 1; +} + +/************************************************************ + * PLATFORM TIMER 2: HIGH PRECISION EVENT TIMER (HPET) + */ + +/* Protected by platform_timer_lock. */ +static u64 hpet_counter64, hpet_overflow_period; +static u32 hpet_stamp; +static struct ac_timer hpet_overflow_timer; + +static void hpet_overflow(void *unused) +{ + u32 counter; + + spin_lock(&platform_timer_lock); + counter = hpet_read32(HPET_COUNTER); + hpet_counter64 += (u32)(counter - hpet_stamp); + hpet_stamp = counter; + spin_unlock(&platform_timer_lock); + + set_ac_timer(&hpet_overflow_timer, NOW() + hpet_overflow_period); +} + +static u64 read_hpet_count(void) +{ + return hpet_counter64 + (u32)(hpet_read32(HPET_COUNTER) - hpet_stamp); +} + +static int init_hpet(void) +{ + u64 hpet_rate; + u32 hpet_id, hpet_period, cfg; + int i; + + if ( (hpet_address == 0) && opt_hpet_force ) + { + printk(KERN_WARNING "WARNING: Enabling HPET base manually!\n"); + outl(0x800038a0, 0xcf8); + outl(0xff000001, 0xcfc); + outl(0x800038a0, 0xcf8); + hpet_address = inl(0xcfc) & 0xfffffffe; + printk(KERN_WARNING "WARNING: Enabled HPET at %#lx.\n", hpet_address); + } + + if ( hpet_address == 0 ) + return 0; + + set_fixmap_nocache(FIX_HPET_BASE, hpet_address); + + hpet_id = hpet_read32(HPET_ID); + if ( hpet_id == 0 ) + { + printk("BAD HPET vendor id.\n"); + return 0; + } + + /* Check for sane period (100ps <= period <= 100ns). */ + hpet_period = hpet_read32(HPET_PERIOD); + if ( (hpet_period > 100000000) || (hpet_period < 100000) ) + { + printk("BAD HPET period %u.\n", hpet_period); + return 0; + } + + cfg = hpet_read32(HPET_CFG); + cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); + hpet_write32(cfg, HPET_CFG); + + for ( i = 0; i <= ((hpet_id >> 8) & 31); i++ ) + { + cfg = hpet_read32(HPET_T0_CFG + i*0x20); + cfg &= ~HPET_TN_ENABLE; + hpet_write32(cfg & ~HPET_TN_ENABLE, HPET_T0_CFG); + } + + cfg = hpet_read32(HPET_CFG); + cfg |= HPET_CFG_ENABLE; + hpet_write32(cfg, HPET_CFG); + + read_platform_count = read_hpet_count; + + hpet_rate = 1000000000000000ULL; /* 10^15 */ + (void)do_div(hpet_rate, hpet_period); + set_time_scale(&platform_timer_scale, hpet_rate); + + /* Trigger overflow avoidance roughly when counter increments 2^31. */ + if ( (hpet_rate >> 31) != 0 ) + { + hpet_overflow_period = MILLISECS(1000); + (void)do_div(hpet_overflow_period, (u32)(hpet_rate >> 31) + 1); + } + else + { + hpet_overflow_period = MILLISECS(1000) << 31; + (void)do_div(hpet_overflow_period, (u32)hpet_rate); + } + + init_ac_timer(&hpet_overflow_timer, hpet_overflow, NULL, 0); + hpet_overflow(NULL); + platform_timer_stamp = hpet_counter64; + + return 1; +} + +/************************************************************ + * GENERIC PLATFORM TIMER INFRASTRUCTURE + */ static s_time_t __read_platform_stime(u64 platform_time) { @@ -276,7 +405,7 @@ s_time_t stime; spin_lock(&platform_timer_lock); - counter = platform_pit_counter + (u16)(pit_stamp - pit_read_counter()); + counter = read_platform_count(); stime = __read_platform_stime(counter); spin_unlock(&platform_timer_lock); @@ -289,11 +418,17 @@ s_time_t stamp; spin_lock(&platform_timer_lock); - counter = platform_pit_counter + (u16)(pit_stamp - pit_read_counter()); + counter = read_platform_count(); stamp = __read_platform_stime(counter); stime_platform_stamp = stamp; platform_timer_stamp = counter; spin_unlock(&platform_timer_lock); +} + +static void init_platform_timer(void) +{ + if ( !init_hpet() ) + BUG_ON(!init_pit()); } @@ -494,9 +629,8 @@ #if 0 printk("PRE%d: tsc=%lld stime=%lld master=%lld\n", cpu, prev_tsc, prev_local_stime, prev_master_stime); - printk("CUR%d: tsc=%lld stime=%lld master=%lld %lld\n", - cpu, curr_tsc, curr_local_stime, curr_master_stime, - platform_pit_counter); + printk("CUR%d: tsc=%lld stime=%lld master=%lld\n", + cpu, curr_tsc, curr_local_stime, curr_master_stime); #endif /* Local time warps forward if it lags behind master time. */ diff -r 7599a943b39e -r b7e975425dd6 xen/include/asm-x86/config.h --- a/xen/include/asm-x86/config.h Wed Jul 27 11:20:47 2005 +++ b/xen/include/asm-x86/config.h Wed Jul 27 15:32:44 2005 @@ -23,6 +23,7 @@ #define CONFIG_X86_LOCAL_APIC 1 #define CONFIG_X86_GOOD_APIC 1 #define CONFIG_X86_IO_APIC 1 +#define CONFIG_HPET_TIMER 1 /* Intel P4 currently has largest cache line (L2 line size is 128 bytes). */ #define CONFIG_X86_L1_CACHE_SHIFT 7 diff -r 7599a943b39e -r b7e975425dd6 xen/include/asm-x86/fixmap.h --- a/xen/include/asm-x86/fixmap.h Wed Jul 27 11:20:47 2005 +++ b/xen/include/asm-x86/fixmap.h Wed Jul 27 15:32:44 2005 @@ -30,6 +30,7 @@ FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1, FIX_ACPI_BEGIN, FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, + FIX_HPET_BASE, __end_of_fixed_addresses }; diff -r 7599a943b39e -r b7e975425dd6 xen/include/asm-x86/hpet.h --- /dev/null Wed Jul 27 11:20:47 2005 +++ b/xen/include/asm-x86/hpet.h Wed Jul 27 15:32:44 2005 @@ -0,0 +1,52 @@ +#ifndef __X86_HPET_H__ +#define __X86_HPET_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_MMAP_SIZE 1024 + +#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_NUMBER_SHIFT 8 + +#define HPET_ID_VENDOR_SHIFT 16 +#define HPET_ID_VENDOR_8086 0x8086 + +#define HPET_CFG_ENABLE 0x001 +#define HPET_CFG_LEGACY 0x002 +#define HPET_LEGACY_8254 2 +#define HPET_LEGACY_RTC 8 + +#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 + +#define hpet_read32(x) \ + (*(volatile u32 *)(fix_to_virt(FIX_HPET_BASE) + (x))) +#define hpet_write32(y,x) \ + (*(volatile u32 *)(fix_to_virt(FIX_HPET_BASE) + (x)) = (y)) + +#endif /* __X86_HPET_H__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |