aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/early-quirks.c
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2008-01-30 07:31:25 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:25 -0500
commitc6b48324325ffb637c3aafb2d795408febf40198 (patch)
tree11fd48bc4bbc2308f91865011679b31842e345f0 /arch/x86/kernel/early-quirks.c
parent41e191e85a122ad822deb7525a015410012e6c70 (diff)
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 <nhorman@tuxdriver.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/early-quirks.c')
-rw-r--r--arch/x86/kernel/early-quirks.c86
1 files changed, 65 insertions, 21 deletions
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 88bb83ec895f..b55258e49208 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -21,7 +21,30 @@
21#include <asm/gart.h> 21#include <asm/gart.h>
22#endif 22#endif
23 23
24static void __init via_bugs(void) 24static void __init fix_hypertransport_config(int num, int slot, int func)
25{
26 u32 htcfg;
27 /*
28 * we found a hypertransport bus
29 * make sure that we are broadcasting
30 * interrupts to all cpus on the ht bus
31 * if we're using extended apic ids
32 */
33 htcfg = read_pci_config(num, slot, func, 0x68);
34 if (htcfg & (1 << 18)) {
35 printk(KERN_INFO "Detected use of extended apic ids on hypertransport bus\n");
36 if ((htcfg & (1 << 17)) == 0) {
37 printk(KERN_INFO "Enabling hypertransport extended apic interrupt broadcast\n");
38 printk(KERN_INFO "Note this is a bios bug, please contact your hw vendor\n");
39 htcfg |= (1 << 17);
40 write_pci_config(num, slot, func, 0x68, htcfg);
41 }
42 }
43
44
45}
46
47static void __init via_bugs(int num, int slot, int func)
25{ 48{
26#ifdef CONFIG_GART_IOMMU 49#ifdef CONFIG_GART_IOMMU
27 if ((end_pfn > MAX_DMA32_PFN || force_iommu) && 50 if ((end_pfn > MAX_DMA32_PFN || force_iommu) &&
@@ -44,7 +67,7 @@ static int __init nvidia_hpet_check(struct acpi_table_header *header)
44#endif /* CONFIG_X86_IO_APIC */ 67#endif /* CONFIG_X86_IO_APIC */
45#endif /* CONFIG_ACPI */ 68#endif /* CONFIG_ACPI */
46 69
47static void __init nvidia_bugs(void) 70static void __init nvidia_bugs(int num, int slot, int func)
48{ 71{
49#ifdef CONFIG_ACPI 72#ifdef CONFIG_ACPI
50#ifdef CONFIG_X86_IO_APIC 73#ifdef CONFIG_X86_IO_APIC
@@ -72,7 +95,7 @@ static void __init nvidia_bugs(void)
72 95
73} 96}
74 97
75static void __init ati_bugs(void) 98static void __init ati_bugs(int num, int slot, int func)
76{ 99{
77#ifdef CONFIG_X86_IO_APIC 100#ifdef CONFIG_X86_IO_APIC
78 if (timer_over_8254 == 1) { 101 if (timer_over_8254 == 1) {
@@ -83,15 +106,27 @@ static void __init ati_bugs(void)
83#endif 106#endif
84} 107}
85 108
109#define QFLAG_APPLY_ONCE 0x1
110#define QFLAG_APPLIED 0x2
111#define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
86struct chipset { 112struct chipset {
87 u16 vendor; 113 u32 vendor;
88 void (*f)(void); 114 u32 device;
115 u32 class;
116 u32 class_mask;
117 u32 flags;
118 void (*f)(int num, int slot, int func);
89}; 119};
90 120
91static struct chipset early_qrk[] __initdata = { 121static struct chipset early_qrk[] __initdata = {
92 { PCI_VENDOR_ID_NVIDIA, nvidia_bugs }, 122 { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
93 { PCI_VENDOR_ID_VIA, via_bugs }, 123 PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs },
94 { PCI_VENDOR_ID_ATI, ati_bugs }, 124 { PCI_VENDOR_ID_VIA, PCI_ANY_ID,
125 PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
126 { PCI_VENDOR_ID_ATI, PCI_ANY_ID,
127 PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, ati_bugs },
128 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
129 PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
95 {} 130 {}
96}; 131};
97 132
@@ -106,27 +141,36 @@ void __init early_quirks(void)
106 for (num = 0; num < 32; num++) { 141 for (num = 0; num < 32; num++) {
107 for (slot = 0; slot < 32; slot++) { 142 for (slot = 0; slot < 32; slot++) {
108 for (func = 0; func < 8; func++) { 143 for (func = 0; func < 8; func++) {
109 u32 class; 144 u16 class;
110 u32 vendor; 145 u16 vendor;
146 u16 device;
111 u8 type; 147 u8 type;
112 int i; 148 int i;
113 class = read_pci_config(num,slot,func, 149
150 class = read_pci_config_16(num,slot,func,
114 PCI_CLASS_REVISION); 151 PCI_CLASS_REVISION);
115 if (class == 0xffffffff) 152 if (class == 0xffff)
116 break; 153 break;
117 154
118 if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) 155 vendor = read_pci_config_16(num, slot, func,
119 continue;
120
121 vendor = read_pci_config(num, slot, func,
122 PCI_VENDOR_ID); 156 PCI_VENDOR_ID);
123 vendor &= 0xffff;
124 157
125 for (i = 0; early_qrk[i].f; i++) 158 device = read_pci_config_16(num, slot, func,
126 if (early_qrk[i].vendor == vendor) { 159 PCI_DEVICE_ID);
127 early_qrk[i].f(); 160
128 return; 161 for(i=0;early_qrk[i].f != NULL;i++) {
162 if (((early_qrk[i].vendor == PCI_ANY_ID) ||
163 (early_qrk[i].vendor == vendor)) &&
164 ((early_qrk[i].device == PCI_ANY_ID) ||
165 (early_qrk[i].device == device)) &&
166 (!((early_qrk[i].class ^ class) &
167 early_qrk[i].class_mask))) {
168 if ((early_qrk[i].flags & QFLAG_DONE) != QFLAG_DONE)
169 early_qrk[i].f(num, slot, func);
170 early_qrk[i].flags |= QFLAG_APPLIED;
171
129 } 172 }
173 }
130 174
131 type = read_pci_config_byte(num, slot, func, 175 type = read_pci_config_byte(num, slot, func,
132 PCI_HEADER_TYPE); 176 PCI_HEADER_TYPE);