Commit 0637a70a5db98182d9ad3d6ae1ee30acf20afde9

Authored by Andi Kleen
Committed by Andi Kleen
1 parent 8f60774a11

[PATCH] x86: Allow disabling early pci scans with pci=noearly or disallowing conf1

Some buggy systems can machine check when config space accesses
happen for some non existent devices.  i386/x86-64 do some early
device scans that might trigger this. Allow pci=noearly to disable
this. Also when type 1 is disabling also don't do any early
accesses which are always type1.

This moves the pci= configuration parsing to be a early parameter.
I don't think this can break anything because it only changes
a single global that is only used by PCI.

Cc: gregkh@suse.de
Cc: Trammell Hudson <hudson@osresearch.net>

Signed-off-by: Andi Kleen <ak@suse.de>

Showing 12 changed files with 41 additions and 6 deletions Side-by-side Diff

Documentation/kernel-parameters.txt
... ... @@ -1240,7 +1240,11 @@
1240 1240 bootloader. This is currently used on
1241 1241 IXP2000 systems where the bus has to be
1242 1242 configured a certain way for adjunct CPUs.
1243   -
  1243 + noearly [X86] Don't do any early type 1 scanning.
  1244 + This might help on some broken boards which
  1245 + machine check when some devices' config space
  1246 + is read. But various workarounds are disabled
  1247 + and some IOMMU drivers will not work.
1244 1248 pcmv= [HW,PCMCIA] BadgePAD 4
1245 1249  
1246 1250 pd. [PARIDE]
arch/i386/kernel/acpi/earlyquirk.c
... ... @@ -48,7 +48,11 @@
48 48 int num, slot, func;
49 49  
50 50 /* Assume the machine supports type 1. If not it will
51   - always read ffffffff and should not have any side effect. */
  51 + always read ffffffff and should not have any side effect.
  52 + Actually a few buggy systems can machine check. Allow the user
  53 + to disable it by command line option at least -AK */
  54 + if (!early_pci_allowed())
  55 + return;
52 56  
53 57 /* Poor man's PCI discovery */
54 58 for (num = 0; num < 32; num++) {
arch/i386/pci/common.c
... ... @@ -242,6 +242,10 @@
242 242 acpi_noirq_set();
243 243 return NULL;
244 244 }
  245 + else if (!strcmp(str, "noearly")) {
  246 + pci_probe |= PCI_PROBE_NOEARLY;
  247 + return NULL;
  248 + }
245 249 #ifndef CONFIG_X86_VISWS
246 250 else if (!strcmp(str, "usepirqmask")) {
247 251 pci_probe |= PCI_USE_PIRQ_MASK;
arch/i386/pci/early.c
1 1 #include <linux/kernel.h>
  2 +#include <linux/pci.h>
2 3 #include <asm/pci-direct.h>
3 4 #include <asm/io.h>
  5 +#include "pci.h"
4 6  
5 7 /* Direct PCI access. This is used for PCI accesses in early boot before
6 8 the PCI subsystem works. */
... ... @@ -41,5 +43,11 @@
41 43 PDprintk("%x writing to %x: %x\n", slot, offset, val);
42 44 outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
43 45 outl(val, 0xcfc);
  46 +}
  47 +
  48 +int early_pci_allowed(void)
  49 +{
  50 + return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) ==
  51 + PCI_PROBE_CONF1;
44 52 }
... ... @@ -17,6 +17,7 @@
17 17 #define PCI_PROBE_CONF2 0x0004
18 18 #define PCI_PROBE_MMCONF 0x0008
19 19 #define PCI_PROBE_MASK 0x000f
  20 +#define PCI_PROBE_NOEARLY 0x0010
20 21  
21 22 #define PCI_NO_SORT 0x0100
22 23 #define PCI_BIOS_SORT 0x0200
arch/x86_64/kernel/aperture.c
... ... @@ -212,7 +212,7 @@
212 212 u64 aper_base, last_aper_base = 0;
213 213 int valid_agp = 0;
214 214  
215   - if (iommu_aperture_disabled || !fix_aperture)
  215 + if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed())
216 216 return;
217 217  
218 218 printk("Checking aperture...\n");
arch/x86_64/kernel/early-quirks.c
... ... @@ -82,6 +82,10 @@
82 82 void __init early_quirks(void)
83 83 {
84 84 int num, slot, func;
  85 +
  86 + if (!early_pci_allowed())
  87 + return;
  88 +
85 89 /* Poor man's PCI discovery */
86 90 for (num = 0; num < 32; num++) {
87 91 for (slot = 0; slot < 32; slot++) {
arch/x86_64/kernel/pci-calgary.c
... ... @@ -924,6 +924,9 @@
924 924 if (swiotlb || no_iommu || iommu_detected)
925 925 return;
926 926  
  927 + if (!early_pci_allowed())
  928 + return;
  929 +
927 930 specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
928 931  
929 932 for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
arch/x86_64/kernel/vsmp.c
... ... @@ -20,6 +20,9 @@
20 20 void *address;
21 21 unsigned int cap, ctl;
22 22  
  23 + if (!early_pci_allowed())
  24 + return 0;
  25 +
23 26 /* Check if we are running on a ScaleMP vSMP box */
24 27 if ((read_pci_config_16(0, 0x1f, 0, PCI_VENDOR_ID) != PCI_VENDOR_ID_SCALEMP) ||
25 28 (read_pci_config_16(0, 0x1f, 0, PCI_DEVICE_ID) != PCI_DEVICE_ID_SCALEMP_VSMP_CTL))
arch/x86_64/mm/k8topology.c
... ... @@ -54,6 +54,9 @@
54 54  
55 55 nodes_clear(nodes_parsed);
56 56  
  57 + if (!early_pci_allowed())
  58 + return -1;
  59 +
57 60 nb = find_northbridge();
58 61 if (nb < 0)
59 62 return nb;
... ... @@ -953,12 +953,11 @@
953 953 }
954 954 str = k;
955 955 }
956   - return 1;
  956 + return 0;
957 957 }
  958 +early_param("pci", pci_setup);
958 959  
959 960 device_initcall(pci_init);
960   -
961   -__setup("pci=", pci_setup);
962 961  
963 962 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
964 963 /* FIXME: Some boxes have multiple ISA bridges! */
include/asm-x86_64/pci-direct.h
... ... @@ -11,5 +11,7 @@
11 11 extern u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset);
12 12 extern void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, u32 val);
13 13  
  14 +extern int early_pci_allowed(void);
  15 +
14 16 #endif