acpi_mcfg.c revision 1.30 1 /* $NetBSD: acpi_mcfg.c,v 1.30 2024/11/10 10:45:37 mlelstv Exp $ */
2
3 /*-
4 * Copyright (C) 2015 NONAKA Kimihiro <nonaka (at) NetBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "opt_pci.h"
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.30 2024/11/10 10:45:37 mlelstv Exp $");
32
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/kmem.h>
36 #include <sys/systm.h>
37
38 #include <dev/pci/pcireg.h>
39 #include <dev/pci/pcivar.h>
40 #include <dev/pci/pci_resource.h>
41 #include <dev/pci/pcidevs.h>
42
43 #include <dev/acpi/acpireg.h>
44 #include <dev/acpi/acpivar.h>
45 #include <dev/acpi/acpi_mcfg.h>
46
47 #include "locators.h"
48
49 #define _COMPONENT ACPI_RESOURCE_COMPONENT
50 ACPI_MODULE_NAME ("acpi_mcfg")
51
52 #define EXTCONF_OFFSET(d, f, r) ((((d) * 8 + (f)) * PCI_EXTCONF_SIZE) + (r))
53
54 #define PCIDEV_SET_VALID(mb, d, f) ((mb)->valid_devs[(d)] |= __BIT((f)))
55 #define PCIDEV_SET_INVALID(mb, d, f) ((mb)->valid_devs[(d)] &= ~__BIT((f)))
56 #define PCIDEV_IS_VALID(mb, d, f) ((mb)->valid_devs[(d)] & __BIT((f)))
57
58 #define EXTCONF_SET_VALID(mb, d, f) ((mb)->valid_extconf[(d)] |= __BIT((f)))
59 #define EXTCONF_SET_INVALID(mb, d, f) ((mb)->valid_extconf[(d)] &= ~__BIT((f)))
60 #define EXTCONF_IS_VALID(mb, d, f) ((mb)->valid_extconf[(d)] & __BIT((f)))
61
62 struct mcfg_segment {
63 uint64_t ms_address; /* Base address */
64 int ms_segment; /* Segment # */
65 int ms_bus_start; /* Start bus # */
66 int ms_bus_end; /* End bus # */
67 bus_space_tag_t ms_bst;
68 struct mcfg_bus {
69 bus_space_handle_t bsh[32][8];
70 uint8_t valid_devs[32];
71 uint8_t valid_extconf[32];
72 int valid_ndevs;
73 pcitag_t last_probed;
74 } *ms_bus;
75 };
76
77 static struct mcfg_segment *mcfg_segs;
78 static int mcfg_nsegs;
79 static ACPI_TABLE_MCFG *mcfg;
80 static int mcfg_inited;
81 static struct acpi_softc *acpi_sc;
82
83 static const struct acpimcfg_ops mcfg_default_ops = {
84 .ao_validate = acpimcfg_default_validate,
85
86 .ao_read = acpimcfg_default_read,
87 .ao_write = acpimcfg_default_write,
88 };
89 static const struct acpimcfg_ops *mcfg_ops = &mcfg_default_ops;
90
91 /*
92 * default operations.
93 */
94 bool
95 acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end)
96 {
97
98 /* Always Ok */
99 return true;
100 }
101
102 uint32_t
103 acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh,
104 bus_addr_t addr)
105 {
106
107 return bus_space_read_4(bst, bsh, addr);
108 }
109
110 void
111 acpimcfg_default_write(bus_space_tag_t bst, bus_space_handle_t bsh,
112 bus_addr_t addr, uint32_t data)
113 {
114
115 bus_space_write_4(bst, bsh, addr, data);
116 }
117
118
119 /*
120 * Check MCFG memory region at system resource
121 */
122 struct acpimcfg_memrange {
123 const char *hid;
124 uint64_t address;
125 int bus_start;
126 int bus_end;
127 bool found;
128 };
129
130 static ACPI_STATUS
131 acpimcfg_parse_callback(ACPI_RESOURCE *res, void *ctx)
132 {
133 struct acpimcfg_memrange *mr = ctx;
134 const char *type;
135 uint64_t size, mapaddr, mapsize;
136 int n;
137
138 switch (res->Type) {
139 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
140 type = "FIXED_MEMORY32";
141 mapaddr = res->Data.FixedMemory32.Address;
142 mapsize = res->Data.FixedMemory32.AddressLength;
143 break;
144
145 case ACPI_RESOURCE_TYPE_ADDRESS32:
146 /* XXX Only fixed size supported for now */
147 if (res->Data.Address32.Address.AddressLength == 0 ||
148 res->Data.Address32.ProducerConsumer != ACPI_CONSUMER)
149 goto out;
150
151 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE)
152 goto out;
153
154 if (res->Data.Address32.MinAddressFixed != ACPI_ADDRESS_FIXED ||
155 res->Data.Address32.MaxAddressFixed != ACPI_ADDRESS_FIXED)
156 goto out;
157
158 type = "ADDRESS32";
159 mapaddr = res->Data.Address32.Address.Minimum;
160 mapsize = res->Data.Address32.Address.AddressLength;
161 break;
162
163 #ifdef _LP64
164 case ACPI_RESOURCE_TYPE_ADDRESS64:
165 /* XXX Only fixed size supported for now */
166 if (res->Data.Address64.Address.AddressLength == 0 ||
167 res->Data.Address64.ProducerConsumer != ACPI_CONSUMER)
168 goto out;
169
170 if (res->Data.Address64.ResourceType != ACPI_MEMORY_RANGE)
171 goto out;
172
173 if (res->Data.Address64.MinAddressFixed != ACPI_ADDRESS_FIXED ||
174 res->Data.Address64.MaxAddressFixed != ACPI_ADDRESS_FIXED)
175 goto out;
176
177 type = "ADDRESS64";
178 mapaddr = res->Data.Address64.Address.Minimum;
179 mapsize = res->Data.Address64.Address.AddressLength;
180 break;
181 #endif
182
183 default:
184 out:
185 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d\n",
186 mr->hid, res->Type);
187 return_ACPI_STATUS(AE_OK);
188 }
189
190 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d(%s), "
191 "Address=0x%016" PRIx64 ", Length=0x%016" PRIx64 "\n",
192 mr->hid, res->Type, type, mapaddr, mapsize);
193
194 if (mr->address < mapaddr || mr->address >= mapaddr + mapsize)
195 return_ACPI_STATUS(AE_OK);
196
197 size = (mr->bus_end - mr->bus_start + 1) * ACPIMCFG_SIZE_PER_BUS;
198
199 /* full map */
200 if (mr->address + size <= mapaddr + mapsize) {
201 mr->found = true;
202 return_ACPI_STATUS(AE_CTRL_TERMINATE);
203 }
204
205 /* partial map */
206 n = (mapsize - (mr->address - mapaddr)) / ACPIMCFG_SIZE_PER_BUS;
207 /* bus_start == bus_end is not allowed. */
208 if (n > 1) {
209 mr->bus_end = mr->bus_start + n - 1;
210 mr->found = true;
211 return_ACPI_STATUS(AE_CTRL_TERMINATE);
212 }
213
214 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d-%d, "
215 "address 0x%016" PRIx64 ": invalid size: request 0x%016" PRIx64
216 ", actual 0x%016" PRIx64 "\n",
217 mr->bus_start, mr->bus_end, mr->address, size, mapsize);
218
219 return_ACPI_STATUS(AE_OK);
220 }
221
222 static ACPI_STATUS
223 acpimcfg_check_system_resource(ACPI_HANDLE handle, UINT32 level, void *ctx,
224 void **retval)
225 {
226 struct acpimcfg_memrange *mr = ctx;
227 ACPI_STATUS status;
228
229 status = AcpiWalkResources(handle, "_CRS", acpimcfg_parse_callback, mr);
230 if (ACPI_FAILURE(status))
231 return_ACPI_STATUS(status);
232
233 if (mr->found)
234 return_ACPI_STATUS(AE_CTRL_TERMINATE);
235
236 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: bus %d-%d, "
237 "address 0x%016" PRIx64 ": no valid region\n", mr->hid,
238 mr->bus_start, mr->bus_end, mr->address);
239
240 return_ACPI_STATUS(AE_OK);
241 }
242
243 static bool
244 acpimcfg_find_system_resource(uint64_t address, int bus_start, int *bus_end)
245 {
246 static const char *system_resource_hid[] = {
247 "PNP0C01", /* System Board */
248 "PNP0C02" /* General ID for reserving resources */
249 };
250 struct acpimcfg_memrange mr;
251 ACPI_STATUS status;
252 int i;
253
254 mr.address = address;
255 mr.bus_start = bus_start;
256 mr.bus_end = *bus_end;
257 mr.found = false;
258
259 for (i = 0; i < __arraycount(system_resource_hid); i++) {
260 mr.hid = system_resource_hid[i];
261 status = AcpiGetDevices(__UNCONST(system_resource_hid[i]),
262 acpimcfg_check_system_resource, &mr, NULL);
263 if (ACPI_FAILURE(status))
264 continue;
265 if (mr.found) {
266 *bus_end = mr.bus_end;
267 return true;
268 }
269 }
270 return false;
271 }
272
273
274 /*
275 * ACPI MCFG
276 */
277 void
278 acpimcfg_probe(struct acpi_softc *sc)
279 {
280 ACPI_MCFG_ALLOCATION *ama;
281 ACPI_STATUS status;
282 uint32_t offset;
283 int i, nsegs;
284
285 if (acpi_sc != NULL)
286 panic("acpi_sc != NULL");
287 acpi_sc = sc;
288
289 status = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg);
290 if (ACPI_FAILURE(status)) {
291 mcfg = NULL;
292 return;
293 }
294
295 nsegs = 0;
296 offset = sizeof(ACPI_TABLE_MCFG);
297 ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
298 for (i = 0; offset + sizeof(ACPI_MCFG_ALLOCATION) <=
299 mcfg->Header.Length; i++) {
300 aprint_debug_dev(sc->sc_dev,
301 "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n",
302 ama->PciSegment, ama->StartBusNumber, ama->EndBusNumber,
303 ama->Address);
304 nsegs++;
305 offset += sizeof(ACPI_MCFG_ALLOCATION);
306 ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
307 }
308 if (nsegs == 0) {
309 mcfg = NULL;
310 return;
311 }
312
313 mcfg_segs = kmem_zalloc(sizeof(*mcfg_segs) * nsegs, KM_SLEEP);
314 mcfg_nsegs = nsegs;
315 }
316
317 int
318 acpimcfg_init(bus_space_tag_t memt, const struct acpimcfg_ops *ops)
319 {
320 ACPI_MCFG_ALLOCATION *ama;
321 struct mcfg_segment *seg;
322 uint32_t offset;
323 int i, n, nsegs, bus_end;
324
325 if (mcfg == NULL)
326 return ENXIO;
327
328 if (mcfg_inited)
329 return 0;
330
331 if (ops != NULL)
332 mcfg_ops = ops;
333
334 nsegs = 0;
335 offset = sizeof(ACPI_TABLE_MCFG);
336 ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
337 for (i = 0; offset < mcfg->Header.Length; i++) {
338 #ifndef _LP64
339 if (ama->Address >= 0x100000000ULL) {
340 aprint_debug_dev(acpi_sc->sc_dev,
341 "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
342 ": ignore (64bit address)\n", ama->PciSegment,
343 ama->StartBusNumber, ama->EndBusNumber,
344 ama->Address);
345 goto next;
346 }
347 #endif
348 /*
349 * Some (broken?) BIOSen have an MCFG table for an empty
350 * bus range. Ignore those tables.
351 */
352 if (ama->StartBusNumber > ama->EndBusNumber) {
353 aprint_debug_dev(acpi_sc->sc_dev,
354 "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
355 ": ignore (bus %d > %d)\n", ama->PciSegment,
356 ama->StartBusNumber, ama->EndBusNumber,
357 ama->Address, ama->StartBusNumber,
358 ama->EndBusNumber);
359 goto next;
360 }
361
362 /* Validate MCFG memory range */
363 bus_end = ama->EndBusNumber;
364 if (mcfg_ops->ao_validate != NULL &&
365 !mcfg_ops->ao_validate(ama->Address, ama->StartBusNumber,
366 &bus_end)) {
367 if (!acpimcfg_find_system_resource(ama->Address,
368 ama->StartBusNumber, &bus_end)) {
369 aprint_debug_dev(acpi_sc->sc_dev,
370 "MCFG: segment %d, bus %d-%d, "
371 "address 0x%016" PRIx64
372 ": ignore (invalid address)\n",
373 ama->PciSegment,
374 ama->StartBusNumber, ama->EndBusNumber,
375 ama->Address);
376 goto next;
377 }
378 }
379 if (ama->EndBusNumber != bus_end) {
380 aprint_debug_dev(acpi_sc->sc_dev,
381 "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
382 " -> bus %d-%d\n", ama->PciSegment,
383 ama->StartBusNumber, ama->EndBusNumber,
384 ama->Address, ama->StartBusNumber, bus_end);
385 }
386
387 #ifndef __HAVE_PCI_GET_SEGMENT
388 if (ama->PciSegment != 0) {
389 aprint_debug_dev(acpi_sc->sc_dev,
390 "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
391 ": ignore (non PCI segment 0)\n", ama->PciSegment,
392 ama->StartBusNumber, bus_end, ama->Address);
393 goto next;
394 }
395 #endif
396
397 seg = &mcfg_segs[nsegs++];
398 seg->ms_address = ama->Address;
399 seg->ms_segment = ama->PciSegment;
400 seg->ms_bus_start = ama->StartBusNumber;
401 seg->ms_bus_end = bus_end;
402 seg->ms_bst = memt;
403 n = seg->ms_bus_end - seg->ms_bus_start + 1;
404 seg->ms_bus = kmem_zalloc(sizeof(*seg->ms_bus) * n, KM_SLEEP);
405
406 next:
407 offset += sizeof(ACPI_MCFG_ALLOCATION);
408 ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
409 }
410 if (nsegs == 0)
411 return ENOENT;
412
413 for (i = 0; i < nsegs; i++) {
414 seg = &mcfg_segs[i];
415 aprint_verbose_dev(acpi_sc->sc_dev,
416 "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n",
417 seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end,
418 seg->ms_address);
419 }
420
421 /* Update # of segment */
422 mcfg_nsegs = nsegs;
423 mcfg_inited = true;
424
425 return 0;
426 }
427
428 static int
429 acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag)
430 {
431 pcireg_t id;
432 int i;
433
434 id = pci_conf_read(pc, tag, PCI_ID_REG);
435 for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) {
436 if (pci_conf_read(pc, tag, i) != id)
437 return false;
438 }
439 return true;
440 }
441
442 static struct mcfg_segment *
443 acpimcfg_get_segment(pci_chipset_tag_t pc, int bus)
444 {
445 struct mcfg_segment *seg;
446 u_int segment;
447 int i;
448
449 segment = pci_get_segment(pc);
450 for (i = 0; i < mcfg_nsegs; i++) {
451 seg = &mcfg_segs[i];
452 if (segment == seg->ms_segment &&
453 bus >= seg->ms_bus_start && bus <= seg->ms_bus_end)
454 return seg;
455 }
456 return NULL;
457 }
458
459 static int
460 acpimcfg_device_probe(const struct pci_attach_args *pa)
461 {
462 pci_chipset_tag_t pc = pa->pa_pc;
463 struct mcfg_segment *seg;
464 struct mcfg_bus *mb;
465 pcitag_t tag;
466 pcireg_t reg;
467 int bus = pa->pa_bus;
468 int dev = pa->pa_device;
469 int func = pa->pa_function;
470 int last_dev, last_func, end_func;
471 int alias = 0;
472 const struct pci_quirkdata *qd;
473 bool force_hasextcnf = false;
474 bool force_noextcnf = false;
475 int i, j;
476
477 seg = acpimcfg_get_segment(pc, bus);
478 if (seg == NULL)
479 return 0;
480
481 mb = &seg->ms_bus[bus - seg->ms_bus_start];
482 tag = pci_make_tag(pc, bus, dev, func);
483
484 /* Mark invalid between last probed device to probed device. */
485 pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func);
486 if (dev != 0 || func != 0) {
487 for (i = last_dev; i <= dev; i++) {
488 end_func = (i == dev) ? func : 8;
489 for (j = last_func; j < end_func; j++) {
490 if (i == last_dev && j == last_func)
491 continue;
492 PCIDEV_SET_INVALID(mb, i, j);
493 }
494 last_func = 0;
495 }
496 }
497 mb->last_probed = tag;
498
499 reg = pci_conf_read(pc, tag, PCI_ID_REG);
500 qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
501 if (qd != NULL && (qd->quirks & PCI_QUIRK_HASEXTCNF) != 0)
502 force_hasextcnf = true;
503 if (qd != NULL && (qd->quirks & PCI_QUIRK_NOEXTCNF) != 0)
504 force_noextcnf = true;
505
506 /* Probe extended configuration space. */
507 if ((!force_hasextcnf) && ((force_noextcnf) ||
508 ((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1)
509 || (reg == 0)
510 || (alias = acpimcfg_ext_conf_is_aliased(pc, tag)))) {
511 aprint_debug_dev(acpi_sc->sc_dev,
512 "MCFG: %03d:%02d:%d: invalid config space "
513 "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func,
514 PCI_CONF_SIZE, reg, alias ? "true" : "false");
515 EXTCONF_SET_INVALID(mb, dev, func);
516 }
517
518 aprint_debug_dev(acpi_sc->sc_dev,
519 "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x extconf=%c)\n",
520 bus, dev, func, PCI_CONF_SIZE, reg,
521 EXTCONF_IS_VALID(mb, dev, func) ? 'Y' : 'N');
522 mb->valid_ndevs++;
523
524 return 0;
525 }
526
527 static void
528 acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus)
529 {
530 static const int wildcard[PCICF_NLOCS] = {
531 PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT
532 };
533
534 sc->sc_bus = bus; /* XXX */
535 sc->sc_pc = pc;
536
537 pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL);
538 }
539
540 int
541 acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus)
542 {
543 struct pci_softc *sc = device_private(self);
544 struct mcfg_segment *seg = NULL;
545 struct mcfg_bus *mb;
546 bus_space_handle_t bsh;
547 bus_addr_t baddr;
548 pcitag_t tag;
549 pcireg_t reg;
550 bool is_e7520_mch;
551 int boff;
552 int last_dev, last_func;
553 int i, j;
554 int error;
555
556 if (!mcfg_inited)
557 return ENXIO;
558
559 seg = acpimcfg_get_segment(pc, bus);
560 if (seg == NULL)
561 return ENOENT;
562
563 boff = bus - seg->ms_bus_start;
564 if (seg->ms_bus[boff].valid_ndevs > 0)
565 return 0;
566
567 mb = &seg->ms_bus[boff];
568 baddr = seg->ms_address + (bus * ACPIMCFG_SIZE_PER_BUS);
569
570 /* Map extended configuration space of all dev/func. */
571 error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0,
572 &bsh);
573 if (error != 0)
574 return error;
575 for (i = 0; i < 32; i++) {
576 for (j = 0; j < 8; j++) {
577 error = bus_space_subregion(seg->ms_bst, bsh,
578 EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE,
579 &mb->bsh[i][j]);
580 if (error != 0)
581 break;
582 }
583 }
584 if (error != 0)
585 return error;
586
587 aprint_debug("\n");
588
589 /* Probe extended configuration space of all devices. */
590 memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs));
591 memset(mb->valid_extconf, 0xff, sizeof(mb->valid_extconf));
592 mb->valid_ndevs = 0;
593 mb->last_probed = pci_make_tag(pc, bus, 0, 0);
594
595 /*
596 * On an Intel E7520 we have to temporarily disable
597 * Enhanced Config Access error detection and reporting
598 * by setting the appropriate error mask in HI_ERRMASK register.
599 *
600 * See "Intel E7520 Memory Controller Hub (MCH) Datasheet",
601 * Document 303006-002, pg. 82
602 */
603 tag = pci_make_tag(pc, 0, 0, 1);
604 reg = pci_conf_read(pc, tag, PCI_ID_REG);
605 is_e7520_mch = (reg ==
606 PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7525_MCHER));
607 if (is_e7520_mch) {
608 reg = pci_conf_read(pc, tag, 0x54);
609 pci_conf_write(pc, tag, 0x54, reg | 0x20);
610 }
611
612 acpimcfg_scan_bus(sc, pc, bus);
613
614 if (is_e7520_mch) {
615 pci_conf_write(pc, tag, 0x54, reg);
616 }
617
618 /* Unmap configuration space of all dev/func. */
619 bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS);
620 memset(mb->bsh, 0, sizeof(mb->bsh));
621
622 if (mb->valid_ndevs == 0) {
623 aprint_debug_dev(acpi_sc->sc_dev,
624 "MCFG: bus %d: no valid devices.\n", bus);
625 memset(mb->valid_devs, 0, sizeof(mb->valid_devs));
626 goto out;
627 }
628
629 /* Mark invalid on remaining all devices. */
630 pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func);
631 for (i = last_dev; i < 32; i++) {
632 for (j = last_func; j < 8; j++) {
633 if (i == last_dev && j == last_func) {
634 /* Don't mark invalid to last probed device. */
635 continue;
636 }
637 PCIDEV_SET_INVALID(mb, i, j);
638 }
639 last_func = 0;
640 }
641
642 /* Map configuration space per dev/func. */
643 for (i = 0; i < 32; i++) {
644 for (j = 0; j < 8; j++) {
645 if (!PCIDEV_IS_VALID(mb, i, j))
646 continue;
647 error = bus_space_map(seg->ms_bst,
648 baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE,
649 0, &mb->bsh[i][j]);
650 if (error != 0) {
651 /* Unmap all handles when map failed. */
652 do {
653 while (--j >= 0) {
654 if (!PCIDEV_IS_VALID(mb, i, j))
655 continue;
656 bus_space_unmap(seg->ms_bst,
657 mb->bsh[i][j],
658 PCI_EXTCONF_SIZE);
659 }
660 j = 8;
661 } while (--i >= 0);
662 memset(mb->valid_devs, 0,
663 sizeof(mb->valid_devs));
664 goto out;
665 }
666 }
667 }
668
669 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus);
670 for (i = 0; i < 32; i++) {
671 for (j = 0; j < 8; j++) {
672 if (PCIDEV_IS_VALID(mb, i, j)) {
673 aprint_debug_dev(acpi_sc->sc_dev,
674 "MCFG: %03d:%02d:%d\n", bus, i, j);
675 }
676 }
677 }
678
679 error = 0;
680 out:
681
682 return error;
683 }
684
685 #ifdef PCI_RESOURCE
686 ACPI_STATUS
687 acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx)
688 {
689 struct pci_resource_info *pciinfo = ctx;
690 bus_addr_t addr;
691 bus_size_t size;
692 int type;
693
694 if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
695 res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
696 res->Type != ACPI_RESOURCE_TYPE_ADDRESS64)
697 return AE_OK;
698
699 if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER)
700 return AE_OK;
701
702 if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
703 res->Data.Address.ResourceType != ACPI_IO_RANGE &&
704 res->Data.Address.ResourceType != ACPI_BUS_NUMBER_RANGE)
705 return AE_OK;
706
707 if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE &&
708 res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) {
709 type = PCI_RANGE_PMEM;
710 } else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE &&
711 res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) {
712 if (res->Type == ACPI_RESOURCE_TYPE_ADDRESS64) {
713 type = PCI_RANGE_PMEM;
714 } else {
715 type = PCI_RANGE_MEM;
716 }
717 } else if (res->Data.Address.ResourceType == ACPI_BUS_NUMBER_RANGE) {
718 type = PCI_RANGE_BUS;
719 } else {
720 KASSERT(res->Data.Address.ResourceType == ACPI_IO_RANGE);
721 type = PCI_RANGE_IO;
722 }
723
724 switch (res->Type) {
725 case ACPI_RESOURCE_TYPE_ADDRESS16:
726 aprint_debug(
727 "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n",
728 res->Data.Address16.Address.Minimum,
729 res->Data.Address16.Address.AddressLength,
730 pci_resource_typename(type));
731 addr = res->Data.Address16.Address.Minimum;
732 size = res->Data.Address16.Address.AddressLength;
733 break;
734 case ACPI_RESOURCE_TYPE_ADDRESS32:
735 aprint_debug(
736 "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n",
737 res->Data.Address32.Address.Minimum,
738 res->Data.Address32.Address.AddressLength,
739 pci_resource_typename(type));
740 addr = res->Data.Address32.Address.Minimum;
741 size = res->Data.Address32.Address.AddressLength;
742 break;
743 case ACPI_RESOURCE_TYPE_ADDRESS64:
744 aprint_debug(
745 "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n",
746 res->Data.Address64.Address.Minimum,
747 res->Data.Address64.Address.AddressLength,
748 pci_resource_typename(type));
749 addr = res->Data.Address64.Address.Minimum;
750 size = res->Data.Address64.Address.AddressLength;
751 break;
752
753 default:
754 return AE_OK;
755 }
756
757 if (size > 0) {
758 pciinfo->ranges[type].start = addr;
759 pciinfo->ranges[type].end = addr + size - 1;
760 }
761
762 return AE_OK;
763 }
764
765 int
766 acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle,
767 int bus, bool mapcfgspace)
768 {
769 struct pci_resource_info pciinfo;
770 struct mcfg_segment *seg;
771 struct mcfg_bus *mb;
772 bus_space_handle_t bsh[256];
773 bool bsh_mapped[256];
774 int error, boff, b, d, f, endbus;
775 bus_addr_t baddr;
776 ACPI_STATUS rv;
777
778 if (mapcfgspace) {
779 seg = acpimcfg_get_segment(pc, bus);
780 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: Bus=%d, Seg=%p\n",
781 bus, seg);
782 if (seg == NULL) {
783 return ENOENT;
784 }
785 endbus = seg->ms_bus_end;
786
787 /*
788 * Map config space for all possible busses and mark them valid
789 * during configuration so pci_configure_bus can access them
790 * through our chipset tag with acpimcfg_conf_read/write below.
791 */
792 memset(bsh_mapped, 0, sizeof(bsh_mapped));
793 for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) {
794 boff = b - seg->ms_bus_start;
795 mb = &seg->ms_bus[boff];
796 baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS);
797
798 /* Map extended configuration space of all dev/func. */
799 error = bus_space_map(seg->ms_bst, baddr,
800 ACPIMCFG_SIZE_PER_BUS, 0, &bsh[b]);
801 if (error != 0) {
802 goto cleanup;
803 }
804 bsh_mapped[b] = true;
805 for (d = 0; d < 32; d++) {
806 for (f = 0; f < 8; f++) {
807 error = bus_space_subregion(seg->ms_bst,
808 bsh[b], EXTCONF_OFFSET(d, f, 0),
809 PCI_EXTCONF_SIZE, &mb->bsh[d][f]);
810 if (error != 0) {
811 break;
812 }
813 }
814 }
815 if (error != 0) {
816 goto cleanup;
817 }
818
819 memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs));
820 }
821 } else {
822 endbus = 255;
823 }
824
825 memset(&pciinfo, 0, sizeof(pciinfo));
826 pciinfo.pc = pc;
827 pciinfo.ranges[PCI_RANGE_BUS].start = bus;
828 pciinfo.ranges[PCI_RANGE_BUS].end = endbus;
829 rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb,
830 &pciinfo);
831 if (ACPI_FAILURE(rv)) {
832 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: Walk _CRS: %ld\n",
833 (long)rv);
834 error = ENXIO;
835 goto cleanup;
836 }
837 error = 0;
838
839 pci_resource_init(&pciinfo);
840
841 cleanup:
842 if (mapcfgspace) {
843 /*
844 * Unmap config space for the segment's busses. Valid devices
845 * will be re-mapped later on by acpimcfg_map_bus.
846 */
847 for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) {
848 boff = b - seg->ms_bus_start;
849 mb = &seg->ms_bus[boff];
850 memset(mb->valid_devs, 0, sizeof(mb->valid_devs));
851
852 if (bsh_mapped[b]) {
853 bus_space_unmap(seg->ms_bst, bsh[b],
854 ACPIMCFG_SIZE_PER_BUS);
855 }
856 }
857 }
858
859 return error;
860 }
861 #else
862 int
863 acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle,
864 int bus, bool mapcfgspace)
865 {
866 return ENXIO;
867 }
868 #endif
869
870 int
871 acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data)
872 {
873 struct mcfg_segment *seg = NULL;
874 struct mcfg_bus *mb;
875 int bus, dev, func;
876
877 KASSERT(reg < PCI_EXTCONF_SIZE);
878 KASSERT((reg & 3) == 0);
879
880 if (!mcfg_inited) {
881 *data = -1;
882 return ENXIO;
883 }
884
885 pci_decompose_tag(pc, tag, &bus, &dev, &func);
886
887 seg = acpimcfg_get_segment(pc, bus);
888 if (seg == NULL) {
889 *data = -1;
890 return ERANGE;
891 }
892
893 mb = &seg->ms_bus[bus - seg->ms_bus_start];
894 if (!PCIDEV_IS_VALID(mb, dev, func)) {
895 *data = -1;
896 return EINVAL;
897 }
898 if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) {
899 *data = -1;
900 return EINVAL;
901 }
902
903 *data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg);
904 return 0;
905 }
906
907 int
908 acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
909 {
910 struct mcfg_segment *seg = NULL;
911 struct mcfg_bus *mb;
912 int bus, dev, func;
913
914 KASSERT(reg < PCI_EXTCONF_SIZE);
915 KASSERT((reg & 3) == 0);
916
917 if (!mcfg_inited)
918 return ENXIO;
919
920 pci_decompose_tag(pc, tag, &bus, &dev, &func);
921
922 seg = acpimcfg_get_segment(pc, bus);
923 if (seg == NULL)
924 return ERANGE;
925
926 mb = &seg->ms_bus[bus - seg->ms_bus_start];
927 if (!PCIDEV_IS_VALID(mb, dev, func))
928 return EINVAL;
929 if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE)
930 return EINVAL;
931
932 mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data);
933 return 0;
934 }
935
936 bool
937 acpimcfg_conf_valid(pci_chipset_tag_t pc, pcitag_t tag, int reg)
938 {
939 struct mcfg_segment *seg = NULL;
940 struct mcfg_bus *mb;
941 int bus, dev, func;
942
943 if (!mcfg_inited)
944 return false;
945
946 pci_decompose_tag(pc, tag, &bus, &dev, &func);
947
948 seg = acpimcfg_get_segment(pc, bus);
949 if (seg == NULL)
950 return false;
951
952 mb = &seg->ms_bus[bus - seg->ms_bus_start];
953 if (!PCIDEV_IS_VALID(mb, dev, func))
954 return false;
955 if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE)
956 return false;
957
958 return true;
959 }
960