ia64/xen-unstable

changeset 5901:b7e975425dd6

Add HPET support to Xen. It is quicker to access and more
precise than the PIT.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Jul 27 15:32:44 2005 +0000 (2005-07-27)
parents 7599a943b39e
children 01966dd718a8 039c7fd6a4d2
files xen/arch/x86/acpi/boot.c xen/arch/x86/time.c xen/include/asm-x86/config.h xen/include/asm-x86/fixmap.h xen/include/asm-x86/hpet.h
line diff
     1.1 --- a/xen/arch/x86/acpi/boot.c	Wed Jul 27 11:20:47 2005 +0000
     1.2 +++ b/xen/arch/x86/acpi/boot.c	Wed Jul 27 15:32:44 2005 +0000
     1.3 @@ -382,7 +382,7 @@ static int __init acpi_parse_hpet(unsign
     1.4  		return -1;
     1.5  	}
     1.6  
     1.7 -#ifdef	CONFIG_X86_64
     1.8 +#if 0/*def	CONFIG_X86_64*/
     1.9          vxtime.hpet_address = hpet_tbl->addr.addrl |
    1.10                  ((long) hpet_tbl->addr.addrh << 32);
    1.11  
     2.1 --- a/xen/arch/x86/time.c	Wed Jul 27 11:20:47 2005 +0000
     2.2 +++ b/xen/arch/x86/time.c	Wed Jul 27 15:32:44 2005 +0000
     2.3 @@ -28,11 +28,18 @@
     2.4  #include <asm/fixmap.h>
     2.5  #include <asm/mc146818rtc.h>
     2.6  #include <asm/div64.h>
     2.7 +#include <asm/hpet.h>
     2.8  #include <io_ports.h>
     2.9  
    2.10 +/* opt_hpet_force: If true, force HPET configuration via PCI space. */
    2.11 +/* NB. This is a gross hack. Mainly useful for HPET testing. */
    2.12 +static int opt_hpet_force = 0;
    2.13 +boolean_param("hpet_force", opt_hpet_force);
    2.14 +
    2.15  #define EPOCH MILLISECS(1000)
    2.16  
    2.17  unsigned long cpu_khz;  /* CPU clock frequency in kHz. */
    2.18 +unsigned long hpet_address;
    2.19  spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
    2.20  int timer_ack = 0;
    2.21  unsigned long volatile jiffies;
    2.22 @@ -58,6 +65,7 @@ static s_time_t stime_platform_stamp;
    2.23  static u64 platform_timer_stamp;
    2.24  static struct time_scale platform_timer_scale;
    2.25  static spinlock_t platform_timer_lock = SPIN_LOCK_UNLOCKED;
    2.26 +static u64 (*read_platform_count)(void);
    2.27  
    2.28  static inline u32 down_shift(u64 time, int shift)
    2.29  {
    2.30 @@ -225,8 +233,13 @@ void calibrate_tsc_ap(void)
    2.31      atomic_dec(&tsc_calibrate_gang);
    2.32  }
    2.33  
    2.34 +
    2.35 +/************************************************************
    2.36 + * PLATFORM TIMER 1: PROGRAMMABLE INTERVAL TIMER (LEGACY PIT)
    2.37 + */
    2.38 +
    2.39  /* Protected by platform_timer_lock. */
    2.40 -static u64 platform_pit_counter;
    2.41 +static u64 pit_counter64;
    2.42  static u16 pit_stamp;
    2.43  static struct ac_timer pit_overflow_timer;
    2.44  
    2.45 @@ -246,21 +259,137 @@ static void pit_overflow(void *unused)
    2.46  
    2.47      spin_lock(&platform_timer_lock);
    2.48      counter = pit_read_counter();
    2.49 -    platform_pit_counter += (u16)(pit_stamp - counter);
    2.50 +    pit_counter64 += (u16)(pit_stamp - counter);
    2.51      pit_stamp = counter;
    2.52      spin_unlock(&platform_timer_lock);
    2.53  
    2.54      set_ac_timer(&pit_overflow_timer, NOW() + MILLISECS(20));
    2.55  }
    2.56  
    2.57 -static void init_platform_timer(void)
    2.58 +static u64 read_pit_count(void)
    2.59  {
    2.60 +    return pit_counter64 + (u16)(pit_stamp - pit_read_counter());
    2.61 +}
    2.62 +
    2.63 +static int init_pit(void)
    2.64 +{
    2.65 +    read_platform_count = read_pit_count;
    2.66 +
    2.67      init_ac_timer(&pit_overflow_timer, pit_overflow, NULL, 0);
    2.68      pit_overflow(NULL);
    2.69 -    platform_timer_stamp = platform_pit_counter;
    2.70 +    platform_timer_stamp = pit_counter64;
    2.71      set_time_scale(&platform_timer_scale, CLOCK_TICK_RATE);
    2.72 +
    2.73 +    return 1;
    2.74  }
    2.75  
    2.76 +/************************************************************
    2.77 + * PLATFORM TIMER 2: HIGH PRECISION EVENT TIMER (HPET)
    2.78 + */
    2.79 +
    2.80 +/* Protected by platform_timer_lock. */
    2.81 +static u64 hpet_counter64, hpet_overflow_period;
    2.82 +static u32 hpet_stamp;
    2.83 +static struct ac_timer hpet_overflow_timer;
    2.84 +
    2.85 +static void hpet_overflow(void *unused)
    2.86 +{
    2.87 +    u32 counter;
    2.88 +
    2.89 +    spin_lock(&platform_timer_lock);
    2.90 +    counter = hpet_read32(HPET_COUNTER);
    2.91 +    hpet_counter64 += (u32)(counter - hpet_stamp);
    2.92 +    hpet_stamp = counter;
    2.93 +    spin_unlock(&platform_timer_lock);
    2.94 +
    2.95 +    set_ac_timer(&hpet_overflow_timer, NOW() + hpet_overflow_period);
    2.96 +}
    2.97 +
    2.98 +static u64 read_hpet_count(void)
    2.99 +{
   2.100 +    return hpet_counter64 + (u32)(hpet_read32(HPET_COUNTER) - hpet_stamp);
   2.101 +}
   2.102 +
   2.103 +static int init_hpet(void)
   2.104 +{
   2.105 +    u64 hpet_rate;
   2.106 +    u32 hpet_id, hpet_period, cfg;
   2.107 +    int i;
   2.108 +
   2.109 +    if ( (hpet_address == 0) && opt_hpet_force )
   2.110 +    {
   2.111 +		printk(KERN_WARNING "WARNING: Enabling HPET base manually!\n");
   2.112 +        outl(0x800038a0, 0xcf8);
   2.113 +        outl(0xff000001, 0xcfc);
   2.114 +        outl(0x800038a0, 0xcf8);
   2.115 +        hpet_address = inl(0xcfc) & 0xfffffffe;
   2.116 +		printk(KERN_WARNING "WARNING: Enabled HPET at %#lx.\n", hpet_address);
   2.117 +    }
   2.118 +
   2.119 +    if ( hpet_address == 0 )
   2.120 +        return 0;
   2.121 +
   2.122 +    set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
   2.123 +
   2.124 +    hpet_id = hpet_read32(HPET_ID);
   2.125 +    if ( hpet_id == 0 )
   2.126 +    {
   2.127 +        printk("BAD HPET vendor id.\n");
   2.128 +        return 0;
   2.129 +    }
   2.130 +
   2.131 +    /* Check for sane period (100ps <= period <= 100ns). */
   2.132 +    hpet_period = hpet_read32(HPET_PERIOD);
   2.133 +    if ( (hpet_period > 100000000) || (hpet_period < 100000) )
   2.134 +    {
   2.135 +        printk("BAD HPET period %u.\n", hpet_period);
   2.136 +        return 0;
   2.137 +    }
   2.138 +
   2.139 +    cfg = hpet_read32(HPET_CFG);
   2.140 +    cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
   2.141 +    hpet_write32(cfg, HPET_CFG);
   2.142 +
   2.143 +    for ( i = 0; i <= ((hpet_id >> 8) & 31); i++ )
   2.144 +    {
   2.145 +        cfg = hpet_read32(HPET_T0_CFG + i*0x20);
   2.146 +        cfg &= ~HPET_TN_ENABLE;
   2.147 +        hpet_write32(cfg & ~HPET_TN_ENABLE, HPET_T0_CFG);
   2.148 +    }
   2.149 +
   2.150 +    cfg = hpet_read32(HPET_CFG);
   2.151 +    cfg |= HPET_CFG_ENABLE;
   2.152 +    hpet_write32(cfg, HPET_CFG);
   2.153 +
   2.154 +    read_platform_count = read_hpet_count;
   2.155 +
   2.156 +    hpet_rate = 1000000000000000ULL; /* 10^15 */
   2.157 +    (void)do_div(hpet_rate, hpet_period);
   2.158 +    set_time_scale(&platform_timer_scale, hpet_rate);
   2.159 +
   2.160 +    /* Trigger overflow avoidance roughly when counter increments 2^31. */
   2.161 +    if ( (hpet_rate >> 31) != 0 )
   2.162 +    {
   2.163 +        hpet_overflow_period = MILLISECS(1000);
   2.164 +        (void)do_div(hpet_overflow_period, (u32)(hpet_rate >> 31) + 1);
   2.165 +    }
   2.166 +    else
   2.167 +    {
   2.168 +        hpet_overflow_period = MILLISECS(1000) << 31;
   2.169 +        (void)do_div(hpet_overflow_period, (u32)hpet_rate);
   2.170 +    }
   2.171 +
   2.172 +    init_ac_timer(&hpet_overflow_timer, hpet_overflow, NULL, 0);
   2.173 +    hpet_overflow(NULL);
   2.174 +    platform_timer_stamp = hpet_counter64;
   2.175 +
   2.176 +    return 1;
   2.177 +}
   2.178 +
   2.179 +/************************************************************
   2.180 + * GENERIC PLATFORM TIMER INFRASTRUCTURE
   2.181 + */
   2.182 +
   2.183  static s_time_t __read_platform_stime(u64 platform_time)
   2.184  {
   2.185      u64 diff64 = platform_time - platform_timer_stamp;
   2.186 @@ -276,7 +405,7 @@ static s_time_t read_platform_stime(void
   2.187      s_time_t stime;
   2.188  
   2.189      spin_lock(&platform_timer_lock);
   2.190 -    counter = platform_pit_counter + (u16)(pit_stamp - pit_read_counter());
   2.191 +    counter = read_platform_count();
   2.192      stime   = __read_platform_stime(counter);
   2.193      spin_unlock(&platform_timer_lock);
   2.194  
   2.195 @@ -289,13 +418,19 @@ static void platform_time_calibration(vo
   2.196      s_time_t stamp;
   2.197  
   2.198      spin_lock(&platform_timer_lock);
   2.199 -    counter = platform_pit_counter + (u16)(pit_stamp - pit_read_counter());
   2.200 +    counter = read_platform_count();
   2.201      stamp   = __read_platform_stime(counter);
   2.202      stime_platform_stamp = stamp;
   2.203      platform_timer_stamp = counter;
   2.204      spin_unlock(&platform_timer_lock);
   2.205  }
   2.206  
   2.207 +static void init_platform_timer(void)
   2.208 +{
   2.209 +    if ( !init_hpet() )
   2.210 +        BUG_ON(!init_pit());
   2.211 +}
   2.212 +
   2.213  
   2.214  /***************************************************************************
   2.215   * CMOS Timer functions
   2.216 @@ -494,9 +629,8 @@ static void local_time_calibration(void 
   2.217  #if 0
   2.218      printk("PRE%d: tsc=%lld stime=%lld master=%lld\n",
   2.219             cpu, prev_tsc, prev_local_stime, prev_master_stime);
   2.220 -    printk("CUR%d: tsc=%lld stime=%lld master=%lld %lld\n",
   2.221 -           cpu, curr_tsc, curr_local_stime, curr_master_stime,
   2.222 -           platform_pit_counter);
   2.223 +    printk("CUR%d: tsc=%lld stime=%lld master=%lld\n",
   2.224 +           cpu, curr_tsc, curr_local_stime, curr_master_stime);
   2.225  #endif
   2.226  
   2.227      /* Local time warps forward if it lags behind master time. */
     3.1 --- a/xen/include/asm-x86/config.h	Wed Jul 27 11:20:47 2005 +0000
     3.2 +++ b/xen/include/asm-x86/config.h	Wed Jul 27 15:32:44 2005 +0000
     3.3 @@ -23,6 +23,7 @@
     3.4  #define CONFIG_X86_LOCAL_APIC 1
     3.5  #define CONFIG_X86_GOOD_APIC 1
     3.6  #define CONFIG_X86_IO_APIC 1
     3.7 +#define CONFIG_HPET_TIMER 1
     3.8  
     3.9  /* Intel P4 currently has largest cache line (L2 line size is 128 bytes). */
    3.10  #define CONFIG_X86_L1_CACHE_SHIFT 7
     4.1 --- a/xen/include/asm-x86/fixmap.h	Wed Jul 27 11:20:47 2005 +0000
     4.2 +++ b/xen/include/asm-x86/fixmap.h	Wed Jul 27 15:32:44 2005 +0000
     4.3 @@ -30,6 +30,7 @@ enum fixed_addresses {
     4.4      FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
     4.5      FIX_ACPI_BEGIN,
     4.6      FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
     4.7 +    FIX_HPET_BASE,
     4.8      __end_of_fixed_addresses
     4.9  };
    4.10  
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/xen/include/asm-x86/hpet.h	Wed Jul 27 15:32:44 2005 +0000
     5.3 @@ -0,0 +1,52 @@
     5.4 +#ifndef __X86_HPET_H__
     5.5 +#define __X86_HPET_H__
     5.6 +
     5.7 +/*
     5.8 + * Documentation on HPET can be found at:
     5.9 + *      http://www.intel.com/ial/home/sp/pcmmspec.htm
    5.10 + *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
    5.11 + */
    5.12 +
    5.13 +#define HPET_MMAP_SIZE	1024
    5.14 +
    5.15 +#define HPET_ID		0x000
    5.16 +#define HPET_PERIOD	0x004
    5.17 +#define HPET_CFG	0x010
    5.18 +#define HPET_STATUS	0x020
    5.19 +#define HPET_COUNTER	0x0f0
    5.20 +#define HPET_T0_CFG	0x100
    5.21 +#define HPET_T0_CMP	0x108
    5.22 +#define HPET_T0_ROUTE	0x110
    5.23 +#define HPET_T1_CFG	0x120
    5.24 +#define HPET_T1_CMP	0x128
    5.25 +#define HPET_T1_ROUTE	0x130
    5.26 +#define HPET_T2_CFG	0x140
    5.27 +#define HPET_T2_CMP	0x148
    5.28 +#define HPET_T2_ROUTE	0x150
    5.29 +
    5.30 +#define HPET_ID_VENDOR	0xffff0000
    5.31 +#define HPET_ID_LEGSUP	0x00008000
    5.32 +#define HPET_ID_NUMBER	0x00001f00
    5.33 +#define HPET_ID_REV	0x000000ff
    5.34 +#define	HPET_ID_NUMBER_SHIFT	8
    5.35 +
    5.36 +#define HPET_ID_VENDOR_SHIFT	16
    5.37 +#define HPET_ID_VENDOR_8086	0x8086
    5.38 +
    5.39 +#define HPET_CFG_ENABLE	0x001
    5.40 +#define HPET_CFG_LEGACY	0x002
    5.41 +#define	HPET_LEGACY_8254	2
    5.42 +#define	HPET_LEGACY_RTC		8
    5.43 +
    5.44 +#define HPET_TN_ENABLE		0x004
    5.45 +#define HPET_TN_PERIODIC	0x008
    5.46 +#define HPET_TN_PERIODIC_CAP	0x010
    5.47 +#define HPET_TN_SETVAL		0x040
    5.48 +#define HPET_TN_32BIT		0x100
    5.49 +
    5.50 +#define hpet_read32(x)    \
    5.51 +    (*(volatile u32 *)(fix_to_virt(FIX_HPET_BASE) + (x)))
    5.52 +#define hpet_write32(y,x) \
    5.53 +    (*(volatile u32 *)(fix_to_virt(FIX_HPET_BASE) + (x)) = (y))
    5.54 +
    5.55 +#endif /* __X86_HPET_H__ */