diff options
Diffstat (limited to 'arch/i386/pci')
-rw-r--r-- | arch/i386/pci/common.c | 9 | ||||
-rw-r--r-- | arch/i386/pci/init.c | 8 | ||||
-rw-r--r-- | arch/i386/pci/mmconfig.c | 36 | ||||
-rw-r--r-- | arch/i386/pci/pci.h | 5 |
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); |