aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2005-12-13 01:17:11 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-12-13 01:31:16 -0500
commitd6ece5491ae71ded1237f59def88bcd1b19b6f60 (patch)
tree3128cb506d050a4007d2724939af15e512d7c5b4
parent928cf8c62763349efc550a12f6518e52c3390906 (diff)
[PATCH] i386/x86-64 Correct for broken MCFG tables on K8 systems
They report all busses as MMCONFIG capable, but it never works for the internal devices in the CPU's builtin northbridge. It just probes all func 0 devices on bus 0 (the internal northbridge is currently always on bus 0) and if they are not accessible using MCFG they are put into a special fallback bitmap. On systems where it isn't we assume the BIOS vendor supplied correct MCFG. Requires the earlier patch for mmconfig type1 fallback Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/i386/pci/mmconfig.c45
-rw-r--r--arch/x86_64/pci/mmconfig.c36
2 files changed, 76 insertions, 5 deletions
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index cc787a7c030c..08a084901212 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -19,14 +19,20 @@
19/* The base address of the last MMCONFIG device accessed */ 19/* The base address of the last MMCONFIG device accessed */
20static u32 mmcfg_last_accessed_device; 20static u32 mmcfg_last_accessed_device;
21 21
22static DECLARE_BITMAP(fallback_slots, 32);
23
22/* 24/*
23 * Functions for accessing PCI configuration space with MMCONFIG accesses 25 * Functions for accessing PCI configuration space with MMCONFIG accesses
24 */ 26 */
25static u32 get_base_addr(unsigned int seg, int bus) 27static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
26{ 28{
27 int cfg_num = -1; 29 int cfg_num = -1;
28 struct acpi_table_mcfg_config *cfg; 30 struct acpi_table_mcfg_config *cfg;
29 31
32 if (seg == 0 && bus == 0 &&
33 test_bit(PCI_SLOT(devfn), fallback_slots))
34 return 0;
35
30 while (1) { 36 while (1) {
31 ++cfg_num; 37 ++cfg_num;
32 if (cfg_num >= pci_mmcfg_config_num) { 38 if (cfg_num >= pci_mmcfg_config_num) {
@@ -60,7 +66,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
60 if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) 66 if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
61 return -EINVAL; 67 return -EINVAL;
62 68
63 base = get_base_addr(seg, bus); 69 base = get_base_addr(seg, bus, devfn);
64 if (!base) 70 if (!base)
65 return pci_conf1_read(seg,bus,devfn,reg,len,value); 71 return pci_conf1_read(seg,bus,devfn,reg,len,value);
66 72
@@ -94,7 +100,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
94 if ((bus > 255) || (devfn > 255) || (reg > 4095)) 100 if ((bus > 255) || (devfn > 255) || (reg > 4095))
95 return -EINVAL; 101 return -EINVAL;
96 102
97 base = get_base_addr(seg, bus); 103 base = get_base_addr(seg, bus, devfn);
98 if (!base) 104 if (!base)
99 return pci_conf1_write(seg,bus,devfn,reg,len,value); 105 return pci_conf1_write(seg,bus,devfn,reg,len,value);
100 106
@@ -124,6 +130,37 @@ static struct pci_raw_ops pci_mmcfg = {
124 .write = pci_mmcfg_write, 130 .write = pci_mmcfg_write,
125}; 131};
126 132
133/* K8 systems have some devices (typically in the builtin northbridge)
134 that are only accessible using type1
135 Normally this can be expressed in the MCFG by not listing them
136 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
137 Instead try to discover all devices on bus 0 that are unreachable using MM
138 and fallback for them.
139 We only do this for bus 0/seg 0 */
140static __init void unreachable_devices(void)
141{
142 int i;
143 unsigned long flags;
144
145 for (i = 0; i < 32; i++) {
146 u32 val1;
147 u32 addr;
148
149 pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1);
150 if (val1 == 0xffffffff)
151 continue;
152
153 /* Locking probably not needed, but safer */
154 spin_lock_irqsave(&pci_config_lock, flags);
155 addr = get_base_addr(0, 0, PCI_DEVFN(i, 0));
156 if (addr != 0)
157 pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0));
158 if (addr == 0 || readl((u32 *)addr) != val1)
159 set_bit(i, fallback_slots);
160 spin_unlock_irqrestore(&pci_config_lock, flags);
161 }
162}
163
127static int __init pci_mmcfg_init(void) 164static int __init pci_mmcfg_init(void)
128{ 165{
129 if ((pci_probe & PCI_PROBE_MMCONF) == 0) 166 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
@@ -139,6 +176,8 @@ static int __init pci_mmcfg_init(void)
139 raw_pci_ops = &pci_mmcfg; 176 raw_pci_ops = &pci_mmcfg;
140 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; 177 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
141 178
179 unreachable_devices();
180
142 out: 181 out:
143 return 0; 182 return 0;
144} 183}
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