blob: 4df637e34f813da1e47839c75d9cd3fc502bc560 [file] [log] [blame]
Olivier Galibertb7867392007-02-13 13:26:20 +01001/*
2 * mmconfig-shared.c - Low-level direct PCI config space access via
3 * MMCONFIG - common code between i386 and x86-64.
4 *
5 * This code does:
Olivier Galibert9358c692007-02-13 13:26:20 +01006 * - known chipset handling
Olivier Galibertb7867392007-02-13 13:26:20 +01007 * - ACPI decoding and validation
8 *
9 * Per-architecture code takes care of the mappings and accesses
10 * themselves.
11 */
12
13#include <linux/pci.h>
14#include <linux/init.h>
15#include <linux/acpi.h>
16#include <linux/bitmap.h>
17#include <asm/e820.h>
18
19#include "pci.h"
20
21/* aperture is up to 256MB but BIOS may reserve less */
22#define MMCONFIG_APER_MIN (2 * 1024*1024)
23#define MMCONFIG_APER_MAX (256 * 1024*1024)
24
Olivier Galibertb7867392007-02-13 13:26:20 +010025DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
26
Aaron Durbina5ba7972007-07-21 17:10:34 +020027/* Indicate if the mmcfg resources have been placed into the resource table. */
28static int __initdata pci_mmcfg_resources_inserted;
29
Olivier Galibertb7867392007-02-13 13:26:20 +010030/* K8 systems have some devices (typically in the builtin northbridge)
31 that are only accessible using type1
32 Normally this can be expressed in the MCFG by not listing them
33 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
34 Instead try to discover all devices on bus 0 that are unreachable using MM
35 and fallback for them. */
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010036static void __init unreachable_devices(void)
Olivier Galibertb7867392007-02-13 13:26:20 +010037{
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010038 int i, bus;
Olivier Galibertb7867392007-02-13 13:26:20 +010039 /* Use the max bus number from ACPI here? */
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010040 for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) {
Olivier Galibertb7867392007-02-13 13:26:20 +010041 for (i = 0; i < 32; i++) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010042 unsigned int devfn = PCI_DEVFN(i, 0);
Olivier Galibertb7867392007-02-13 13:26:20 +010043 u32 val1, val2;
44
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010045 pci_conf1_read(0, bus, devfn, 0, 4, &val1);
Olivier Galibertb7867392007-02-13 13:26:20 +010046 if (val1 == 0xffffffff)
47 continue;
48
OGAWA Hirofumi56829d12007-02-13 13:26:20 +010049 if (pci_mmcfg_arch_reachable(0, bus, devfn)) {
50 raw_pci_ops->read(0, bus, devfn, 0, 4, &val2);
51 if (val1 == val2)
52 continue;
Olivier Galibertb7867392007-02-13 13:26:20 +010053 }
OGAWA Hirofumi56829d12007-02-13 13:26:20 +010054 set_bit(i + 32 * bus, pci_mmcfg_fallback_slots);
55 printk(KERN_NOTICE "PCI: No mmconfig possible on device"
56 " %02x:%02x\n", bus, i);
Olivier Galibertb7867392007-02-13 13:26:20 +010057 }
58 }
59}
60
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010061static const char __init *pci_mmcfg_e7520(void)
Olivier Galibert9358c692007-02-13 13:26:20 +010062{
63 u32 win;
64 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
65
Olivier Galibertb5229db2007-05-02 19:27:22 +020066 win = win & 0xf000;
67 if(win == 0x0000 || win == 0xf000)
68 pci_mmcfg_config_num = 0;
69 else {
70 pci_mmcfg_config_num = 1;
71 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
72 if (!pci_mmcfg_config)
73 return NULL;
74 pci_mmcfg_config[0].address = win << 16;
75 pci_mmcfg_config[0].pci_segment = 0;
76 pci_mmcfg_config[0].start_bus_number = 0;
77 pci_mmcfg_config[0].end_bus_number = 255;
78 }
Olivier Galibert9358c692007-02-13 13:26:20 +010079
80 return "Intel Corporation E7520 Memory Controller Hub";
81}
82
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010083static const char __init *pci_mmcfg_intel_945(void)
Olivier Galibert9358c692007-02-13 13:26:20 +010084{
85 u32 pciexbar, mask = 0, len = 0;
86
87 pci_mmcfg_config_num = 1;
88
89 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
90
91 /* Enable bit */
92 if (!(pciexbar & 1))
93 pci_mmcfg_config_num = 0;
94
95 /* Size bits */
96 switch ((pciexbar >> 1) & 3) {
97 case 0:
98 mask = 0xf0000000U;
99 len = 0x10000000U;
100 break;
101 case 1:
102 mask = 0xf8000000U;
103 len = 0x08000000U;
104 break;
105 case 2:
106 mask = 0xfc000000U;
107 len = 0x04000000U;
108 break;
109 default:
110 pci_mmcfg_config_num = 0;
111 }
112
113 /* Errata #2, things break when not aligned on a 256Mb boundary */
114 /* Can only happen in 64M/128M mode */
115
116 if ((pciexbar & mask) & 0x0fffffffU)
117 pci_mmcfg_config_num = 0;
118
Olivier Galibertb5229db2007-05-02 19:27:22 +0200119 /* Don't hit the APIC registers and their friends */
120 if ((pciexbar & mask) >= 0xf0000000U)
121 pci_mmcfg_config_num = 0;
122
Olivier Galibert9358c692007-02-13 13:26:20 +0100123 if (pci_mmcfg_config_num) {
124 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
125 if (!pci_mmcfg_config)
126 return NULL;
127 pci_mmcfg_config[0].address = pciexbar & mask;
128 pci_mmcfg_config[0].pci_segment = 0;
129 pci_mmcfg_config[0].start_bus_number = 0;
130 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
131 }
132
133 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
134}
135
136struct pci_mmcfg_hostbridge_probe {
137 u32 vendor;
138 u32 device;
139 const char *(*probe)(void);
140};
141
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100142static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
Olivier Galibert9358c692007-02-13 13:26:20 +0100143 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
144 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
145};
146
147static int __init pci_mmcfg_check_hostbridge(void)
148{
149 u32 l;
150 u16 vendor, device;
151 int i;
152 const char *name;
153
154 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
155 vendor = l & 0xffff;
156 device = (l >> 16) & 0xffff;
157
158 pci_mmcfg_config_num = 0;
159 pci_mmcfg_config = NULL;
160 name = NULL;
161
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100162 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
163 if (pci_mmcfg_probes[i].vendor == vendor &&
164 pci_mmcfg_probes[i].device == device)
Olivier Galibert9358c692007-02-13 13:26:20 +0100165 name = pci_mmcfg_probes[i].probe();
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100166 }
Olivier Galibert9358c692007-02-13 13:26:20 +0100167
168 if (name) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100169 printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
170 name, pci_mmcfg_config_num ? "with" : "without");
Olivier Galibert9358c692007-02-13 13:26:20 +0100171 }
172
173 return name != NULL;
174}
175
Aaron Durbina5ba7972007-07-21 17:10:34 +0200176static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100177{
178#define PCI_MMCFG_RESOURCE_NAME_LEN 19
179 int i;
180 struct resource *res;
181 char *names;
182 unsigned num_buses;
183
184 res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
185 pci_mmcfg_config_num, GFP_KERNEL);
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100186 if (!res) {
187 printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
188 return;
189 }
190
191 names = (void *)&res[pci_mmcfg_config_num];
192 for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100193 struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
194 num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100195 res->name = names;
196 snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100197 cfg->pci_segment);
198 res->start = cfg->address;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100199 res->end = res->start + (num_buses << 20) - 1;
Aaron Durbina5ba7972007-07-21 17:10:34 +0200200 res->flags = IORESOURCE_MEM | resource_flags;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100201 insert_resource(&iomem_resource, res);
202 names += PCI_MMCFG_RESOURCE_NAME_LEN;
203 }
Aaron Durbina5ba7972007-07-21 17:10:34 +0200204
205 /* Mark that the resources have been inserted. */
206 pci_mmcfg_resources_inserted = 1;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100207}
208
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100209static void __init pci_mmcfg_reject_broken(int type)
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100210{
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100211 typeof(pci_mmcfg_config[0]) *cfg;
212
213 if ((pci_mmcfg_config_num == 0) ||
214 (pci_mmcfg_config == NULL) ||
215 (pci_mmcfg_config[0].address == 0))
216 return;
217
218 cfg = &pci_mmcfg_config[0];
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100219
220 /*
221 * Handle more broken MCFG tables on Asus etc.
222 * They only contain a single entry for bus 0-0.
223 */
224 if (pci_mmcfg_config_num == 1 &&
225 cfg->pci_segment == 0 &&
226 (cfg->start_bus_number | cfg->end_bus_number) == 0) {
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100227 printk(KERN_ERR "PCI: start and end of bus number is 0. "
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100228 "Rejected as broken MCFG.\n");
229 goto reject;
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100230 }
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100231
232 /*
233 * Only do this check when type 1 works. If it doesn't work
234 * assume we run on a Mac and always use MCFG
235 */
236 if (type == 1 && !e820_all_mapped(cfg->address,
237 cfg->address + MMCONFIG_APER_MIN,
238 E820_RESERVED)) {
239 printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
240 " E820-reserved\n", cfg->address);
241 goto reject;
242 }
243 return;
244
245reject:
246 printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
247 kfree(pci_mmcfg_config);
248 pci_mmcfg_config = NULL;
249 pci_mmcfg_config_num = 0;
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100250}
251
Olivier Galibertb7867392007-02-13 13:26:20 +0100252void __init pci_mmcfg_init(int type)
253{
Olivier Galibert9358c692007-02-13 13:26:20 +0100254 int known_bridge = 0;
255
Olivier Galibertb7867392007-02-13 13:26:20 +0100256 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
257 return;
258
Olivier Galibert9358c692007-02-13 13:26:20 +0100259 if (type == 1 && pci_mmcfg_check_hostbridge())
260 known_bridge = 1;
261
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100262 if (!known_bridge) {
Olivier Galibert9358c692007-02-13 13:26:20 +0100263 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100264 pci_mmcfg_reject_broken(type);
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100265 }
Olivier Galibertb7867392007-02-13 13:26:20 +0100266
267 if ((pci_mmcfg_config_num == 0) ||
268 (pci_mmcfg_config == NULL) ||
269 (pci_mmcfg_config[0].address == 0))
270 return;
271
Olivier Galibertb7867392007-02-13 13:26:20 +0100272 if (pci_mmcfg_arch_init()) {
Olivier Galibert5f027382007-02-13 13:26:20 +0100273 if (type == 1)
274 unreachable_devices();
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100275 if (known_bridge)
Aaron Durbina5ba7972007-07-21 17:10:34 +0200276 pci_mmcfg_insert_resources(IORESOURCE_BUSY);
Olivier Galibertb7867392007-02-13 13:26:20 +0100277 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
Aaron Durbina5ba7972007-07-21 17:10:34 +0200278 } else {
279 /*
280 * Signal not to attempt to insert mmcfg resources because
281 * the architecture mmcfg setup could not initialize.
282 */
283 pci_mmcfg_resources_inserted = 1;
Olivier Galibertb7867392007-02-13 13:26:20 +0100284 }
285}
Aaron Durbina5ba7972007-07-21 17:10:34 +0200286
287static int __init pci_mmcfg_late_insert_resources(void)
288{
289 /*
290 * If resources are already inserted or we are not using MMCONFIG,
291 * don't insert the resources.
292 */
293 if ((pci_mmcfg_resources_inserted == 1) ||
294 (pci_probe & PCI_PROBE_MMCONF) == 0 ||
295 (pci_mmcfg_config_num == 0) ||
296 (pci_mmcfg_config == NULL) ||
297 (pci_mmcfg_config[0].address == 0))
298 return 1;
299
300 /*
301 * Attempt to insert the mmcfg resources but not with the busy flag
302 * marked so it won't cause request errors when __request_region is
303 * called.
304 */
305 pci_mmcfg_insert_resources(0);
306
307 return 0;
308}
309
310/*
311 * Perform MMCONFIG resource insertion after PCI initialization to allow for
312 * misprogrammed MCFG tables that state larger sizes but actually conflict
313 * with other system resources.
314 */
315late_initcall(pci_mmcfg_late_insert_resources);