1 /* $NetBSD: acpi_mcfg.c,v 1.33 2026/07/05 01:51:58 riastradh 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.33 2026/07/05 01:51:58 riastradh 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 aprint_verbose_dev(acpi_sc->sc_dev, 412 "MCFG: no valid segments found\n"); 413 kmem_free(mcfg_segs, sizeof(*mcfg_segs) * mcfg_nsegs); 414 mcfg_segs = NULL; 415 mcfg_nsegs = 0; 416 return ENOENT; 417 } 418 419 for (i = 0; i < nsegs; i++) { 420 seg = &mcfg_segs[i]; 421 aprint_verbose_dev(acpi_sc->sc_dev, 422 "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", 423 seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end, 424 seg->ms_address); 425 } 426 427 /* Update # of segment */ 428 mcfg_nsegs = nsegs; 429 mcfg_inited = true; 430 431 return 0; 432 } 433 434 static int 435 acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag) 436 { 437 pcireg_t id; 438 int i; 439 440 id = pci_conf_read(pc, tag, PCI_ID_REG); 441 for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) { 442 if (pci_conf_read(pc, tag, i) != id) 443 return false; 444 } 445 return true; 446 } 447 448 static struct mcfg_segment * 449 acpimcfg_get_segment(pci_chipset_tag_t pc, int bus) 450 { 451 struct mcfg_segment *seg; 452 u_int segment; 453 int i; 454 455 segment = pci_get_segment(pc); 456 for (i = 0; i < mcfg_nsegs; i++) { 457 seg = &mcfg_segs[i]; 458 if (segment == seg->ms_segment && 459 bus >= seg->ms_bus_start && bus <= seg->ms_bus_end) 460 return seg; 461 } 462 return NULL; 463 } 464 465 static int 466 acpimcfg_device_probe(const struct pci_attach_args *pa) 467 { 468 pci_chipset_tag_t pc = pa->pa_pc; 469 struct mcfg_segment *seg; 470 struct mcfg_bus *mb; 471 pcitag_t tag; 472 pcireg_t reg; 473 int bus = pa->pa_bus; 474 int dev = pa->pa_device; 475 int func = pa->pa_function; 476 int last_dev, last_func, end_func; 477 int alias = 0; 478 const struct pci_quirkdata *qd; 479 bool force_hasextcnf = false; 480 bool force_noextcnf = false; 481 int i, j; 482 483 seg = acpimcfg_get_segment(pc, bus); 484 if (seg == NULL) 485 return 0; 486 487 mb = &seg->ms_bus[bus - seg->ms_bus_start]; 488 tag = pci_make_tag(pc, bus, dev, func); 489 490 /* Mark invalid between last probed device to probed device. */ 491 pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); 492 if (dev != 0 || func != 0) { 493 for (i = last_dev; i <= dev; i++) { 494 end_func = (i == dev) ? func : 8; 495 for (j = last_func; j < end_func; j++) { 496 if (i == last_dev && j == last_func) 497 continue; 498 PCIDEV_SET_INVALID(mb, i, j); 499 } 500 last_func = 0; 501 } 502 } 503 mb->last_probed = tag; 504 505 reg = pci_conf_read(pc, tag, PCI_ID_REG); 506 qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg)); 507 if (qd != NULL && (qd->quirks & PCI_QUIRK_HASEXTCNF) != 0) 508 force_hasextcnf = true; 509 if (qd != NULL && (qd->quirks & PCI_QUIRK_NOEXTCNF) != 0) 510 force_noextcnf = true; 511 512 /* Probe extended configuration space. */ 513 if ((!force_hasextcnf) && ((force_noextcnf) || 514 ((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1) 515 || (reg == 0) 516 || (alias = acpimcfg_ext_conf_is_aliased(pc, tag)))) { 517 aprint_debug_dev(acpi_sc->sc_dev, 518 "MCFG: %03d:%02d:%d: invalid config space " 519 "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func, 520 PCI_CONF_SIZE, reg, alias ? "true" : "false"); 521 EXTCONF_SET_INVALID(mb, dev, func); 522 } 523 524 aprint_debug_dev(acpi_sc->sc_dev, 525 "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x extconf=%c)\n", 526 bus, dev, func, PCI_CONF_SIZE, reg, 527 EXTCONF_IS_VALID(mb, dev, func) ? 'Y' : 'N'); 528 mb->valid_ndevs++; 529 530 return 0; 531 } 532 533 static void 534 acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus) 535 { 536 static const int wildcard[PCICF_NLOCS] = { 537 PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT 538 }; 539 540 sc->sc_bus = bus; /* XXX */ 541 sc->sc_pc = pc; 542 543 pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL); 544 } 545 546 int 547 acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus) 548 { 549 struct pci_softc *sc = device_private(self); 550 struct mcfg_segment *seg = NULL; 551 struct mcfg_bus *mb; 552 bus_space_handle_t bsh; 553 bus_addr_t baddr; 554 pcitag_t tag; 555 pcireg_t reg; 556 bool is_e7520_mch; 557 int boff; 558 int last_dev, last_func; 559 int i, j; 560 int error; 561 562 if (!mcfg_inited) 563 return ENXIO; 564 565 seg = acpimcfg_get_segment(pc, bus); 566 if (seg == NULL) 567 return ENOENT; 568 569 boff = bus - seg->ms_bus_start; 570 if (seg->ms_bus[boff].valid_ndevs > 0) 571 return 0; 572 573 mb = &seg->ms_bus[boff]; 574 baddr = seg->ms_address + (bus * ACPIMCFG_SIZE_PER_BUS); 575 576 /* Map extended configuration space of all dev/func. */ 577 error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0, 578 &bsh); 579 if (error != 0) 580 return error; 581 for (i = 0; i < 32; i++) { 582 for (j = 0; j < 8; j++) { 583 error = bus_space_subregion(seg->ms_bst, bsh, 584 EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, 585 &mb->bsh[i][j]); 586 if (error != 0) 587 break; 588 } 589 } 590 if (error != 0) 591 return error; 592 593 aprint_debug("\n"); 594 595 /* Probe extended configuration space of all devices. */ 596 memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); 597 memset(mb->valid_extconf, 0xff, sizeof(mb->valid_extconf)); 598 mb->valid_ndevs = 0; 599 mb->last_probed = pci_make_tag(pc, bus, 0, 0); 600 601 /* 602 * On an Intel E7520 we have to temporarily disable 603 * Enhanced Config Access error detection and reporting 604 * by setting the appropriate error mask in HI_ERRMASK register. 605 * 606 * See "Intel E7520 Memory Controller Hub (MCH) Datasheet", 607 * Document 303006-002, pg. 82 608 */ 609 tag = pci_make_tag(pc, 0, 0, 1); 610 reg = pci_conf_read(pc, tag, PCI_ID_REG); 611 is_e7520_mch = (reg == 612 PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7525_MCHER)); 613 if (is_e7520_mch) { 614 reg = pci_conf_read(pc, tag, 0x54); 615 pci_conf_write(pc, tag, 0x54, reg | 0x20); 616 } 617 618 acpimcfg_scan_bus(sc, pc, bus); 619 620 if (is_e7520_mch) { 621 pci_conf_write(pc, tag, 0x54, reg); 622 } 623 624 /* Unmap configuration space of all dev/func. */ 625 bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS); 626 memset(mb->bsh, 0, sizeof(mb->bsh)); 627 628 if (mb->valid_ndevs == 0) { 629 aprint_debug_dev(acpi_sc->sc_dev, 630 "MCFG: bus %d: no valid devices.\n", bus); 631 memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); 632 goto out; 633 } 634 635 /* Mark invalid on remaining all devices. */ 636 pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); 637 for (i = last_dev; i < 32; i++) { 638 for (j = last_func; j < 8; j++) { 639 if (i == last_dev && j == last_func) { 640 /* Don't mark invalid to last probed device. */ 641 continue; 642 } 643 PCIDEV_SET_INVALID(mb, i, j); 644 } 645 last_func = 0; 646 } 647 648 /* Map configuration space per dev/func. */ 649 for (i = 0; i < 32; i++) { 650 for (j = 0; j < 8; j++) { 651 if (!PCIDEV_IS_VALID(mb, i, j)) 652 continue; 653 error = bus_space_map(seg->ms_bst, 654 baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, 655 0, &mb->bsh[i][j]); 656 if (error != 0) { 657 /* Unmap all handles when map failed. */ 658 do { 659 while (--j >= 0) { 660 if (!PCIDEV_IS_VALID(mb, i, j)) 661 continue; 662 bus_space_unmap(seg->ms_bst, 663 mb->bsh[i][j], 664 PCI_EXTCONF_SIZE); 665 } 666 j = 8; 667 } while (--i >= 0); 668 memset(mb->valid_devs, 0, 669 sizeof(mb->valid_devs)); 670 goto out; 671 } 672 } 673 } 674 675 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus); 676 for (i = 0; i < 32; i++) { 677 for (j = 0; j < 8; j++) { 678 if (PCIDEV_IS_VALID(mb, i, j)) { 679 aprint_debug_dev(acpi_sc->sc_dev, 680 "MCFG: %03d:%02d:%d\n", bus, i, j); 681 } 682 } 683 } 684 685 error = 0; 686 out: 687 688 return error; 689 } 690 691 #ifdef PCI_RESOURCE 692 struct acpimcfg_configure_bus_context { 693 struct pci_resource_info pciinfo; 694 bool bus_found; 695 }; 696 697 ACPI_STATUS 698 acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) 699 { 700 struct acpimcfg_configure_bus_context *C = ctx; 701 struct pci_resource_info *pciinfo = &C->pciinfo; 702 bus_addr_t addr; 703 bus_size_t size; 704 int type; 705 706 if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && 707 res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && 708 res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) 709 return AE_OK; 710 711 if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER) 712 return AE_OK; 713 714 if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE && 715 res->Data.Address.ResourceType != ACPI_IO_RANGE && 716 res->Data.Address.ResourceType != ACPI_BUS_NUMBER_RANGE) 717 return AE_OK; 718 719 if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && 720 res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) { 721 type = PCI_RANGE_PMEM; 722 } else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && 723 res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) { 724 if (res->Type == ACPI_RESOURCE_TYPE_ADDRESS64) { 725 type = PCI_RANGE_PMEM; 726 } else { 727 type = PCI_RANGE_MEM; 728 } 729 } else if (res->Data.Address.ResourceType == ACPI_BUS_NUMBER_RANGE) { 730 type = PCI_RANGE_BUS; 731 } else { 732 KASSERT(res->Data.Address.ResourceType == ACPI_IO_RANGE); 733 type = PCI_RANGE_IO; 734 } 735 736 switch (res->Type) { 737 case ACPI_RESOURCE_TYPE_ADDRESS16: 738 aprint_debug( 739 "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n", 740 res->Data.Address16.Address.Minimum, 741 res->Data.Address16.Address.AddressLength, 742 pci_resource_typename(type)); 743 addr = res->Data.Address16.Address.Minimum; 744 size = res->Data.Address16.Address.AddressLength; 745 break; 746 case ACPI_RESOURCE_TYPE_ADDRESS32: 747 aprint_debug( 748 "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n", 749 res->Data.Address32.Address.Minimum, 750 res->Data.Address32.Address.AddressLength, 751 pci_resource_typename(type)); 752 addr = res->Data.Address32.Address.Minimum; 753 size = res->Data.Address32.Address.AddressLength; 754 break; 755 case ACPI_RESOURCE_TYPE_ADDRESS64: 756 aprint_debug( 757 "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n", 758 res->Data.Address64.Address.Minimum, 759 res->Data.Address64.Address.AddressLength, 760 pci_resource_typename(type)); 761 addr = res->Data.Address64.Address.Minimum; 762 size = res->Data.Address64.Address.AddressLength; 763 break; 764 765 default: 766 return AE_OK; 767 } 768 769 if (size > 0) { 770 pci_resource_add_range(pciinfo, type, addr, addr + size - 1); 771 if (type == PCI_RANGE_BUS) 772 C->bus_found = true; 773 } 774 775 return AE_OK; 776 } 777 778 int 779 acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, 780 int bus, bool mapcfgspace) 781 { 782 struct acpimcfg_configure_bus_context context, *C = &context; 783 struct mcfg_segment *seg; 784 struct mcfg_bus *mb; 785 bus_space_handle_t bsh[256]; 786 bool bsh_mapped[256]; 787 int error, boff, b, d, f, endbus; 788 bus_addr_t baddr; 789 ACPI_STATUS rv; 790 791 if (mapcfgspace) { 792 seg = acpimcfg_get_segment(pc, bus); 793 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: Bus=%d, Seg=%p\n", 794 bus, seg); 795 if (seg == NULL) { 796 return ENOENT; 797 } 798 endbus = seg->ms_bus_end; 799 800 /* 801 * Map config space for all possible busses and mark them valid 802 * during configuration so pci_configure_bus can access them 803 * through our chipset tag with acpimcfg_conf_read/write below. 804 */ 805 memset(bsh_mapped, 0, sizeof(bsh_mapped)); 806 for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { 807 boff = b - seg->ms_bus_start; 808 mb = &seg->ms_bus[boff]; 809 baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS); 810 811 /* Map extended configuration space of all dev/func. */ 812 error = bus_space_map(seg->ms_bst, baddr, 813 ACPIMCFG_SIZE_PER_BUS, 0, &bsh[b]); 814 if (error != 0) { 815 goto cleanup; 816 } 817 bsh_mapped[b] = true; 818 for (d = 0; d < 32; d++) { 819 for (f = 0; f < 8; f++) { 820 error = bus_space_subregion(seg->ms_bst, 821 bsh[b], EXTCONF_OFFSET(d, f, 0), 822 PCI_EXTCONF_SIZE, &mb->bsh[d][f]); 823 if (error != 0) { 824 break; 825 } 826 } 827 } 828 if (error != 0) { 829 goto cleanup; 830 } 831 832 memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); 833 } 834 } else { 835 endbus = 255; 836 } 837 838 memset(C, 0, sizeof(*C)); 839 C->pciinfo.pc = pc; 840 rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb, 841 &C->pciinfo); 842 if (ACPI_FAILURE(rv)) { 843 aprint_debug_dev(acpi_sc->sc_dev, "MCFG: Walk _CRS: %ld\n", 844 (long)rv); 845 error = ENXIO; 846 goto cleanup; 847 } 848 849 /* 850 * Paranoia: In case _CRS didn't list any bus ranges, guess 851 * from the MCFG. 852 */ 853 if (!C->bus_found) { 854 aprint_error_dev(acpi_sc->sc_dev, 855 "no PCI bus range in _CRS, guessing %d-%d from MCFG\n", 856 bus, endbus); 857 pci_resource_add_range(&C->pciinfo, PCI_RANGE_BUS, 858 bus, endbus); 859 } 860 861 error = 0; 862 863 pci_resource_init(&C->pciinfo); 864 865 cleanup: 866 if (mapcfgspace) { 867 /* 868 * Unmap config space for the segment's busses. Valid devices 869 * will be re-mapped later on by acpimcfg_map_bus. 870 */ 871 for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { 872 boff = b - seg->ms_bus_start; 873 mb = &seg->ms_bus[boff]; 874 memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); 875 876 if (bsh_mapped[b]) { 877 bus_space_unmap(seg->ms_bst, bsh[b], 878 ACPIMCFG_SIZE_PER_BUS); 879 } 880 } 881 } 882 883 return error; 884 } 885 #else 886 int 887 acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, 888 int bus, bool mapcfgspace) 889 { 890 return ENXIO; 891 } 892 #endif 893 894 int 895 acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data) 896 { 897 struct mcfg_segment *seg = NULL; 898 struct mcfg_bus *mb; 899 int bus, dev, func; 900 901 KASSERT(reg < PCI_EXTCONF_SIZE); 902 KASSERT((reg & 3) == 0); 903 904 if (!mcfg_inited) { 905 *data = -1; 906 return ENXIO; 907 } 908 909 pci_decompose_tag(pc, tag, &bus, &dev, &func); 910 911 seg = acpimcfg_get_segment(pc, bus); 912 if (seg == NULL) { 913 *data = -1; 914 return ERANGE; 915 } 916 917 mb = &seg->ms_bus[bus - seg->ms_bus_start]; 918 if (!PCIDEV_IS_VALID(mb, dev, func)) { 919 *data = -1; 920 return EINVAL; 921 } 922 if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) { 923 *data = -1; 924 return EINVAL; 925 } 926 927 *data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg); 928 return 0; 929 } 930 931 int 932 acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 933 { 934 struct mcfg_segment *seg = NULL; 935 struct mcfg_bus *mb; 936 int bus, dev, func; 937 938 KASSERT(reg < PCI_EXTCONF_SIZE); 939 KASSERT((reg & 3) == 0); 940 941 if (!mcfg_inited) 942 return ENXIO; 943 944 pci_decompose_tag(pc, tag, &bus, &dev, &func); 945 946 seg = acpimcfg_get_segment(pc, bus); 947 if (seg == NULL) 948 return ERANGE; 949 950 mb = &seg->ms_bus[bus - seg->ms_bus_start]; 951 if (!PCIDEV_IS_VALID(mb, dev, func)) 952 return EINVAL; 953 if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) 954 return EINVAL; 955 956 mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data); 957 return 0; 958 } 959 960 bool 961 acpimcfg_conf_valid(pci_chipset_tag_t pc, pcitag_t tag, int reg) 962 { 963 struct mcfg_segment *seg = NULL; 964 struct mcfg_bus *mb; 965 int bus, dev, func; 966 967 if (!mcfg_inited) 968 return false; 969 970 pci_decompose_tag(pc, tag, &bus, &dev, &func); 971 972 seg = acpimcfg_get_segment(pc, bus); 973 if (seg == NULL) 974 return false; 975 976 mb = &seg->ms_bus[bus - seg->ms_bus_start]; 977 if (!PCIDEV_IS_VALID(mb, dev, func)) 978 return false; 979 if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) 980 return false; 981 982 return true; 983 } 984