Skip to contentSkip to conversation

force HPET support on buggy NVidia-based machines

PATCH In review Holger Steinhaus 2 participants 4 messages Jan 25, 2008

lore
Share & tools
lore
#0 lore raw

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
diff -r bf828db8d017 xen/arch/x86/time.c
@@ -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

#1 lore raw

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

#2 lore raw

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

#3 lore raw

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