Browse Source

[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>
Andi Kleen 18 years ago
parent
commit
0637a70a5d

+ 5 - 1
Documentation/kernel-parameters.txt

@@ -1240,7 +1240,11 @@ running once the system is up.
 				bootloader. This is currently used on
 				bootloader. This is currently used on
 				IXP2000 systems where the bus has to be
 				IXP2000 systems where the bus has to be
 				configured a certain way for adjunct CPUs.
 				configured a certain way for adjunct CPUs.
-
+		noearly		[X86] Don't do any early type 1 scanning.
+				This might help on some broken boards which
+				machine check when some devices' config space
+				is read. But various workarounds are disabled
+				and some IOMMU drivers will not work.
 	pcmv=		[HW,PCMCIA] BadgePAD 4
 	pcmv=		[HW,PCMCIA] BadgePAD 4
 
 
 	pd.		[PARIDE]
 	pd.		[PARIDE]

+ 5 - 1
arch/i386/kernel/acpi/earlyquirk.c

@@ -48,7 +48,11 @@ void __init check_acpi_pci(void)
 	int num, slot, func;
 	int num, slot, func;
 
 
 	/* Assume the machine supports type 1. If not it will 
 	/* Assume the machine supports type 1. If not it will 
-	   always read ffffffff and should not have any side effect. */
+	   always read ffffffff and should not have any side effect.
+	   Actually a few buggy systems can machine check. Allow the user
+	   to disable it by command line option at least -AK */
+	if (!early_pci_allowed())
+		return;
 
 
 	/* Poor man's PCI discovery */
 	/* Poor man's PCI discovery */
 	for (num = 0; num < 32; num++) {
 	for (num = 0; num < 32; num++) {

+ 4 - 0
arch/i386/pci/common.c

@@ -242,6 +242,10 @@ char * __devinit  pcibios_setup(char *str)
 		acpi_noirq_set();
 		acpi_noirq_set();
 		return NULL;
 		return NULL;
 	}
 	}
+	else if (!strcmp(str, "noearly")) {
+		pci_probe |= PCI_PROBE_NOEARLY;
+		return NULL;
+	}
 #ifndef CONFIG_X86_VISWS
 #ifndef CONFIG_X86_VISWS
 	else if (!strcmp(str, "usepirqmask")) {
 	else if (!strcmp(str, "usepirqmask")) {
 		pci_probe |= PCI_USE_PIRQ_MASK;
 		pci_probe |= PCI_USE_PIRQ_MASK;

+ 8 - 0
arch/i386/pci/early.c

@@ -1,6 +1,8 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <asm/pci-direct.h>
 #include <asm/pci-direct.h>
 #include <asm/io.h>
 #include <asm/io.h>
+#include "pci.h"
 
 
 /* Direct PCI access. This is used for PCI accesses in early boot before
 /* Direct PCI access. This is used for PCI accesses in early boot before
    the PCI subsystem works. */
    the PCI subsystem works. */
@@ -42,3 +44,9 @@ void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
 	outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
 	outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
 	outl(val, 0xcfc);
 	outl(val, 0xcfc);
 }
 }
+
+int early_pci_allowed(void)
+{
+	return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) ==
+			PCI_PROBE_CONF1;
+}

+ 1 - 0
arch/i386/pci/pci.h

@@ -17,6 +17,7 @@
 #define PCI_PROBE_CONF2		0x0004
 #define PCI_PROBE_CONF2		0x0004
 #define PCI_PROBE_MMCONF	0x0008
 #define PCI_PROBE_MMCONF	0x0008
 #define PCI_PROBE_MASK		0x000f
 #define PCI_PROBE_MASK		0x000f
+#define PCI_PROBE_NOEARLY	0x0010
 
 
 #define PCI_NO_SORT		0x0100
 #define PCI_NO_SORT		0x0100
 #define PCI_BIOS_SORT		0x0200
 #define PCI_BIOS_SORT		0x0200

+ 1 - 1
arch/x86_64/kernel/aperture.c

