diff options
Diffstat (limited to 'arch/x86_64/pci/mmconfig.c')
-rw-r--r-- | arch/x86_64/pci/mmconfig.c | 39 |
1 files changed, 24 insertions, 15 deletions
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index dfe84c322552..d4e25f38287d 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c | |||
@@ -14,8 +14,11 @@ | |||
14 | #include "pci.h" | 14 | #include "pci.h" |
15 | 15 | ||
16 | #define MMCONFIG_APER_SIZE (256*1024*1024) | 16 | #define MMCONFIG_APER_SIZE (256*1024*1024) |
17 | /* Verify the first 16 busses. We assume that systems with more busses | ||
18 | get MCFG right. */ | ||
19 | #define MAX_CHECK_BUS 16 | ||
17 | 20 | ||
18 | static DECLARE_BITMAP(fallback_slots, 32); | 21 | static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS); |
19 | 22 | ||
20 | /* Static virtual mapping of the MMCONFIG aperture */ | 23 | /* Static virtual mapping of the MMCONFIG aperture */ |
21 | struct mmcfg_virt { | 24 | struct mmcfg_virt { |
@@ -57,7 +60,8 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus) | |||
57 | static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) | 60 | static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) |
58 | { | 61 | { |
59 | char __iomem *addr; | 62 | char __iomem *addr; |
60 | if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), fallback_slots)) | 63 | if (seg == 0 && bus < MAX_CHECK_BUS && |
64 | test_bit(32*bus + PCI_SLOT(devfn), fallback_slots)) | ||
61 | return NULL; | 65 | return NULL; |
62 | addr = get_virt(seg, bus); | 66 | addr = get_virt(seg, bus); |
63 | if (!addr) | 67 | if (!addr) |
@@ -131,21 +135,26 @@ static struct pci_raw_ops pci_mmcfg = { | |||
131 | Normally this can be expressed in the MCFG by not listing them | 135 | Normally this can be expressed in the MCFG by not listing them |
132 | and assigning suitable _SEGs, but this isn't implemented in some BIOS. | 136 | and assigning suitable _SEGs, but this isn't implemented in some BIOS. |
133 | Instead try to discover all devices on bus 0 that are unreachable using MM | 137 | Instead try to discover all devices on bus 0 that are unreachable using MM |
134 | and fallback for them. | 138 | and fallback for them. */ |
135 | We only do this for bus 0/seg 0 */ | ||
136 | static __init void unreachable_devices(void) | 139 | static __init void unreachable_devices(void) |
137 | { | 140 | { |
138 | int i; | 141 | int i, k; |
139 | for (i = 0; i < 32; i++) { | 142 | /* Use the max bus number from ACPI here? */ |
140 | u32 val1; | 143 | for (k = 0; i < MAX_CHECK_BUS; k++) { |
141 | char __iomem *addr; | 144 | for (i = 0; i < 32; i++) { |
142 | 145 | u32 val1; | |
143 | pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1); | 146 | char __iomem *addr; |
144 | if (val1 == 0xffffffff) | 147 | |
145 | continue; | 148 | pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1); |
146 | addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0)); | 149 | if (val1 == 0xffffffff) |
147 | if (addr == NULL|| readl(addr) != val1) { | 150 | continue; |
148 | set_bit(i, fallback_slots); | 151 | addr = pci_dev_base(0, k, PCI_DEVFN(i, 0)); |
152 | if (addr == NULL|| readl(addr) != val1) { | ||
153 | set_bit(i + 32*k, fallback_slots); | ||
154 | printk(KERN_NOTICE | ||
155 | "PCI: No mmconfig possible on device %x:%x\n", | ||
156 | k, i); | ||
157 | } | ||
149 | } | 158 | } |
150 | } | 159 | } |
151 | } | 160 | } |