Add HPET support to Xen. It is quicker to access and more

precise than the PIT.
Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kaf24@firebug.cl.cam.ac.uk committed 2005-07-27 15:32:44 +00:00
1 parent e386da97d1
commit 5e8bc03f67
5 files changed
+198 -10

No files matched your search

+1 -1
View File
@@ -382,7 +382,7 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
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);
+143 -9
View File
@@ -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 s_time_t stime_platform_stamp;
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 @@ void calibrate_tsc_ap(void)
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,21 +259,137 @@ static void pit_overflow(void *unused)
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)
{
u64 diff64 = platform_time - platform_timer_stamp;
@@ -276,7 +405,7 @@ static s_time_t read_platform_stime(void)
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,13 +418,19 @@ static void platform_time_calibration(void)
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());
}
/***************************************************************************
* CMOS Timer functions
@@ -494,9 +629,8 @@ static void local_time_calibration(void *unused)
#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. */
+1
View File
@@ -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
+1
View File
@@ -30,6 +30,7 @@ enum fixed_addresses {
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
};
+52
View File
@@ -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__ */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.