@@ -212,7 +212,7 @@ void __init iommu_hole_init(void)
 	u64 aper_base, last_aper_base = 0;
 	u64 aper_base, last_aper_base = 0;
 	int valid_agp = 0;
 	int valid_agp = 0;
 
 
-	if (iommu_aperture_disabled || !fix_aperture)
+	if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed())
 		return;
 		return;
 
 
 	printk("Checking aperture...\n"); 
 	printk("Checking aperture...\n"); 

+ 4 - 0
arch/x86_64/kernel/early-quirks.c

@@ -82,6 +82,10 @@ static struct chipset early_qrk[] = {
 void __init early_quirks(void)
 void __init early_quirks(void)
 {
 {
 	int num, slot, func;
 	int num, slot, func;
+
+	if (!early_pci_allowed())
+		return;
+
 	/* Poor man's PCI discovery */
 	/* Poor man's PCI discovery */
 	for (num = 0; num < 32; num++) {
 	for (num = 0; num < 32; num++) {
 		for (slot = 0; slot < 32; slot++) {
 		for (slot = 0; slot < 32; slot++) {

+ 3 - 0
arch/x86_64/kernel/pci-calgary.c

@@ -924,6 +924,9 @@ void __init detect_calgary(void)
 	if (swiotlb || no_iommu || iommu_detected)
 	if (swiotlb || no_iommu || iommu_detected)
 		return;
 		return;
 
 
+	if (!early_pci_allowed())
+		return;
+
 	specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
 	specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
 
 
 	for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
 	for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {

+ 3 - 0
arch/x86_64/kernel/vsmp.c

@@ -20,6 +20,9 @@ static int __init vsmp_init(void)
 	void *address;
 	void *address;
 	unsigned int cap, ctl;
 	unsigned int cap, ctl;
 
 
+	if (!early_pci_allowed())
+		return 0;
+
 	/* Check if we are running on a ScaleMP vSMP box */
 	/* Check if we are running on a ScaleMP vSMP box */
 	if ((read_pci_config_16(0, 0x1f, 0, PCI_VENDOR_ID) != PCI_VENDOR_ID_SCALEMP) ||
 	if ((read_pci_config_16(0, 0x1f, 0, PCI_VENDOR_ID) != PCI_VENDOR_ID_SCALEMP) ||
 	    (read_pci_config_16(0, 0x1f, 0, PCI_DEVICE_ID) != PCI_DEVICE_ID_SCALEMP_VSMP_CTL))
 	    (read_pci_config_16(0, 0x1f, 0, PCI_DEVICE_ID) != PCI_DEVICE_ID_SCALEMP_VSMP_CTL))

+ 3 - 0
arch/x86_64/mm/k8topology.c

@@ -54,6 +54,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
 
 
 	nodes_clear(nodes_parsed);
 	nodes_clear(nodes_parsed);
 
 
+	if (!early_pci_allowed())
+		return -1;
+
 	nb = find_northbridge(); 
 	nb = find_northbridge(); 
 	if (nb < 0) 
 	if (nb < 0) 
 		return nb;
 		return nb;

+ 2 - 3
drivers/pci/pci.c

@@ -953,13 +953,12 @@ static int __devinit pci_setup(char *str)
 		}
 		}
 		str = k;
 		str = k;
 	}
 	}
-	return 1;
+	return 0;
 }
 }
+early_param("pci", pci_setup);
 
 
 device_initcall(pci_init);
 device_initcall(pci_init);
 
 
-__setup("pci=", pci_setup);
-
 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
 /* FIXME: Some boxes have multiple ISA bridges! */
 /* FIXME: Some boxes have multiple ISA bridges! */
 struct pci_dev *isa_bridge;
 struct pci_dev *isa_bridge;

+ 2 - 0
include/asm-x86_64/pci-direct.h

@@ -11,4 +11,6 @@ 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);
 extern u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset);
 extern void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, u32 val);
 extern void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, u32 val);
 
 
+extern int early_pci_allowed(void);
+
 #endif
 #endif