force HPET support on buggy NVidia-based machines
PATCH 1/1 force HPET support on buggy NVidia-based machines
While playing around with some cpufreq issues, I found out that Xen unstable is currently unable to use the HPET timer of my NVidia Nforce Pro-based machine.
Some research on the net revealed that quite a lot dual socket machines (i.e. workstations and small servers from Dell and HP) don't provide correct ACPI information about this timer, even though the HPET is present and functional. Very recent Linux kernels (starting from 2.6.23(?)) as well as LinuxBIOS therefore provide a workaround to enable the HPET anyway by scanning the PCI bus for suspicious devices and querying them directly.
I've ported a part of this workaround to Xen. To enable it, apply the patch below and pass the cmd line arg "clocksource=hpet_nv" to Xen. This patch currently only covers some NVidia chipsets with the PCI ids shown in the patch.Other chipsets may need a similar procedure. The original Linux source even covers Intel (ICH4) and VIA chipsets. The patch below has been tested on my Tyan K8SE mainboard using a NForce Pro 2200 chipset and does it's job without woes so far.
I'm not sure if patches like this one are really a good idea for Xen, but maybe it helps some other people to run Xen more smoothly on their development machines.
Regards,
Holger
xen/arch/x86/time.c +129 -0
@@ -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") )
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH] force HPET support on buggy NVidia-basedmachines
Quoted 3 lines
I'm not sure if patches like this one are really a good idea for Xen, but maybe it helps some other people to run Xen more smoothly on their development machines.
Besides having reservations about this kind of change in general, your workaround looks functionally quite different from the Linux one, despite you having said that you cloned it from that code. Any reason for this?
Jan
Re: [PATCH] force HPET support on buggy NVidia-basedmachines
Quoted 4 lines
Besides having reservations about this kind of change in general, your workaround looks functionally quite different from the Linux one, despite you having said that you cloned it from that code. Any reason for this?
My patch is based on this one: http://lkml.org/lkml/2007/4/17/354
Some minor changes were necessary to resolve some dependencies from the Linux kernel. Finally, I did not include any Intel or VIA related stuff, as I'm not able to test it due to the lack of appropriate hardware.
Regards,
Holger
Re: [PATCH] force HPET support on buggyNVidia-basedmachines
Quoted 9 lines
Quoted 5 lines
Quoted 1 line
Holger Steinhaus <[email protected]> 25.01.08 12:53 >>>
Besides having reservations about this kind of change in general, your workaround looks functionally quite different from the Linux one, despite you having said that you cloned it from that code. Any reason for this?
My patch is based on this one: http://lkml.org/lkml/2007/4/17/354
Some minor changes were necessary to resolve some dependencies from the Linux kernel. Finally, I did not include any Intel or VIA related stuff, as I'm not able to test it due to the lack of appropriate hardware.
But this afaict never made it into any Linux version; I checked 2.6.24 and the workaround there looks different (and without knowing any chipset details it seems to me that both approaches have some weaknesses).
Jan