aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/pci
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/pci')
-rw-r--r--arch/x86_64/pci/mmconfig.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index 22ff1b07d4e0..9c4f907e301c 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -8,10 +8,13 @@
8#include <linux/pci.h> 8#include <linux/pci.h>
9#include <linux/init.h> 9#include <linux/init.h>
10#include <linux/acpi.h> 10#include <linux/acpi.h>
11#include <linux/bitmap.h>
11#include "pci.h" 12#include "pci.h"
12 13
13#define MMCONFIG_APER_SIZE (256*1024*1024) 14#define MMCONFIG_APER_SIZE (256*1024*1024)
14 15
16static DECLARE_BITMAP(fallback_slots, 32);
17
15/* Static virtual mapping of the MMCONFIG aperture */ 18/* Static virtual mapping of the MMCONFIG aperture */
16struct mmcfg_virt { 19struct mmcfg_virt {
17 struct acpi_table_mcfg_config *cfg; 20 struct acpi_table_mcfg_config *cfg;
@@ -40,9 +43,12 @@ static char *get_virt(unsigned int seg, unsigned bus)
40 } 43 }
41} 44}
42 45
43static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) 46static char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
44{ 47{
45 char *addr = get_virt(seg, bus); 48 char *addr;
49 if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), &fallback_slots))
50 return NULL;
51 addr = get_virt(seg, bus);
46 if (!addr) 52 if (!addr)
47 return NULL; 53 return NULL;
48 return addr + ((bus << 20) | (devfn << 12)); 54 return addr + ((bus << 20) | (devfn << 12));
@@ -109,6 +115,30 @@ static struct pci_raw_ops pci_mmcfg = {
109 .write = pci_mmcfg_write, 115 .write = pci_mmcfg_write,
110}; 116};
111 117
118/* K8 systems have some devices (typically in the builtin northbridge)
119 that are only accessible using type1
120 Normally this can be expressed in the MCFG by not listing them
121 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
122 Instead try to discover all devices on bus 0 that are unreachable using MM
123 and fallback for them.
124 We only do this for bus 0/seg 0 */
125static __init void unreachable_devices(void)
126{
127 int i;
128 for (i = 0; i < 32; i++) {
129 u32 val1;
130 char *addr;
131
132 pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1);
133 if (val1 == 0xffffffff)
134 continue;
135 addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0));
136 if (addr == NULL|| readl(addr) != val1) {
137 set_bit(i, &fallback_slots);
138 }
139 }
140}
141
112static int __init pci_mmcfg_init(void) 142static int __init pci_mmcfg_init(void)
113{ 143{
114 int i; 144 int i;
@@ -139,6 +169,8 @@ static int __init pci_mmcfg_init(void)
139 printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address); 169 printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
140 } 170 }
141 171
172 unreachable_devices();
173
142 raw_pci_ops = &pci_mmcfg; 174 raw_pci_ops = &pci_mmcfg;
143 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; 175 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
144 176