aboutsummaryrefslogtreecommitdiff
path: root/arch/i386/pci
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/pci')
-rw-r--r--arch/i386/pci/common.c9
-rw-r--r--arch/i386/pci/init.c8
-rw-r--r--arch/i386/pci/mmconfig.c36
-rw-r--r--arch/i386/pci/pci.h5
4 files changed, 39 insertions, 19 deletions
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index c624b61e110..1220dd828ce 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -17,10 +17,6 @@
#include "pci.h"
-#ifdef CONFIG_PCI_BIOS
-extern void pcibios_sort(void);
-#endif
-
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
PCI_PROBE_MMCONF;
@@ -241,6 +237,11 @@ char * __devinit pcibios_setup(char *str)
pci_probe &= ~PCI_PROBE_MMCONF;
return NULL;
}
+ /* override DMI blacklist */
+ else if (!strcmp(str, "mmconf")) {
+ pci_probe |= PCI_PROBE_MMCONF_FORCE;
+ return NULL;
+ }
#endif
else if (!strcmp(str, "noacpi")) {
acpi_noirq_set();
diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c
index c7650a7e0b0..51087a9d917 100644
--- a/arch/i386/pci/init.c
+++ b/arch/i386/pci/init.c
@@ -14,8 +14,12 @@ static __init int pci_access_init(void)
#ifdef CONFIG_PCI_BIOS
pci_pcbios_init();
#endif
- if (raw_pci_ops)
- return 0;
+ /*
+ * don't check for raw_pci_ops here because we want pcbios as last
+ * fallback, yet it's needed to run first to set pcibios_last_bus
+ * in case legacy PCI probing is used. otherwise detecting peer busses
+ * fails.
+ */
#ifdef CONFIG_PCI_DIRECT
pci_direct_init();
#endif
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index e545b0992c4..ef5a2faa7d8 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -12,6 +12,7 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include <asm/e820.h>
#include "pci.h"
@@ -178,7 +179,7 @@ static __init void unreachable_devices(void)
pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0));
if (addr == 0 ||
readl((u32 __iomem *)mmcfg_virt_addr) != val1) {
- set_bit(i, fallback_slots);
+ set_bit(i + 32*k, fallback_slots);
printk(KERN_NOTICE
"PCI: No mmconfig possible on %x:%x\n", k, i);
}
@@ -187,9 +188,31 @@ static __init void unreachable_devices(void)
}
}
+static int disable_mcfg(struct dmi_system_id *d)
+{
+ printk("PCI: %s detected. Disabling MCFG.\n", d->ident);
+ pci_probe &= ~PCI_PROBE_MMCONF;
+ return 0;
+}
+
+static struct dmi_system_id __initdata dmi_bad_mcfg[] = {
+ /* Has broken MCFG table that makes the system hang when used */
+ {
+ .callback = disable_mcfg,
+ .ident = "Intel D3C5105 SDV",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Intel"),
+ DMI_MATCH(DMI_BOARD_NAME, "D26928"),
+ },
+ },
+ {}
+};
+
void __init pci_mmcfg_init(void)
{
- if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+ dmi_check_system(dmi_bad_mcfg);
+
+ if ((pci_probe & (PCI_PROBE_MMCONF_FORCE|PCI_PROBE_MMCONF)) == 0)
return;
acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
@@ -198,15 +221,6 @@ void __init pci_mmcfg_init(void)
(pci_mmcfg_config[0].base_address == 0))
return;
- if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
- E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
- pci_mmcfg_config[0].base_address);
- printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
- return;
- }
-
printk(KERN_INFO "PCI: Using MMCONFIG\n");
raw_pci_ops = &pci_mmcfg;
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
index 12bf3d8dda2..49a849b3a24 100644
--- a/arch/i386/pci/pci.h
+++ b/arch/i386/pci/pci.h
@@ -16,7 +16,8 @@
#define PCI_PROBE_CONF1 0x0002
#define PCI_PROBE_CONF2 0x0004
#define PCI_PROBE_MMCONF 0x0008
-#define PCI_PROBE_MASK 0x000f
+#define PCI_PROBE_MMCONF_FORCE 0x0010
+#define PCI_PROBE_MASK 0x00ff
#define PCI_NO_SORT 0x0100
#define PCI_BIOS_SORT 0x0200
@@ -84,4 +85,4 @@ extern int pci_conf1_read(unsigned int seg, unsigned int bus,
extern void pci_direct_init(void);
extern void pci_pcbios_init(void);
extern void pci_mmcfg_init(void);
-
+extern void pcibios_sort(void);