diff -r bf828db8d017 xen/arch/x86/time.c --- a/xen/arch/x86/time.c Thu Jan 17 16:39:14 2008 +0000 +++ b/xen/arch/x86/time.c Sat Jan 19 23:51:24 2008 +0100 @@ -320,6 +320,130 @@ static u32 read_hpet_count(void) return hpet_read32(HPET_COUNTER); } +#define PDprintk(x...) + +static inline u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset) +{ + u32 v; + outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); + v = inl(0xcfc); + if (v != 0xffffffff) + PDprintk("%x reading 4 from %x: %x\n", slot, offset, v); + return v; +} + +static inline u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset) +{ + u8 v; + outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); + v = inb(0xcfc + (offset&3)); + PDprintk("%x reading 1 from %x: %x\n", slot, offset, v); + return v; +} + + +static void detect_nforce_hpet(int num, int slot, int func) +{ + u32 addr; + + addr = read_pci_config(num, slot, func, 0x44); + if (!addr) { + return; + } + + hpet_address = addr; + printk(KERN_INFO "NVidia quirk. Enabled hidden HPET that BIOS had " + "configured at base: %#x\n", addr); +} + +struct pci_entry { + u16 class; + u16 vendor; + u16 device; + void (*f)(int num, int slot, int func); +}; + +#define PCI_HEADER_TYPE 0x0e +#define PCI_VENDOR_ID 0x00 +#define PCI_CLASS_REVISION 0x08 +#define PCI_CLASS_BRIDGE_ISA 0x0601 +#define PCI_VENDOR_ID_NVIDIA 0x10de + + +static struct pci_entry nforce_hpet_chips[] __initdata = { + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0050, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0051, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0360, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0361, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0362, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0363, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0364, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0365, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0366, detect_nforce_hpet }, + { PCI_CLASS_BRIDGE_ISA, PCI_VENDOR_ID_NVIDIA, 0x0367, detect_nforce_hpet }, + {} +}; + + +void early_pci_scan(struct pci_entry matching[]) +{ + int num, slot, func; + + /* Poor man's PCI discovery */ + for (num = 0; num < 32; num++) { + for (slot = 0; slot < 32; slot++) { + for (func = 0; func < 8; func++) { + u32 class; + u32 vendor; + u8 type; + int i; + class = read_pci_config(num,slot,func, + PCI_CLASS_REVISION); + if (class == 0xffffffff) + break; + + class >>= 16; + + vendor = read_pci_config(num, slot, func, + PCI_VENDOR_ID); + + for (i = 0; matching[i].f; i++) { + if (class != matching[i].class) + continue; + + if ((vendor & 0xffff) != matching[i].vendor) + continue; + + if (matching[i].device != 0xffff && + (vendor >> 16) != matching[i].device) + continue; + + matching[i].f(num, slot, func); + return; + } + + /* No multi-function device? */ + type = read_pci_config_byte(num,slot,func, + PCI_HEADER_TYPE); + if (!(type & 0x80)) + break; + } + } + } +} + +static int enable_nvidia_hpet(void) +{ + if (hpet_address) + return 0; + + early_pci_scan(nforce_hpet_chips); + + return hpet_address != 0; +} + + + static int init_hpet(struct platform_timesource *pts) { u64 hpet_rate; @@ -540,6 +664,11 @@ static void init_platform_timer(void) rc = (init_pit(pts), 1); else if ( !strcmp(opt_clocksource, "hpet") ) rc = init_hpet(pts); + else if ( !strcmp(opt_clocksource, "hpet_nv") ) + { + enable_nvidia_hpet(); + rc = init_hpet(pts); + } else if ( !strcmp(opt_clocksource, "cyclone") ) rc = init_cyclone(pts); else if ( !strcmp(opt_clocksource, "acpi") )