X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=arch%2Fi386%2Fpci%2Fmmconfig.c;h=d0c3da3aa2aa9978eef4774c4a61ec97955e2df3;hb=42eaf0d8f2e7b8201afc00b0ebe1bd89ea51d42d;hp=ef5a2faa7d824728d4c44cade01a2f2c023adca2;hpb=ab5cfd2aa3af40b35d7a948de8e279dc82c5b9f6;p=pandora-kernel.git diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index ef5a2faa7d82..bb1afd9e589d 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -12,67 +12,51 @@ #include #include #include -#include #include #include "pci.h" -/* aperture is up to 256MB but BIOS may reserve less */ -#define MMCONFIG_APER_MIN (2 * 1024*1024) -#define MMCONFIG_APER_MAX (256 * 1024*1024) - /* Assume systems with more busses have correct MCFG */ -#define MAX_CHECK_BUS 16 - #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) /* The base address of the last MMCONFIG device accessed */ static u32 mmcfg_last_accessed_device; - -static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32); +static int mmcfg_last_accessed_cpu; /* * Functions for accessing PCI configuration space with MMCONFIG accesses */ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) { - int cfg_num = -1; - struct acpi_table_mcfg_config *cfg; + struct acpi_mcfg_allocation *cfg; + int cfg_num; - if (seg == 0 && bus < MAX_CHECK_BUS && - test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots)) + if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && + test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots)) return 0; - while (1) { - ++cfg_num; - if (cfg_num >= pci_mmcfg_config_num) { - break; - } + for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { cfg = &pci_mmcfg_config[cfg_num]; - if (cfg->pci_segment_group_number != seg) - continue; - if ((cfg->start_bus_number <= bus) && + if (cfg->pci_segment == seg && + (cfg->start_bus_number <= bus) && (cfg->end_bus_number >= bus)) - return cfg->base_address; + return cfg->address; } - /* Handle more broken MCFG tables on Asus etc. - They only contain a single entry for bus 0-0. Assume - this applies to all busses. */ - cfg = &pci_mmcfg_config[0]; - if (pci_mmcfg_config_num == 1 && - cfg->pci_segment_group_number == 0 && - (cfg->start_bus_number | cfg->end_bus_number) == 0) - return cfg->base_address; - /* Fall back to type 0 */ return 0; } -static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) +/* + * This is always called under pci_config_lock + */ +static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) { u32 dev_base = base | (bus << 20) | (devfn << 12); - if (dev_base != mmcfg_last_accessed_device) { + int cpu = smp_processor_id(); + if (dev_base != mmcfg_last_accessed_device || + cpu != mmcfg_last_accessed_cpu) { mmcfg_last_accessed_device = dev_base; + mmcfg_last_accessed_cpu = cpu; set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); } } @@ -119,7 +103,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, unsigned long flags; u32 base; - if ((bus > 255) || (devfn > 255) || (reg > 4095)) + if ((bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; base = get_base_addr(seg, bus, devfn); @@ -152,78 +136,15 @@ static struct pci_raw_ops pci_mmcfg = { .write = pci_mmcfg_write, }; -/* K8 systems have some devices (typically in the builtin northbridge) - that are only accessible using type1 - Normally this can be expressed in the MCFG by not listing them - and assigning suitable _SEGs, but this isn't implemented in some BIOS. - Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. */ -static __init void unreachable_devices(void) +int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, + unsigned int devfn) { - int i, k; - unsigned long flags; - - for (k = 0; k < MAX_CHECK_BUS; k++) { - for (i = 0; i < 32; i++) { - u32 val1; - u32 addr; - - pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1); - if (val1 == 0xffffffff) - continue; - - /* Locking probably not needed, but safer */ - spin_lock_irqsave(&pci_config_lock, flags); - addr = get_base_addr(0, k, PCI_DEVFN(i, 0)); - if (addr != 0) - pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0)); - if (addr == 0 || - readl((u32 __iomem *)mmcfg_virt_addr) != val1) { - set_bit(i + 32*k, fallback_slots); - printk(KERN_NOTICE - "PCI: No mmconfig possible on %x:%x\n", k, i); - } - spin_unlock_irqrestore(&pci_config_lock, flags); - } - } + return get_base_addr(seg, bus, devfn) != 0; } -static int disable_mcfg(struct dmi_system_id *d) +int __init pci_mmcfg_arch_init(void) { - 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) -{ - 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); - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].base_address == 0)) - return; - printk(KERN_INFO "PCI: Using MMCONFIG\n"); raw_pci_ops = &pci_mmcfg; - pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; - - unreachable_devices(); + return 1; }