Commit 0637a70a authored by Andi Kleen's avatar Andi Kleen Committed by Andi Kleen

[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: default avatarAndi Kleen <ak@suse.de>
parent 8f60774a
...@@ -1240,7 +1240,11 @@ running once the system is up. ...@@ -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]
......
...@@ -48,7 +48,11 @@ void __init check_acpi_pci(void) ...@@ -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++) {
......
...@@ -242,6 +242,10 @@ char * __devinit pcibios_setup(char *str) ...@@ -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;
......
#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, ...@@ -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;
}
...@@ -17,6 +17,7 @@ ...@@ -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
......
...@@ -212,7 +212,7 @@ void __init iommu_hole_init(void) ...@@ -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");
......
...@@ -82,6 +82,10 @@ static struct chipset early_qrk[] = { ...@@ -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++) {
......
...@@ -924,6 +924,9 @@ void __init detect_calgary(void) ...@@ -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++) {
......
...@@ -20,6 +20,9 @@ static int __init vsmp_init(void) ...@@ -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))
......
...@@ -54,6 +54,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) ...@@ -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;
......
...@@ -953,13 +953,12 @@ static int __devinit pci_setup(char *str) ...@@ -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;
......
...@@ -11,4 +11,6 @@ extern u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset); ...@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment