[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.