* [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards
@ 2007-04-16 7:21 Mikko Tiihonen
2007-04-16 11:36 ` Krzysztof Halasa
2007-04-16 19:24 ` Andi Kleen
0 siblings, 2 replies; 12+ messages in thread
From: Mikko Tiihonen @ 2007-04-16 7:21 UTC (permalink / raw)
To: clemens, bob.picco; +Cc: linux-kernel, Andrew Morton
Enables HPET for NVidia motherboards with broken BIOS. The patch reads
the HPET address from the pci config space. The patch should also work
if ACPI is disabled.
The HPET search is done in early-quirks because even
DECLARE_PCI_FIXUP_EARLY was too late. If the new quirk causes problems
it can be disabled with the nohpet boot option.
The patch assumes that the BIOS has done the basic setup of HPET, but
has not published the result in ACPI tables. This is at least true for
some Asus and Gigabyte motherboards.
Patch is against 2.6.21-rc6-git7 but should apply cleanly to most
kernels.
Signed-off-by: Mikko Tiihonen <mikko.tiihonen@iki.fi>
---
It looks probable that most NVidia chipsets have the HPET address at
0x44. It might be possible to enable the HPET even if BIOS did not
initialize it properly by writing the wanted address there. Some other
pci config space bits might need to be fiddled around too, most likely
candidates are 0x74 bit 2 and 0xA3 bit ?. One or both of them have been
identified to change in some motherboards when HPET is enabled/disabled
in BIOS.
--- arch/x86_64/kernel/early-quirks.c.orig 2007-04-16 01:30:33.000000000 +0300
+++ arch/x86_64/kernel/early-quirks.c 2007-04-16 01:27:23.000000000 +0300
@@ -15,6 +15,7 @@
#include <asm/pci-direct.h>
#include <asm/proto.h>
#include <asm/dma.h>
+#include <linux/bootmem.h>
static void __init via_bugs(void)
{
@@ -36,6 +37,104 @@ static int __init nvidia_hpet_check(stru
}
#endif
+#ifdef CONFIG_HPET
+
+static u32 nvidia_hpet_chips[] __initdata = {
+ /* ISA Bridge */
+ PCI_VENDOR_ID_NVIDIA | (0x0050 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0051 << 16),
+ /* LPC Bridge */
+ PCI_VENDOR_ID_NVIDIA | (0x0360 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0361 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0362 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0363 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0364 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0365 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0366 << 16),
+ PCI_VENDOR_ID_NVIDIA | (0x0367 << 16),
+ 0,
+};
+
+static int __init force_enable_nvidia_hpet(void)
+{
+ int num, slot, func;
+ u32 addr;
+ struct resource *hpet_res;
+
+ if (hpet_address || nohpet)
+ return 0;
+
+ /* 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;
+ vendor = read_pci_config(num, slot, func,
+ PCI_VENDOR_ID);
+
+ for (i = 0; nvidia_hpet_chips[i]; i++)
+ if (nvidia_hpet_chips[i] == vendor) {
+ goto found;
+ }
+
+ type = read_pci_config_byte(num, slot, func,
+ PCI_HEADER_TYPE);
+ if (!(type & 0x80))
+ break;
+ }
+ }
+ }
+ return 0;
+
+ found:
+ addr = read_pci_config(num, slot, func, 0x44);
+ if (!addr) {
+ return 0;
+ }
+
+#define HPET_RESOURCE_NAME_SIZE 12
+ hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
+ if (!hpet_res) {
+ /* We could try writing to the 0x44 and see if that is enough
+ * to enable HPET even if BIOS did not initialize it.
+ */
+ printk(KERN_INFO "HPET not set up by BIOS.\n");
+ return 0;
+ }
+
+ memset(hpet_res, 0, sizeof(*hpet_res));
+ hpet_res->name = (void *)&hpet_res[1];
+ hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ strncpy((char *)hpet_res->name, "NVidia HPET",
+ HPET_RESOURCE_NAME_SIZE);
+ hpet_res->start = addr;
+ hpet_res->end = hpet_res->start + HPET_MMAP_SIZE - 1;
+
+ if (request_resource(&iomem_resource, hpet_res)) {
+ printk(KERN_INFO "NVidia quirk failed. Could not "
+ "reserve resources for HPET at base: %#x\n", addr);
+ return 0;
+ }
+
+ hpet_address = addr;
+ printk(KERN_INFO "NVidia quirk. Enabled hidden HPET that BIOS had "
+ "configured at base: %#x\n", addr);
+ return 1;
+}
+#else
+static int __init force_enable_nvidia_hpet(void)
+{
+ return 0;
+}
+#endif
+
static void __init nvidia_bugs(void)
{
#ifdef CONFIG_ACPI
@@ -50,6 +149,10 @@ static void __init nvidia_bugs(void)
return;
if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) {
+ if (force_enable_nvidia_hpet()) {
+ return;
+ }
+
acpi_skip_timer_override = 1;
printk(KERN_INFO "Nvidia board "
"detected. Ignoring ACPI "
@@ -57,6 +160,8 @@ static void __init nvidia_bugs(void)
printk(KERN_INFO "If you got timer trouble "
"try acpi_use_timer_override\n");
}
+#else
+ force_enable_nvidia_hpet();
#endif
/* RED-PEN skip them on mptables too? */
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-16 7:21 [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards Mikko Tiihonen @ 2007-04-16 11:36 ` Krzysztof Halasa 2007-04-16 13:33 ` Mikko Tiihonen 2007-04-16 19:24 ` Andi Kleen 1 sibling, 1 reply; 12+ messages in thread From: Krzysztof Halasa @ 2007-04-16 11:36 UTC (permalink / raw) To: Mikko Tiihonen; +Cc: clemens, bob.picco, linux-kernel, Andrew Morton Mikko Tiihonen <mikko.tiihonen@iki.fi> writes: > Enables HPET for NVidia motherboards with broken BIOS. The patch reads > the HPET address from the pci config space. The patch should also work > if ACPI is disabled. > > The HPET search is done in early-quirks because even > DECLARE_PCI_FIXUP_EARLY was too late. If the new quirk causes problems > it can be disabled with the nohpet boot option. > > The patch assumes that the BIOS has done the basic setup of HPET, but > has not published the result in ACPI tables. This is at least true for > some Asus and Gigabyte motherboards. I think the code should only be enabled by its CONFIG_*. -- Krzysztof Halasa ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-16 11:36 ` Krzysztof Halasa @ 2007-04-16 13:33 ` Mikko Tiihonen 2007-04-17 11:26 ` Krzysztof Halasa 0 siblings, 1 reply; 12+ messages in thread From: Mikko Tiihonen @ 2007-04-16 13:33 UTC (permalink / raw) To: Krzysztof Halasa; +Cc: clemens, bob.picco, linux-kernel, Andrew Morton On Mon, 16 Apr 2007, Krzysztof Halasa wrote: > Mikko Tiihonen <mikko.tiihonen@iki.fi> writes: > >> Enables HPET for NVidia motherboards with broken BIOS. The patch reads >> the HPET address from the pci config space. The patch should also work >> if ACPI is disabled. >> >> The HPET search is done in early-quirks because even >> DECLARE_PCI_FIXUP_EARLY was too late. If the new quirk causes problems >> it can be disabled with the nohpet boot option. >> >> The patch assumes that the BIOS has done the basic setup of HPET, but >> has not published the result in ACPI tables. This is at least true for >> some Asus and Gigabyte motherboards. > > I think the code should only be enabled by its CONFIG_*. Currently the all the code is protected by CONFIG_HPET. Are you proposing to use for example CONFIG_HPET_NVIDIA instead? I think that the code should be safe even without it's own config option. It won't override values from ACPI tables and can still be disabled with nohpet boot option. Also all the code and data are __init. -Mikko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-16 13:33 ` Mikko Tiihonen @ 2007-04-17 11:26 ` Krzysztof Halasa 0 siblings, 0 replies; 12+ messages in thread From: Krzysztof Halasa @ 2007-04-17 11:26 UTC (permalink / raw) To: Mikko Tiihonen; +Cc: clemens, bob.picco, linux-kernel, Andrew Morton Mikko Tiihonen <mikko.tiihonen@iki.fi> writes: > Currently the all the code is protected by CONFIG_HPET. > Are you proposing to use for example CONFIG_HPET_NVIDIA instead? Something like that. CONFIG_HPET_NFORCE_DETECT maybe? > I think that the code should be safe even without it's own config option. Well, who knows. The hardware side (config bits) are probably safe and easy to verify, but depending on BIOS assigning address to inactive device seems risky. -- Krzysztof Halasa ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-16 7:21 [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards Mikko Tiihonen 2007-04-16 11:36 ` Krzysztof Halasa @ 2007-04-16 19:24 ` Andi Kleen 2007-04-16 21:28 ` Mikko Tiihonen 1 sibling, 1 reply; 12+ messages in thread From: Andi Kleen @ 2007-04-16 19:24 UTC (permalink / raw) To: Mikko Tiihonen; +Cc: clemens, bob.picco, linux-kernel, Andrew Morton Mikko Tiihonen <mikko.tiihonen@iki.fi> writes: > It looks probable that most NVidia chipsets have the HPET address at > 0x44. It might be possible to enable the HPET even if BIOS did not That seems like a dangerous assumption. If anything this needs to be keyed on specific PCI IDs. And the way you coded a recursive PCI scan is just .... <looking for words, censoring some that come to mind first> ... not nice. > initialize it properly by writing the wanted address there. Some other > pci config space bits might need to be fiddled around too, most likely > candidates are 0x74 bit 2 and 0xA3 bit ?. One or both of them have been > identified to change in some motherboards when HPET is enabled/disabled > in BIOS. Or just add a random generator and poke random bits? Should be roughly equivalent. Also there should be done anything here without confirmation from Nvidia that HPET is actually supposed to work. Sometimes hardware is disabled by BIOS because it is seriously broken (there was at least one other chipset that could corrupt your flash if you force enabled HPET in some steppings) -Andi ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-16 19:24 ` Andi Kleen @ 2007-04-16 21:28 ` Mikko Tiihonen 2007-04-16 21:40 ` Andi Kleen 0 siblings, 1 reply; 12+ messages in thread From: Mikko Tiihonen @ 2007-04-16 21:28 UTC (permalink / raw) To: Andi Kleen; +Cc: clemens, bob.picco, linux-kernel, Andrew Morton On Mon, 16 Apr 2007, Andi Kleen wrote: > Mikko Tiihonen <mikko.tiihonen@iki.fi> writes: > >> It looks probable that most NVidia chipsets have the HPET address at >> 0x44. It might be possible to enable the HPET even if BIOS did not > > That seems like a dangerous assumption. If anything this needs to be keyed > on specific PCI IDs. The patch contains a list of PCI IDs. Currently the CK804 and MCP55 have been verified to work. Other PCI IDs can be added if needed. > And the way you coded a recursive PCI scan is just .... <looking for words, censoring > some that come to mind first> ... not nice. I actually was more worried that someone might complain that the pci scanning is copy & paste code from end of the same file. I did try to use the generic pci functions first but because they insist on enabling interrupts they cannot be used this early. And this code needs to be run before the timer initialization. If you want I can submit a separate patch to move the ... not nice pci scanning code to pci directory under some early_pci_scan(u32 *pci_ids, hook) function. The same code was already cut&pasted in i386/kernel/acpi/earlyquik.c, in x86_64/kernel/aperture.c and in x86_64/kernel/early-quirks.c. Moving the uglyness to a central place would at least hide it from the casual browser. Or would a global flag that the pci scanning code checks to see if locks should be used or not be better? >> initialize it properly by writing the wanted address there. Some other >> pci config space bits might need to be fiddled around too, most likely >> candidates are 0x74 bit 2 and 0xA3 bit ?. One or both of them have been >> identified to change in some motherboards when HPET is enabled/disabled >> in BIOS. > > Or just add a random generator and poke random bits? Should be roughly > equivalent. Fair enough, that was just my written hope that some day someone might reverse engineer how HPET is enabled on NVidia chipsets. The patch does not try write to any registers so it should be safe? The code also properly checks that the memory area does not collide with any existing resource. I could of course add a check that there is a HPET at that address, but the hpet driver already checks it itself later and disabled itself it cannot see valid data. > Also there should be done anything here without confirmation from > Nvidia that HPET is actually supposed to work. Sometimes hardware > is disabled by BIOS because it is seriously broken (there was at least > one other chipset that could corrupt your flash if you force enabled > HPET in some steppings) I hope someone has some secret contacts at NVidia because they have not been very open with their chipsets. I looked at LinuxBios and their NForce4 chipset code had just had commented out code that wrote to 0x44 register. So obviously something more is needed. Even Intel just posted code a while ago that allows enabling HPET from a quirk even if BIOS did not set it up properly. Does anyone know how to _really_ test if HPET works properly (from user space for example). I've just tested with busylooping gettimeofday while changing the clocksource and measured the speed difference. We could then change the quirk to point to instructions on how to test the HPET manually and then request to submit the PCI ID. -Mikko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-16 21:28 ` Mikko Tiihonen @ 2007-04-16 21:40 ` Andi Kleen 2007-04-17 10:13 ` Mikko Tiihonen 2007-04-17 21:57 ` [PATCH v3] hpet: Detect " Mikko Tiihonen 0 siblings, 2 replies; 12+ messages in thread From: Andi Kleen @ 2007-04-16 21:40 UTC (permalink / raw) To: Mikko Tiihonen Cc: Andi Kleen, clemens, bob.picco, linux-kernel, Andrew Morton, Andy Currid On Tue, Apr 17, 2007 at 12:28:31AM +0300, Mikko Tiihonen wrote: > I actually was more worried that someone might complain that the pci > scanning is copy & paste code from end of the same file. I did try to use > the generic pci functions first but because they insist on enabling > interrupts they cannot be used this early. And this code needs to be run > before the timer initialization. Yes that's the issue. You're adding another PCI scanner copy'n'pasted from the caller of the function you're adding it to. See the problem? > If you want I can submit a separate patch to move the ... not nice pci > scanning code to pci directory under some early_pci_scan(u32 *pci_ids, > hook) function. The same code was already cut&pasted in That is what early-quirks is anyways. But the way to scan for multple things is not to add anther recursive scan, but to just extend or change the main loop. > >Also there should be done anything here without confirmation from > >Nvidia that HPET is actually supposed to work. Sometimes hardware > >is disabled by BIOS because it is seriously broken (there was at least > >one other chipset that could corrupt your flash if you force enabled > >HPET in some steppings) > > I hope someone has some secret contacts at NVidia because they have not > been very open with their chipsets. I looked at LinuxBios and their NForce4 > chipset code had just had commented out code that wrote to 0x44 register. > So obviously something more is needed. Andy, can you help please? There is interest in force enabling HPET on boards where the BIOS didn't chose too. We would need a list of PCI-IDs where this is safe to do and what bits to poke. Thanks. -Andi ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-16 21:40 ` Andi Kleen @ 2007-04-17 10:13 ` Mikko Tiihonen 2007-04-17 22:18 ` Andi Kleen 2007-04-17 21:57 ` [PATCH v3] hpet: Detect " Mikko Tiihonen 1 sibling, 1 reply; 12+ messages in thread From: Mikko Tiihonen @ 2007-04-17 10:13 UTC (permalink / raw) To: Andi Kleen; +Cc: linux-kernel On Mon, 16 Apr 2007, Andi Kleen wrote: > On Tue, Apr 17, 2007 at 12:28:31AM +0300, Mikko Tiihonen wrote: >> I actually was more worried that someone might complain that the pci >> scanning is copy & paste code from end of the same file. I did try to use >> the generic pci functions first but because they insist on enabling >> interrupts they cannot be used this early. And this code needs to be run >> before the timer initialization. > > Yes that's the issue. You're adding another PCI scanner copy'n'pasted > from the caller of the function you're adding it to. See the problem? I'll remove the duplicated scanning code in next patch version by creating a more general scanning code. >> If you want I can submit a separate patch to move the ... not nice pci >> scanning code to pci directory under some early_pci_scan(u32 *pci_ids, >> hook) function. The same code was already cut&pasted in > > That is what early-quirks is anyways. But the way to scan for multple > things is not to add anther recursive scan, but to just extend or > change the main loop. I don't think the quirk can avoid a recursive scan easily. It is supposed to be only run if the first scan finds nvidia chipset, does not detect acpi hpet and, as a last resort, tries to scan for the hpet manually to avoid enabling the original quirk. In more pictoresque way: scan-for-chipsets -> nvidia chipset found -> does acpi hpet exist -> did manual_hpet_quirk fail (new) -> enable acpi_skip_timer_override quirk It could be done in one scanning loop provided that it is quaranteed that the nvidia chipset is always before the the hpet quirk chip in pci hierarchy. Then the nvidia quirk needs to be split to two parts, of which the last part is run after all other quirks and to check if hpet quirk was ever activated. scan-for-pci-ids -> nvidia chipset id found -> does acpi hpet exist -> possibly_enable_acpi_skip_timer_override = 1 -> nvidia pci-id matching hpet chip found -> if possibly_enable_acpi_skip_timer_override -> did manual_hpet_quirk work -> possibly_enable_acpi_skip_timer_override = 0 if possibly_enable_acpi_skip_timer_override -> enable acpi_skip_timer_override quirk But I really do think that overall the first solution is better, even if it does a recursive scan. Assuming of course that stupid code duplication is removed. -Mikko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards 2007-04-17 10:13 ` Mikko Tiihonen @ 2007-04-17 22:18 ` Andi Kleen 0 siblings, 0 replies; 12+ messages in thread From: Andi Kleen @ 2007-04-17 22:18 UTC (permalink / raw) To: Mikko Tiihonen; +Cc: Andi Kleen, linux-kernel > It could be done in one scanning loop provided that it is quaranteed that > the nvidia chipset is always before the the hpet quirk chip in pci > hierarchy. Then the nvidia quirk needs to be split to two parts, of which You just only set flags for both in the scanning loop and then handle it after every device has been visited. It's a simple state machine. -Andi ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3] hpet: Detect hidden HPET on NVidia motherboards 2007-04-16 21:40 ` Andi Kleen 2007-04-17 10:13 ` Mikko Tiihonen @ 2007-04-17 21:57 ` Mikko Tiihonen 2007-04-20 22:41 ` Andrew Morton 1 sibling, 1 reply; 12+ messages in thread From: Mikko Tiihonen @ 2007-04-17 21:57 UTC (permalink / raw) To: Andi Kleen; +Cc: linux-kernel, Andrew Morton, Andy Currid Enables HPET for NVidia motherboards with broken BIOS. The patch reads the HPET address from the pci config space. The patch should also work if ACPI is disabled. The new quirk activates use of HPET only run if - CONFIG_HPET_NFORCE_DETECT is enabled - nohpet boot option is not set - main chipset is from NVidia - ACPI tables do not list HPET - matching PCI ID for device with HPET is found - BIOS has set up the HPET to some address - there is no other resource allocated at the HPET address This is true at least for some Asus, Gigabyte and DFI motherboards. Patch is against 2.6.21-rc6-git7 but should apply cleanly to most kernels. Signed-off-by: Mikko Tiihonen <mikko.tiihonen@iki.fi> --- Changes since v2: - removed duplicated pci scanning code and moved it to pci/early.c - added CONFIG_HPET_NFORCE_DETECT diff -uprN -X linux-2.6.21-rc6-git7/Documentation/dontdiff linux-2.6.21-rc6-git7/arch/i386/pci/early.c linux-2.6.21-rc6-git7.hpet/arch/i386/pci/early.c --- linux-2.6.21-rc6-git7/arch/i386/pci/early.c 2007-02-04 20:44:54.000000000 +0200 +++ linux-2.6.21-rc6-git7.hpet/arch/i386/pci/early.c 2007-04-18 00:25:35.000000000 +0300 @@ -57,3 +57,50 @@ int early_pci_allowed(void) return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) == PCI_PROBE_CONF1; } + +void __init 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; + } + } + } +} diff -uprN -X linux-2.6.21-rc6-git7/Documentation/dontdiff linux-2.6.21-rc6-git7/arch/x86_64/Kconfig linux-2.6.21-rc6-git7.hpet/arch/x86_64/Kconfig --- linux-2.6.21-rc6-git7/arch/x86_64/Kconfig 2007-04-15 13:34:28.000000000 +0300 +++ linux-2.6.21-rc6-git7.hpet/arch/x86_64/Kconfig 2007-04-17 23:53:18.000000000 +0300 @@ -453,6 +453,15 @@ config HPET_EMULATE_RTC bool "Provide RTC interrupt" depends on HPET_TIMER && RTC=y +config HPET_NFORCE_DETECT + bool "Detect HPET on NForce motherboards with broken BIOS" + depends on HPET_TIMER + default y + help + Some buggy BIOS implementations do not list HPET in ACPI + tables but still have the HPET enabled. This option allows + using HPET on such motherboards with NForce chipsets. + # Mark as embedded because too many people got it wrong. # The code disables itself when not needed. config IOMMU diff -uprN -X linux-2.6.21-rc6-git7/Documentation/dontdiff linux-2.6.21-rc6-git7/arch/x86_64/kernel/early-quirks.c linux-2.6.21-rc6-git7.hpet/arch/x86_64/kernel/early-quirks.c --- linux-2.6.21-rc6-git7/arch/x86_64/kernel/early-quirks.c 2007-04-18 00:27:26.000000000 +0300 +++ linux-2.6.21-rc6-git7.hpet/arch/x86_64/kernel/early-quirks.c 2007-04-17 23:02:16.000000000 +0300 @@ -15,8 +15,9 @@ #include <asm/pci-direct.h> #include <asm/proto.h> #include <asm/dma.h> +#include <linux/bootmem.h> -static void __init via_bugs(void) +static void __init via_bugs(int num, int slot, int func) { #ifdef CONFIG_IOMMU if ((end_pfn > MAX_DMA32_PFN || force_iommu) && @@ -36,7 +37,79 @@ static int __init nvidia_hpet_check(stru } #endif -static void __init nvidia_bugs(void) +#ifdef CONFIG_HPET_NFORCE_DETECT + +static void __init detect_nforce_hpet(int num, int slot, int func) +{ + u32 addr; + struct resource *hpet_res; + + addr = read_pci_config(num, slot, func, 0x44); + if (!addr) { + return; + } + +#define HPET_RESOURCE_NAME_SIZE 12 + hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE); + if (!hpet_res) { + /* We could try writing to the 0x44 and see if that is enough + * to enable HPET even if BIOS did not initialize it. + */ + printk(KERN_INFO "HPET not set up by BIOS.\n"); + return; + } + + memset(hpet_res, 0, sizeof(*hpet_res)); + hpet_res->name = (void *)&hpet_res[1]; + hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + strncpy((char *)hpet_res->name, "NVidia HPET", + HPET_RESOURCE_NAME_SIZE); + hpet_res->start = addr; + hpet_res->end = hpet_res->start + HPET_MMAP_SIZE - 1; + + if (request_resource(&iomem_resource, hpet_res)) { + printk(KERN_INFO "NVidia quirk failed. Could not " + "reserve resources for HPET at base: %#x\n", addr); + return; + } + + hpet_address = addr; + printk(KERN_INFO "NVidia quirk. Enabled hidden HPET that BIOS had " + "configured at base: %#x\n", addr); +} + +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 }, + {} +}; + +static bool __init enable_nvidia_hpet(void) +{ + if (hpet_address || nohpet) + return 0; + + early_pci_scan(nforce_hpet_chips); + + return hpet_address != 0; +} + +#else +static bool __init enable_nvidia_hpet(void) +{ + return 0; +} +#endif + +static void __init nvidia_bugs(int num, int slot, int func) { #ifdef CONFIG_ACPI /* @@ -50,6 +123,10 @@ static void __init nvidia_bugs(void) return; if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) { + if (enable_nvidia_hpet()) { + return; + } + acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " "detected. Ignoring ACPI " @@ -57,12 +134,14 @@ static void __init nvidia_bugs(void) printk(KERN_INFO "If you got timer trouble " "try acpi_use_timer_override\n"); } +#else + enable_nvidia_hpet(); #endif /* RED-PEN skip them on mptables too? */ } -static void __init ati_bugs(void) +static void __init ati_bugs(int num, int slot, int func) { if (timer_over_8254 == 1) { timer_over_8254 = 0; @@ -71,7 +150,7 @@ static void __init ati_bugs(void) } } -static void intel_bugs(void) +static void intel_bugs(int num, int slot, int func) { u16 device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID); @@ -83,57 +162,18 @@ static void intel_bugs(void) #endif } -struct chipset { - u16 vendor; - void (*f)(void); -}; - -static struct chipset early_qrk[] __initdata = { - { PCI_VENDOR_ID_NVIDIA, nvidia_bugs }, - { PCI_VENDOR_ID_VIA, via_bugs }, - { PCI_VENDOR_ID_ATI, ati_bugs }, - { PCI_VENDOR_ID_INTEL, intel_bugs}, +static struct pci_entry early_qrk[] __initdata = { + { PCI_CLASS_BRIDGE_PCI, PCI_VENDOR_ID_NVIDIA, 0xffff, nvidia_bugs }, + { PCI_CLASS_BRIDGE_PCI, PCI_VENDOR_ID_VIA, 0xffff, via_bugs }, + { PCI_CLASS_BRIDGE_PCI, PCI_VENDOR_ID_ATI, 0xffff, ati_bugs }, + { PCI_CLASS_BRIDGE_PCI, PCI_VENDOR_ID_INTEL, 0xffff, intel_bugs}, {} }; void __init early_quirks(void) { - int num, slot, func; - if (!early_pci_allowed()) return; - /* 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; - - if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) - continue; - - vendor = read_pci_config(num, slot, func, - PCI_VENDOR_ID); - vendor &= 0xffff; - - for (i = 0; early_qrk[i].f; i++) - if (early_qrk[i].vendor == vendor) { - early_qrk[i].f(); - return; - } - - type = read_pci_config_byte(num, slot, func, - PCI_HEADER_TYPE); - if (!(type & 0x80)) - break; - } - } - } + early_pci_scan(early_qrk); } diff -uprN -X linux-2.6.21-rc6-git7/Documentation/dontdiff linux-2.6.21-rc6-git7/include/asm-x86_64/pci-direct.h linux-2.6.21-rc6-git7.hpet/include/asm-x86_64/pci-direct.h --- linux-2.6.21-rc6-git7/include/asm-x86_64/pci-direct.h 2007-02-04 20:44:54.000000000 +0200 +++ linux-2.6.21-rc6-git7.hpet/include/asm-x86_64/pci-direct.h 2007-04-17 23:04:12.000000000 +0300 @@ -6,6 +6,20 @@ /* Direct PCI access. This is used for PCI accesses in early boot before the PCI subsystem works. */ +/** + * struct pci_entry - simple pci device matching struct with callback + * @class: class to match - mandatory + * @vendor: vendor to match - mandatory + * @device: device to match - use 0xffff to ignore + * @f: callback function - called on matching entry + */ +struct pci_entry { + u16 class; + u16 vendor; + u16 device; + void (*f)(int num, int slot, int func); +}; + extern u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset); extern u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset); extern u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset); @@ -13,5 +27,6 @@ extern void write_pci_config(u8 bus, u8 extern void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val); extern int early_pci_allowed(void); +extern void early_pci_scan(struct pci_entry matching[]); #endif ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3] hpet: Detect hidden HPET on NVidia motherboards 2007-04-17 21:57 ` [PATCH v3] hpet: Detect " Mikko Tiihonen @ 2007-04-20 22:41 ` Andrew Morton 2007-04-21 9:50 ` Andi Kleen 0 siblings, 1 reply; 12+ messages in thread From: Andrew Morton @ 2007-04-20 22:41 UTC (permalink / raw) To: Mikko Tiihonen; +Cc: Andi Kleen, linux-kernel, Andy Currid On Wed, 18 Apr 2007 00:57:48 +0300 Mikko Tiihonen <mikko.tiihonen@iki.fi> wrote: > Enables HPET for NVidia motherboards with broken BIOS. The patch reads > the HPET address from the pci config space. The patch should also work > if ACPI is disabled. > > The new quirk activates use of HPET only run if > - CONFIG_HPET_NFORCE_DETECT is enabled > - nohpet boot option is not set > - main chipset is from NVidia > - ACPI tables do not list HPET > - matching PCI ID for device with HPET is found > - BIOS has set up the HPET to some address > - there is no other resource allocated at the HPET address > > This is true at least for some Asus, Gigabyte and DFI motherboards. > > Patch is against 2.6.21-rc6-git7 but should apply cleanly to most > kernels. I looked at applying this but a) there have been rather a lot of underlying changes in Andi's devel tree and b) we still haven't heard from Andy? ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3] hpet: Detect hidden HPET on NVidia motherboards 2007-04-20 22:41 ` Andrew Morton @ 2007-04-21 9:50 ` Andi Kleen 0 siblings, 0 replies; 12+ messages in thread From: Andi Kleen @ 2007-04-21 9:50 UTC (permalink / raw) To: Andrew Morton; +Cc: Mikko Tiihonen, Andi Kleen, linux-kernel, Andy Currid > a) there have been rather a lot of underlying changes in Andi's devel tree and > > b) we still haven't heard from Andy? c) my original review comments haven't been completely addressed. -Andi ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2007-04-21 9:51 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-04-16 7:21 [PATCH v2] hpet: Enable hidden HPET on NVidia motherboards Mikko Tiihonen 2007-04-16 11:36 ` Krzysztof Halasa 2007-04-16 13:33 ` Mikko Tiihonen 2007-04-17 11:26 ` Krzysztof Halasa 2007-04-16 19:24 ` Andi Kleen 2007-04-16 21:28 ` Mikko Tiihonen 2007-04-16 21:40 ` Andi Kleen 2007-04-17 10:13 ` Mikko Tiihonen 2007-04-17 22:18 ` Andi Kleen 2007-04-17 21:57 ` [PATCH v3] hpet: Detect " Mikko Tiihonen 2007-04-20 22:41 ` Andrew Morton 2007-04-21 9:50 ` Andi Kleen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox