1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Low-level direct PCI config space access via ECAM - common code between |
4 | * i386 and x86-64. |
5 | * |
6 | * This code does: |
7 | * - known chipset handling |
8 | * - ACPI decoding and validation |
9 | * |
10 | * Per-architecture code takes care of the mappings and accesses |
11 | * themselves. |
12 | */ |
13 | |
14 | #define pr_fmt(fmt) "PCI: " fmt |
15 | |
16 | #include <linux/acpi.h> |
17 | #include <linux/efi.h> |
18 | #include <linux/pci.h> |
19 | #include <linux/init.h> |
20 | #include <linux/bitmap.h> |
21 | #include <linux/dmi.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/mutex.h> |
24 | #include <linux/rculist.h> |
25 | #include <asm/e820/api.h> |
26 | #include <asm/pci_x86.h> |
27 | #include <asm/acpi.h> |
28 | |
29 | /* Indicate if the ECAM resources have been placed into the resource table */ |
30 | static bool pci_mmcfg_running_state; |
31 | static bool pci_mmcfg_arch_init_failed; |
32 | static DEFINE_MUTEX(pci_mmcfg_lock); |
33 | #define pci_mmcfg_lock_held() lock_is_held(&(pci_mmcfg_lock).dep_map) |
34 | |
35 | LIST_HEAD(pci_mmcfg_list); |
36 | |
37 | static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg) |
38 | { |
39 | if (cfg->res.parent) |
40 | release_resource(new: &cfg->res); |
41 | list_del(entry: &cfg->list); |
42 | kfree(objp: cfg); |
43 | } |
44 | |
45 | static void __init free_all_mmcfg(void) |
46 | { |
47 | struct pci_mmcfg_region *cfg, *tmp; |
48 | |
49 | pci_mmcfg_arch_free(); |
50 | list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list) |
51 | pci_mmconfig_remove(cfg); |
52 | } |
53 | |
54 | static void list_add_sorted(struct pci_mmcfg_region *new) |
55 | { |
56 | struct pci_mmcfg_region *cfg; |
57 | |
58 | /* keep list sorted by segment and starting bus number */ |
59 | list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list, pci_mmcfg_lock_held()) { |
60 | if (cfg->segment > new->segment || |
61 | (cfg->segment == new->segment && |
62 | cfg->start_bus >= new->start_bus)) { |
63 | list_add_tail_rcu(new: &new->list, head: &cfg->list); |
64 | return; |
65 | } |
66 | } |
67 | list_add_tail_rcu(new: &new->list, head: &pci_mmcfg_list); |
68 | } |
69 | |
70 | static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start, |
71 | int end, u64 addr) |
72 | { |
73 | struct pci_mmcfg_region *new; |
74 | struct resource *res; |
75 | |
76 | if (addr == 0) |
77 | return NULL; |
78 | |
79 | new = kzalloc(size: sizeof(*new), GFP_KERNEL); |
80 | if (!new) |
81 | return NULL; |
82 | |
83 | new->address = addr; |
84 | new->segment = segment; |
85 | new->start_bus = start; |
86 | new->end_bus = end; |
87 | |
88 | res = &new->res; |
89 | res->start = addr + PCI_MMCFG_BUS_OFFSET(start); |
90 | res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1; |
91 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
92 | snprintf(buf: new->name, PCI_MMCFG_RESOURCE_NAME_LEN, |
93 | fmt: "PCI ECAM %04x [bus %02x-%02x]" , segment, start, end); |
94 | res->name = new->name; |
95 | |
96 | return new; |
97 | } |
98 | |
99 | struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start, |
100 | int end, u64 addr) |
101 | { |
102 | struct pci_mmcfg_region *new; |
103 | |
104 | new = pci_mmconfig_alloc(segment, start, end, addr); |
105 | if (!new) |
106 | return NULL; |
107 | |
108 | mutex_lock(&pci_mmcfg_lock); |
109 | list_add_sorted(new); |
110 | mutex_unlock(lock: &pci_mmcfg_lock); |
111 | |
112 | pr_info("ECAM %pR (base %#lx) for domain %04x [bus %02x-%02x]\n" , |
113 | &new->res, (unsigned long)addr, segment, start, end); |
114 | |
115 | return new; |
116 | } |
117 | |
118 | struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus) |
119 | { |
120 | struct pci_mmcfg_region *cfg; |
121 | |
122 | list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list, pci_mmcfg_lock_held()) |
123 | if (cfg->segment == segment && |
124 | cfg->start_bus <= bus && bus <= cfg->end_bus) |
125 | return cfg; |
126 | |
127 | return NULL; |
128 | } |
129 | |
130 | static const char *__init pci_mmcfg_e7520(void) |
131 | { |
132 | u32 win; |
133 | raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win); |
134 | |
135 | win = win & 0xf000; |
136 | if (win == 0x0000 || win == 0xf000) |
137 | return NULL; |
138 | |
139 | if (pci_mmconfig_add(segment: 0, start: 0, end: 255, addr: win << 16) == NULL) |
140 | return NULL; |
141 | |
142 | return "Intel Corporation E7520 Memory Controller Hub" ; |
143 | } |
144 | |
145 | static const char *__init pci_mmcfg_intel_945(void) |
146 | { |
147 | u32 pciexbar, mask = 0, len = 0; |
148 | |
149 | raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar); |
150 | |
151 | /* Enable bit */ |
152 | if (!(pciexbar & 1)) |
153 | return NULL; |
154 | |
155 | /* Size bits */ |
156 | switch ((pciexbar >> 1) & 3) { |
157 | case 0: |
158 | mask = 0xf0000000U; |
159 | len = 0x10000000U; |
160 | break; |
161 | case 1: |
162 | mask = 0xf8000000U; |
163 | len = 0x08000000U; |
164 | break; |
165 | case 2: |
166 | mask = 0xfc000000U; |
167 | len = 0x04000000U; |
168 | break; |
169 | default: |
170 | return NULL; |
171 | } |
172 | |
173 | /* Errata #2, things break when not aligned on a 256Mb boundary */ |
174 | /* Can only happen in 64M/128M mode */ |
175 | |
176 | if ((pciexbar & mask) & 0x0fffffffU) |
177 | return NULL; |
178 | |
179 | /* Don't hit the APIC registers and their friends */ |
180 | if ((pciexbar & mask) >= 0xf0000000U) |
181 | return NULL; |
182 | |
183 | if (pci_mmconfig_add(segment: 0, start: 0, end: (len >> 20) - 1, addr: pciexbar & mask) == NULL) |
184 | return NULL; |
185 | |
186 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub" ; |
187 | } |
188 | |
189 | static const char *__init pci_mmcfg_amd_fam10h(void) |
190 | { |
191 | u32 low, high, address; |
192 | u64 base, msr; |
193 | int i; |
194 | unsigned segnbits = 0, busnbits, end_bus; |
195 | |
196 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) |
197 | return NULL; |
198 | |
199 | address = MSR_FAM10H_MMIO_CONF_BASE; |
200 | if (rdmsr_safe(address, &low, &high)) |
201 | return NULL; |
202 | |
203 | msr = high; |
204 | msr <<= 32; |
205 | msr |= low; |
206 | |
207 | /* ECAM is not enabled */ |
208 | if (!(msr & FAM10H_MMIO_CONF_ENABLE)) |
209 | return NULL; |
210 | |
211 | base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); |
212 | |
213 | busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & |
214 | FAM10H_MMIO_CONF_BUSRANGE_MASK; |
215 | |
216 | /* |
217 | * only handle bus 0 ? |
218 | * need to skip it |
219 | */ |
220 | if (!busnbits) |
221 | return NULL; |
222 | |
223 | if (busnbits > 8) { |
224 | segnbits = busnbits - 8; |
225 | busnbits = 8; |
226 | } |
227 | |
228 | end_bus = (1 << busnbits) - 1; |
229 | for (i = 0; i < (1 << segnbits); i++) |
230 | if (pci_mmconfig_add(segment: i, start: 0, end: end_bus, |
231 | addr: base + (1<<28) * i) == NULL) { |
232 | free_all_mmcfg(); |
233 | return NULL; |
234 | } |
235 | |
236 | return "AMD Family 10h NB" ; |
237 | } |
238 | |
239 | static bool __initdata mcp55_checked; |
240 | static const char *__init pci_mmcfg_nvidia_mcp55(void) |
241 | { |
242 | int bus; |
243 | int mcp55_mmconf_found = 0; |
244 | |
245 | static const u32 extcfg_regnum __initconst = 0x90; |
246 | static const u32 extcfg_regsize __initconst = 4; |
247 | static const u32 extcfg_enable_mask __initconst = 1 << 31; |
248 | static const u32 extcfg_start_mask __initconst = 0xff << 16; |
249 | static const int extcfg_start_shift __initconst = 16; |
250 | static const u32 extcfg_size_mask __initconst = 0x3 << 28; |
251 | static const int extcfg_size_shift __initconst = 28; |
252 | static const int extcfg_sizebus[] __initconst = { |
253 | 0x100, 0x80, 0x40, 0x20 |
254 | }; |
255 | static const u32 extcfg_base_mask[] __initconst = { |
256 | 0x7ff8, 0x7ffc, 0x7ffe, 0x7fff |
257 | }; |
258 | static const int extcfg_base_lshift __initconst = 25; |
259 | |
260 | /* |
261 | * do check if amd fam10h already took over |
262 | */ |
263 | if (!acpi_disabled || !list_empty(head: &pci_mmcfg_list) || mcp55_checked) |
264 | return NULL; |
265 | |
266 | mcp55_checked = true; |
267 | for (bus = 0; bus < 256; bus++) { |
268 | u64 base; |
269 | u32 l, extcfg; |
270 | u16 vendor, device; |
271 | int start, size_index, end; |
272 | |
273 | raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l); |
274 | vendor = l & 0xffff; |
275 | device = (l >> 16) & 0xffff; |
276 | |
277 | if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device) |
278 | continue; |
279 | |
280 | raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum, |
281 | extcfg_regsize, &extcfg); |
282 | |
283 | if (!(extcfg & extcfg_enable_mask)) |
284 | continue; |
285 | |
286 | size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; |
287 | base = extcfg & extcfg_base_mask[size_index]; |
288 | /* base could > 4G */ |
289 | base <<= extcfg_base_lshift; |
290 | start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; |
291 | end = start + extcfg_sizebus[size_index] - 1; |
292 | if (pci_mmconfig_add(segment: 0, start, end, addr: base) == NULL) |
293 | continue; |
294 | mcp55_mmconf_found++; |
295 | } |
296 | |
297 | if (!mcp55_mmconf_found) |
298 | return NULL; |
299 | |
300 | return "nVidia MCP55" ; |
301 | } |
302 | |
303 | struct pci_mmcfg_hostbridge_probe { |
304 | u32 bus; |
305 | u32 devfn; |
306 | u32 vendor; |
307 | u32 device; |
308 | const char *(*probe)(void); |
309 | }; |
310 | |
311 | static const struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initconst = { |
312 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, |
313 | PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, |
314 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, |
315 | PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, |
316 | { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD, |
317 | 0x1200, pci_mmcfg_amd_fam10h }, |
318 | { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, |
319 | 0x1200, pci_mmcfg_amd_fam10h }, |
320 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA, |
321 | 0x0369, pci_mmcfg_nvidia_mcp55 }, |
322 | }; |
323 | |
324 | static void __init pci_mmcfg_check_end_bus_number(void) |
325 | { |
326 | struct pci_mmcfg_region *cfg, *cfgx; |
327 | |
328 | /* Fixup overlaps */ |
329 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
330 | if (cfg->end_bus < cfg->start_bus) |
331 | cfg->end_bus = 255; |
332 | |
333 | /* Don't access the list head ! */ |
334 | if (cfg->list.next == &pci_mmcfg_list) |
335 | break; |
336 | |
337 | cfgx = list_entry(cfg->list.next, typeof(*cfg), list); |
338 | if (cfg->end_bus >= cfgx->start_bus) |
339 | cfg->end_bus = cfgx->start_bus - 1; |
340 | } |
341 | } |
342 | |
343 | static int __init pci_mmcfg_check_hostbridge(void) |
344 | { |
345 | u32 l; |
346 | u32 bus, devfn; |
347 | u16 vendor, device; |
348 | int i; |
349 | const char *name; |
350 | |
351 | if (!raw_pci_ops) |
352 | return 0; |
353 | |
354 | free_all_mmcfg(); |
355 | |
356 | for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
357 | bus = pci_mmcfg_probes[i].bus; |
358 | devfn = pci_mmcfg_probes[i].devfn; |
359 | raw_pci_ops->read(0, bus, devfn, 0, 4, &l); |
360 | vendor = l & 0xffff; |
361 | device = (l >> 16) & 0xffff; |
362 | |
363 | name = NULL; |
364 | if (pci_mmcfg_probes[i].vendor == vendor && |
365 | pci_mmcfg_probes[i].device == device) |
366 | name = pci_mmcfg_probes[i].probe(); |
367 | |
368 | if (name) |
369 | pr_info("%s with ECAM support\n" , name); |
370 | } |
371 | |
372 | /* some end_bus_number is crazy, fix it */ |
373 | pci_mmcfg_check_end_bus_number(); |
374 | |
375 | return !list_empty(head: &pci_mmcfg_list); |
376 | } |
377 | |
378 | static acpi_status check_mcfg_resource(struct acpi_resource *res, void *data) |
379 | { |
380 | struct resource *mcfg_res = data; |
381 | struct acpi_resource_address64 address; |
382 | acpi_status status; |
383 | |
384 | if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { |
385 | struct acpi_resource_fixed_memory32 *fixmem32 = |
386 | &res->data.fixed_memory32; |
387 | if (!fixmem32) |
388 | return AE_OK; |
389 | if ((mcfg_res->start >= fixmem32->address) && |
390 | (mcfg_res->end < (fixmem32->address + |
391 | fixmem32->address_length))) { |
392 | mcfg_res->flags = 1; |
393 | return AE_CTRL_TERMINATE; |
394 | } |
395 | } |
396 | if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) && |
397 | (res->type != ACPI_RESOURCE_TYPE_ADDRESS64)) |
398 | return AE_OK; |
399 | |
400 | status = acpi_resource_to_address64(resource: res, out: &address); |
401 | if (ACPI_FAILURE(status) || |
402 | (address.address.address_length <= 0) || |
403 | (address.resource_type != ACPI_MEMORY_RANGE)) |
404 | return AE_OK; |
405 | |
406 | if ((mcfg_res->start >= address.address.minimum) && |
407 | (mcfg_res->end < (address.address.minimum + address.address.address_length))) { |
408 | mcfg_res->flags = 1; |
409 | return AE_CTRL_TERMINATE; |
410 | } |
411 | return AE_OK; |
412 | } |
413 | |
414 | static acpi_status find_mboard_resource(acpi_handle handle, u32 lvl, |
415 | void *context, void **rv) |
416 | { |
417 | struct resource *mcfg_res = context; |
418 | |
419 | acpi_walk_resources(device: handle, METHOD_NAME__CRS, |
420 | user_function: check_mcfg_resource, context); |
421 | |
422 | if (mcfg_res->flags) |
423 | return AE_CTRL_TERMINATE; |
424 | |
425 | return AE_OK; |
426 | } |
427 | |
428 | static bool is_acpi_reserved(u64 start, u64 end, enum e820_type not_used) |
429 | { |
430 | struct resource mcfg_res; |
431 | |
432 | mcfg_res.start = start; |
433 | mcfg_res.end = end - 1; |
434 | mcfg_res.flags = 0; |
435 | |
436 | acpi_get_devices(HID: "PNP0C01" , user_function: find_mboard_resource, context: &mcfg_res, NULL); |
437 | |
438 | if (!mcfg_res.flags) |
439 | acpi_get_devices(HID: "PNP0C02" , user_function: find_mboard_resource, context: &mcfg_res, |
440 | NULL); |
441 | |
442 | return mcfg_res.flags; |
443 | } |
444 | |
445 | static bool is_efi_mmio(struct resource *res) |
446 | { |
447 | #ifdef CONFIG_EFI |
448 | u64 start = res->start; |
449 | u64 end = res->start + resource_size(res); |
450 | efi_memory_desc_t *md; |
451 | u64 size, mmio_start, mmio_end; |
452 | |
453 | for_each_efi_memory_desc(md) { |
454 | if (md->type == EFI_MEMORY_MAPPED_IO) { |
455 | size = md->num_pages << EFI_PAGE_SHIFT; |
456 | mmio_start = md->phys_addr; |
457 | mmio_end = mmio_start + size; |
458 | |
459 | if (mmio_start <= start && end <= mmio_end) |
460 | return true; |
461 | } |
462 | } |
463 | #endif |
464 | |
465 | return false; |
466 | } |
467 | |
468 | typedef bool (*check_reserved_t)(u64 start, u64 end, enum e820_type type); |
469 | |
470 | static bool __ref is_mmconf_reserved(check_reserved_t is_reserved, |
471 | struct pci_mmcfg_region *cfg, |
472 | struct device *dev, const char *method) |
473 | { |
474 | u64 addr = cfg->res.start; |
475 | u64 size = resource_size(res: &cfg->res); |
476 | u64 old_size = size; |
477 | int num_buses; |
478 | |
479 | while (!is_reserved(addr, addr + size, E820_TYPE_RESERVED)) { |
480 | size >>= 1; |
481 | if (size < (16UL<<20)) |
482 | break; |
483 | } |
484 | |
485 | if (size < (16UL<<20) && size != old_size) |
486 | return false; |
487 | |
488 | if (dev) |
489 | dev_info(dev, "ECAM %pR reserved as %s\n" , |
490 | &cfg->res, method); |
491 | else |
492 | pr_info("ECAM %pR reserved as %s\n" , &cfg->res, method); |
493 | |
494 | if (old_size != size) { |
495 | /* update end_bus */ |
496 | cfg->end_bus = cfg->start_bus + ((size>>20) - 1); |
497 | num_buses = cfg->end_bus - cfg->start_bus + 1; |
498 | cfg->res.end = cfg->res.start + |
499 | PCI_MMCFG_BUS_OFFSET(num_buses) - 1; |
500 | snprintf(buf: cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, |
501 | fmt: "PCI ECAM %04x [bus %02x-%02x]" , |
502 | cfg->segment, cfg->start_bus, cfg->end_bus); |
503 | |
504 | if (dev) |
505 | dev_info(dev, "ECAM %pR (base %#lx) (size reduced!)\n" , |
506 | &cfg->res, (unsigned long) cfg->address); |
507 | else |
508 | pr_info("ECAM %pR (base %#lx) for %04x [bus%02x-%02x] (size reduced!)\n" , |
509 | &cfg->res, (unsigned long) cfg->address, |
510 | cfg->segment, cfg->start_bus, cfg->end_bus); |
511 | } |
512 | |
513 | return true; |
514 | } |
515 | |
516 | static bool __ref pci_mmcfg_reserved(struct device *dev, |
517 | struct pci_mmcfg_region *cfg, int early) |
518 | { |
519 | struct resource *conflict; |
520 | |
521 | if (!early && !acpi_disabled) { |
522 | if (is_mmconf_reserved(is_reserved: is_acpi_reserved, cfg, dev, |
523 | method: "ACPI motherboard resource" )) |
524 | return true; |
525 | |
526 | if (dev) |
527 | dev_info(dev, FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n" , |
528 | &cfg->res); |
529 | else |
530 | pr_info(FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n" , |
531 | &cfg->res); |
532 | |
533 | if (is_efi_mmio(res: &cfg->res)) { |
534 | pr_info("ECAM %pR is EfiMemoryMappedIO; assuming valid\n" , |
535 | &cfg->res); |
536 | conflict = insert_resource_conflict(parent: &iomem_resource, |
537 | new: &cfg->res); |
538 | if (conflict) |
539 | pr_warn("ECAM %pR conflicts with %s %pR\n" , |
540 | &cfg->res, conflict->name, conflict); |
541 | else |
542 | pr_info("ECAM %pR reserved to work around lack of ACPI motherboard _CRS\n" , |
543 | &cfg->res); |
544 | return true; |
545 | } |
546 | } |
547 | |
548 | /* |
549 | * e820__mapped_all() is marked as __init. |
550 | * All entries from ACPI MCFG table have been checked at boot time. |
551 | * For MCFG information constructed from hotpluggable host bridge's |
552 | * _CBA method, just assume it's reserved. |
553 | */ |
554 | if (pci_mmcfg_running_state) |
555 | return true; |
556 | |
557 | /* Don't try to do this check unless configuration |
558 | type 1 is available. how about type 2 ?*/ |
559 | if (raw_pci_ops) |
560 | return is_mmconf_reserved(is_reserved: e820__mapped_all, cfg, dev, |
561 | method: "E820 entry" ); |
562 | |
563 | return false; |
564 | } |
565 | |
566 | static void __init pci_mmcfg_reject_broken(int early) |
567 | { |
568 | struct pci_mmcfg_region *cfg; |
569 | |
570 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
571 | if (!pci_mmcfg_reserved(NULL, cfg, early)) { |
572 | pr_info("not using ECAM (%pR not reserved)\n" , |
573 | &cfg->res); |
574 | free_all_mmcfg(); |
575 | return; |
576 | } |
577 | } |
578 | } |
579 | |
580 | static bool __init acpi_mcfg_valid_entry(struct acpi_table_mcfg *mcfg, |
581 | struct acpi_mcfg_allocation *cfg) |
582 | { |
583 | if (cfg->address < 0xFFFFFFFF) |
584 | return true; |
585 | |
586 | if (!strncmp(mcfg->header.oem_id, "SGI" , 3)) |
587 | return true; |
588 | |
589 | if ((mcfg->header.revision >= 1) && (dmi_get_bios_year() >= 2010)) |
590 | return true; |
591 | |
592 | pr_err("ECAM at %#llx for %04x [bus %02x-%02x] is above 4GB, ignored\n" , |
593 | cfg->address, cfg->pci_segment, cfg->start_bus_number, |
594 | cfg->end_bus_number); |
595 | return false; |
596 | } |
597 | |
598 | static int __init pci_parse_mcfg(struct acpi_table_header *) |
599 | { |
600 | struct acpi_table_mcfg *mcfg; |
601 | struct acpi_mcfg_allocation *cfg_table, *cfg; |
602 | unsigned long i; |
603 | int entries; |
604 | |
605 | if (!header) |
606 | return -EINVAL; |
607 | |
608 | mcfg = (struct acpi_table_mcfg *)header; |
609 | |
610 | /* how many config structures do we have */ |
611 | free_all_mmcfg(); |
612 | entries = 0; |
613 | i = header->length - sizeof(struct acpi_table_mcfg); |
614 | while (i >= sizeof(struct acpi_mcfg_allocation)) { |
615 | entries++; |
616 | i -= sizeof(struct acpi_mcfg_allocation); |
617 | } |
618 | if (entries == 0) { |
619 | pr_err("MCFG has no entries\n" ); |
620 | return -ENODEV; |
621 | } |
622 | |
623 | cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1]; |
624 | for (i = 0; i < entries; i++) { |
625 | cfg = &cfg_table[i]; |
626 | if (!acpi_mcfg_valid_entry(mcfg, cfg)) { |
627 | free_all_mmcfg(); |
628 | return -ENODEV; |
629 | } |
630 | |
631 | if (pci_mmconfig_add(segment: cfg->pci_segment, start: cfg->start_bus_number, |
632 | end: cfg->end_bus_number, addr: cfg->address) == NULL) { |
633 | pr_warn("no memory for MCFG entries\n" ); |
634 | free_all_mmcfg(); |
635 | return -ENOMEM; |
636 | } |
637 | } |
638 | |
639 | return 0; |
640 | } |
641 | |
642 | #ifdef CONFIG_ACPI_APEI |
643 | extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size, |
644 | void *data), void *data); |
645 | |
646 | static int pci_mmcfg_for_each_region(int (*func)(__u64 start, __u64 size, |
647 | void *data), void *data) |
648 | { |
649 | struct pci_mmcfg_region *cfg; |
650 | int rc; |
651 | |
652 | if (list_empty(head: &pci_mmcfg_list)) |
653 | return 0; |
654 | |
655 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
656 | rc = func(cfg->res.start, resource_size(res: &cfg->res), data); |
657 | if (rc) |
658 | return rc; |
659 | } |
660 | |
661 | return 0; |
662 | } |
663 | #define set_apei_filter() (arch_apei_filter_addr = pci_mmcfg_for_each_region) |
664 | #else |
665 | #define set_apei_filter() |
666 | #endif |
667 | |
668 | static void __init __pci_mmcfg_init(int early) |
669 | { |
670 | pr_debug("%s(%s)\n" , __func__, early ? "early" : "late" ); |
671 | |
672 | pci_mmcfg_reject_broken(early); |
673 | if (list_empty(head: &pci_mmcfg_list)) |
674 | return; |
675 | |
676 | if (pcibios_last_bus < 0) { |
677 | const struct pci_mmcfg_region *cfg; |
678 | |
679 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
680 | if (cfg->segment) |
681 | break; |
682 | pcibios_last_bus = cfg->end_bus; |
683 | } |
684 | } |
685 | |
686 | if (pci_mmcfg_arch_init()) |
687 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; |
688 | else { |
689 | free_all_mmcfg(); |
690 | pci_mmcfg_arch_init_failed = true; |
691 | } |
692 | } |
693 | |
694 | static int __initdata known_bridge; |
695 | |
696 | void __init pci_mmcfg_early_init(void) |
697 | { |
698 | pr_debug("%s() pci_probe %#x\n" , __func__, pci_probe); |
699 | |
700 | if (pci_probe & PCI_PROBE_MMCONF) { |
701 | if (pci_mmcfg_check_hostbridge()) |
702 | known_bridge = 1; |
703 | else |
704 | acpi_table_parse(ACPI_SIG_MCFG, handler: pci_parse_mcfg); |
705 | __pci_mmcfg_init(early: 1); |
706 | |
707 | set_apei_filter(); |
708 | } |
709 | } |
710 | |
711 | void __init pci_mmcfg_late_init(void) |
712 | { |
713 | pr_debug("%s() pci_probe %#x\n" , __func__, pci_probe); |
714 | |
715 | /* ECAM disabled */ |
716 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
717 | return; |
718 | |
719 | if (known_bridge) |
720 | return; |
721 | |
722 | /* ECAM hasn't been enabled yet, try again */ |
723 | if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) { |
724 | acpi_table_parse(ACPI_SIG_MCFG, handler: pci_parse_mcfg); |
725 | __pci_mmcfg_init(early: 0); |
726 | } |
727 | } |
728 | |
729 | static int __init pci_mmcfg_late_insert_resources(void) |
730 | { |
731 | struct pci_mmcfg_region *cfg; |
732 | |
733 | pci_mmcfg_running_state = true; |
734 | |
735 | pr_debug("%s() pci_probe %#x\n" , __func__, pci_probe); |
736 | |
737 | /* If we are not using ECAM, don't insert the resources. */ |
738 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
739 | return 1; |
740 | |
741 | /* |
742 | * Attempt to insert the mmcfg resources but not with the busy flag |
743 | * marked so it won't cause request errors when __request_region is |
744 | * called. |
745 | */ |
746 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
747 | if (!cfg->res.parent) { |
748 | pr_debug("%s() insert %pR\n" , __func__, &cfg->res); |
749 | insert_resource(parent: &iomem_resource, new: &cfg->res); |
750 | } |
751 | } |
752 | |
753 | return 0; |
754 | } |
755 | |
756 | /* |
757 | * Perform ECAM resource insertion after PCI initialization to allow for |
758 | * misprogrammed MCFG tables that state larger sizes but actually conflict |
759 | * with other system resources. |
760 | */ |
761 | late_initcall(pci_mmcfg_late_insert_resources); |
762 | |
763 | /* Add ECAM information for host bridges */ |
764 | int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, |
765 | phys_addr_t addr) |
766 | { |
767 | int rc; |
768 | struct resource *tmp = NULL; |
769 | struct pci_mmcfg_region *cfg; |
770 | |
771 | dev_dbg(dev, "%s(%04x [bus %02x-%02x])\n" , __func__, seg, start, end); |
772 | |
773 | if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed) |
774 | return -ENODEV; |
775 | |
776 | if (start > end) |
777 | return -EINVAL; |
778 | |
779 | mutex_lock(&pci_mmcfg_lock); |
780 | cfg = pci_mmconfig_lookup(segment: seg, bus: start); |
781 | if (cfg) { |
782 | if (cfg->end_bus < end) |
783 | dev_info(dev, FW_INFO "ECAM %pR for domain %04x [bus %02x-%02x] only partially covers this bridge\n" , |
784 | &cfg->res, cfg->segment, cfg->start_bus, |
785 | cfg->end_bus); |
786 | mutex_unlock(lock: &pci_mmcfg_lock); |
787 | return -EEXIST; |
788 | } |
789 | |
790 | /* |
791 | * Don't move earlier; we must return -EEXIST, not -EINVAL, if |
792 | * pci_mmconfig_lookup() finds something |
793 | */ |
794 | if (!addr) { |
795 | mutex_unlock(lock: &pci_mmcfg_lock); |
796 | return -EINVAL; |
797 | } |
798 | |
799 | rc = -EBUSY; |
800 | cfg = pci_mmconfig_alloc(segment: seg, start, end, addr); |
801 | if (cfg == NULL) { |
802 | dev_warn(dev, "fail to add ECAM (out of memory)\n" ); |
803 | rc = -ENOMEM; |
804 | } else if (!pci_mmcfg_reserved(dev, cfg, early: 0)) { |
805 | dev_warn(dev, FW_BUG "ECAM %pR isn't reserved\n" , |
806 | &cfg->res); |
807 | } else { |
808 | /* Insert resource if it's not in boot stage */ |
809 | if (pci_mmcfg_running_state) |
810 | tmp = insert_resource_conflict(parent: &iomem_resource, |
811 | new: &cfg->res); |
812 | |
813 | if (tmp) { |
814 | dev_warn(dev, "ECAM %pR conflicts with %s %pR\n" , |
815 | &cfg->res, tmp->name, tmp); |
816 | } else if (pci_mmcfg_arch_map(cfg)) { |
817 | dev_warn(dev, "fail to map ECAM %pR\n" , &cfg->res); |
818 | } else { |
819 | list_add_sorted(new: cfg); |
820 | dev_info(dev, "ECAM %pR (base %#lx)\n" , |
821 | &cfg->res, (unsigned long)addr); |
822 | cfg = NULL; |
823 | rc = 0; |
824 | } |
825 | } |
826 | |
827 | if (cfg) { |
828 | if (cfg->res.parent) |
829 | release_resource(new: &cfg->res); |
830 | kfree(objp: cfg); |
831 | } |
832 | |
833 | mutex_unlock(lock: &pci_mmcfg_lock); |
834 | |
835 | return rc; |
836 | } |
837 | |
838 | /* Delete ECAM information for host bridges */ |
839 | int pci_mmconfig_delete(u16 seg, u8 start, u8 end) |
840 | { |
841 | struct pci_mmcfg_region *cfg; |
842 | |
843 | mutex_lock(&pci_mmcfg_lock); |
844 | list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) |
845 | if (cfg->segment == seg && cfg->start_bus == start && |
846 | cfg->end_bus == end) { |
847 | list_del_rcu(entry: &cfg->list); |
848 | synchronize_rcu(); |
849 | pci_mmcfg_arch_unmap(cfg); |
850 | if (cfg->res.parent) |
851 | release_resource(new: &cfg->res); |
852 | mutex_unlock(lock: &pci_mmcfg_lock); |
853 | kfree(objp: cfg); |
854 | return 0; |
855 | } |
856 | mutex_unlock(lock: &pci_mmcfg_lock); |
857 | |
858 | return -ENOENT; |
859 | } |
860 | |