Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c6b48324325ffb637c3aafb2d795408febf40198
Commit:     c6b48324325ffb637c3aafb2d795408febf40198
Parent:     41e191e85a122ad822deb7525a015410012e6c70
Author:     Neil Horman <[EMAIL PROTECTED]>
AuthorDate: Wed Jan 30 13:31:25 2008 +0100
Committer:  Ingo Molnar <[EMAIL PROTECTED]>
CommitDate: Wed Jan 30 13:31:25 2008 +0100

    x86, kexec: force x86 arches to boot kdump kernels on boot cpu
    
    Recently a kdump bug was discovered in which a system would hang inside
    calibrate_delay during the booting of the kdump kernel.  This was caused
    by the fact that the jiffies counter was not being incremented during
    timer calibration.  The root cause of this problem was found to be a
    bios misconfiguration of the hypertransport bus.  On system affected by
    this hang, the bios had assigned APIC ids which used extended apic bits
    (more than the nominal 4 bit ids's), but failed to configure bit 17 of
    the hypertransport transaction config register, which indicated that the
    mask for the destination field of interrupt packets accross the ht bus
    (see section 3.3.9 of
    
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF).
    If a crash occurs on a cpu with an APIC id that extends beyond 4 bits,
    it will not recieve interrupts during the kdump kernel boot, and this
    hang will be the result.  The fix is to add this patch, whcih add an
    early pci quirk check, to forcibly enable this bit in the httcfg
    register.  This enables all cpus on a system to receive interrupts, and
    allows kdump kernel bootup to procede normally.
    
    Signed-off-by: Neil Horman <[EMAIL PROTECTED]>
    Signed-off-by: Ingo Molnar <[EMAIL PROTECTED]>
    Signed-off-by: Thomas Gleixner <[EMAIL PROTECTED]>
---
 arch/x86/kernel/early-quirks.c |   86 ++++++++++++++++++++++++++++++----------
 1 files changed, 65 insertions(+), 21 deletions(-)

diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 88bb83e..b55258e 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -21,7 +21,30 @@
 #include <asm/gart.h>
 #endif
 
-static void __init via_bugs(void)
+static void __init fix_hypertransport_config(int num, int slot, int func)
+{
+       u32 htcfg;
+       /*
+        * we found a hypertransport bus
+        * make sure that we are broadcasting
+        * interrupts to all cpus on the ht bus
+        * if we're using extended apic ids
+        */
+       htcfg = read_pci_config(num, slot, func, 0x68);
+       if (htcfg & (1 << 18)) {
+               printk(KERN_INFO "Detected use of extended apic ids on 
hypertransport bus\n");
+               if ((htcfg & (1 << 17)) == 0) {
+                       printk(KERN_INFO "Enabling hypertransport extended apic 
interrupt broadcast\n");
+                       printk(KERN_INFO "Note this is a bios bug, please 
contact your hw vendor\n");
+                       htcfg |= (1 << 17);
+                       write_pci_config(num, slot, func, 0x68, htcfg);
+               }
+       }
+
+
+}
+
+static void __init via_bugs(int  num, int slot, int func)
 {
 #ifdef CONFIG_GART_IOMMU
        if ((end_pfn > MAX_DMA32_PFN ||  force_iommu) &&
@@ -44,7 +67,7 @@ static int __init nvidia_hpet_check(struct acpi_table_header 
*header)
 #endif /* CONFIG_X86_IO_APIC */
 #endif /* CONFIG_ACPI */
 
-static void __init nvidia_bugs(void)
+static void __init nvidia_bugs(int num, int slot, int func)
 {
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_X86_IO_APIC
@@ -72,7 +95,7 @@ static void __init nvidia_bugs(void)
 
 }
 
-static void __init ati_bugs(void)
+static void __init ati_bugs(int num, int slot, int func)
 {
 #ifdef CONFIG_X86_IO_APIC
        if (timer_over_8254 == 1) {
@@ -83,15 +106,27 @@ static void __init ati_bugs(void)
 #endif
 }
 
+#define QFLAG_APPLY_ONCE       0x1
+#define QFLAG_APPLIED          0x2
+#define QFLAG_DONE             (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
 struct chipset {
-       u16 vendor;
-       void (*f)(void);
+       u32 vendor;
+       u32 device;
+       u32 class;
+       u32 class_mask;
+       u32 flags;
+       void (*f)(int num, int slot, int func);
 };
 
 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_NVIDIA, PCI_ANY_ID,
+         PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs },
+       { PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+         PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
+       { PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+         PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, ati_bugs },
+       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
+         PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
        {}
 };
 
@@ -106,27 +141,36 @@ void __init early_quirks(void)
        for (num = 0; num < 32; num++) {
                for (slot = 0; slot < 32; slot++) {
                        for (func = 0; func < 8; func++) {
-                               u32 class;
-                               u32 vendor;
+                               u16 class;
+                               u16 vendor;
+                               u16 device;
                                u8 type;
                                int i;
-                               class = read_pci_config(num,slot,func,
+
+                               class = read_pci_config_16(num,slot,func,
                                                        PCI_CLASS_REVISION);
-                               if (class == 0xffffffff)
+                               if (class == 0xffff)
                                        break;
 
-                               if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
-                                       continue;
-
-                               vendor = read_pci_config(num, slot, func,
+                               vendor = read_pci_config_16(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;
+                               device = read_pci_config_16(num, slot, func,
+                                                       PCI_DEVICE_ID);
+
+                               for(i=0;early_qrk[i].f != NULL;i++) {
+                                       if (((early_qrk[i].vendor == 
PCI_ANY_ID) ||
+                                           (early_qrk[i].vendor == vendor)) &&
+                                          ((early_qrk[i].device == PCI_ANY_ID) 
||
+                                           (early_qrk[i].device == device)) &&
+                                          (!((early_qrk[i].class ^ class) &
+                                            early_qrk[i].class_mask))) {
+                                               if ((early_qrk[i].flags & 
QFLAG_DONE) != QFLAG_DONE)
+                                                       early_qrk[i].f(num, 
slot, func);
+                                               early_qrk[i].flags |= 
QFLAG_APPLIED;
+
                                        }
+                               }
 
                                type = read_pci_config_byte(num, slot, func,
                                                            PCI_HEADER_TYPE);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to