aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/pci/mmconfig.c52
1 files changed, 30 insertions, 22 deletions
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index ee815c7d3e4c..2002c741a383 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -17,12 +17,15 @@
17 17
18#define MMCONFIG_APER_SIZE (256*1024*1024) 18#define MMCONFIG_APER_SIZE (256*1024*1024)
19 19
20/* Assume systems with more busses have correct MCFG */
21#define MAX_CHECK_BUS 16
22
20#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) 23#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
21 24
22/* The base address of the last MMCONFIG device accessed */ 25/* The base address of the last MMCONFIG device accessed */
23static u32 mmcfg_last_accessed_device; 26static u32 mmcfg_last_accessed_device;
24 27
25static DECLARE_BITMAP(fallback_slots, 32); 28static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
26 29
27/* 30/*
28 * Functions for accessing PCI configuration space with MMCONFIG accesses 31 * Functions for accessing PCI configuration space with MMCONFIG accesses
@@ -32,8 +35,8 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
32 int cfg_num = -1; 35 int cfg_num = -1;
33 struct acpi_table_mcfg_config *cfg; 36 struct acpi_table_mcfg_config *cfg;
34 37
35 if (seg == 0 && bus == 0 && 38 if (seg == 0 && bus < MAX_CHECK_BUS &&
36 test_bit(PCI_SLOT(devfn), fallback_slots)) 39 test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots))
37 return 0; 40 return 0;
38 41
39 while (1) { 42 while (1) {
@@ -149,29 +152,34 @@ static struct pci_raw_ops pci_mmcfg = {
149 Normally this can be expressed in the MCFG by not listing them 152 Normally this can be expressed in the MCFG by not listing them
150 and assigning suitable _SEGs, but this isn't implemented in some BIOS. 153 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
151 Instead try to discover all devices on bus 0 that are unreachable using MM 154 Instead try to discover all devices on bus 0 that are unreachable using MM
152 and fallback for them. 155 and fallback for them. */
153 We only do this for bus 0/seg 0 */
154static __init void unreachable_devices(void) 156static __init void unreachable_devices(void)
155{ 157{
156 int i; 158 int i, k;
157 unsigned long flags; 159 unsigned long flags;
158 160
159 for (i = 0; i < 32; i++) { 161 for (k = 0; k < MAX_CHECK_BUS; k++) {
160 u32 val1; 162 for (i = 0; i < 32; i++) {
161 u32 addr; 163 u32 val1;
162 164 u32 addr;
163 pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1); 165
164 if (val1 == 0xffffffff) 166 pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1);
165 continue; 167 if (val1 == 0xffffffff)
166 168 continue;
167 /* Locking probably not needed, but safer */ 169
168 spin_lock_irqsave(&pci_config_lock, flags); 170 /* Locking probably not needed, but safer */
169 addr = get_base_addr(0, 0, PCI_DEVFN(i, 0)); 171 spin_lock_irqsave(&pci_config_lock, flags);
170 if (addr != 0) 172 addr = get_base_addr(0, k, PCI_DEVFN(i, 0));
171 pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0)); 173 if (addr != 0)
172 if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1) 174 pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0));
173 set_bit(i, fallback_slots); 175 if (addr == 0 ||
174 spin_unlock_irqrestore(&pci_config_lock, flags); 176 readl((u32 __iomem *)mmcfg_virt_addr) != val1) {
177 set_bit(i, fallback_slots);
178 printk(KERN_NOTICE
179 "PCI: No mmconfig possible on %x:%x\n", k, i);
180 }
181 spin_unlock_irqrestore(&pci_config_lock, flags);
182 }
175 } 183 }
176} 184}
177 185