1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2016 Joyent, Inc. 24 * Copyright 2019 Western Digital Corporation 25 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 26 * Copyright 2022 Oxide Computer Company 27 */ 28 29 /* 30 * This file contains the x86 PCI platform resource discovery backend. This uses 31 * data from a combination of sources, preferring ACPI, if present, and if not, 32 * falling back to either the PCI hot-plug resource table or the mps tables. 33 * 34 * Today, to get information from ACPI we need to start from a dev_info_t. This 35 * is partly why the PRD interface has a callback for getting information about 36 * a dev_info_t. It also means we cannot initialize the tables with information 37 * until all devices have been initially scanned. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/memlist.h> 42 #include <sys/pci.h> 43 #include <sys/pci_impl.h> 44 #include <sys/pci_cfgspace_impl.h> 45 #include <sys/sunndi.h> 46 #include <sys/systm.h> 47 #include <sys/cmn_err.h> 48 #include <sys/acpi/acpi.h> 49 #include <sys/acpica.h> 50 #include <sys/plat/pci_prd.h> 51 #include "mps_table.h" 52 #include "pcihrt.h" 53 54 extern int pci_bios_maxbus; 55 56 int pci_prd_debug = 0; 57 #define dprintf if (pci_prd_debug) printf 58 #define dcmn_err if (pci_prd_debug != 0) cmn_err 59 60 static int tbl_init = 0; 61 static uchar_t *mps_extp = NULL; 62 static uchar_t *mps_ext_endp = NULL; 63 static struct php_entry *hrt_hpep; 64 static uint_t hrt_entry_cnt = 0; 65 static int acpi_cb_cnt = 0; 66 static pci_prd_upcalls_t *prd_upcalls; 67 68 static void mps_probe(void); 69 static void acpi_pci_probe(void); 70 static int mps_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **); 71 static void hrt_probe(void); 72 static int hrt_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **); 73 static int acpi_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **); 74 static uchar_t *find_sig(uchar_t *cp, int len, char *sig); 75 static int checksum(unsigned char *cp, int len); 76 static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context); 77 static void acpi_trim_bus_ranges(void); 78 79 /* 80 * -1 = attempt ACPI resource discovery 81 * 0 = don't attempt ACPI resource discovery 82 * 1 = ACPI resource discovery successful 83 */ 84 volatile int acpi_resource_discovery = -1; 85 86 struct memlist *acpi_io_res[PCI_MAX_BUS_NUM]; 87 struct memlist *acpi_mem_res[PCI_MAX_BUS_NUM]; 88 struct memlist *acpi_pmem_res[PCI_MAX_BUS_NUM]; 89 struct memlist *acpi_bus_res[PCI_MAX_BUS_NUM]; 90 91 /* 92 * This indicates whether or not we have a traditional x86 BIOS present or not. 93 */ 94 static boolean_t pci_prd_have_bios = B_TRUE; 95 96 /* 97 * This value is set up as part of PCI configuration space initialization. 98 */ 99 extern int pci_bios_maxbus; 100 101 static void 102 acpi_pci_probe(void) 103 { 104 ACPI_HANDLE ah; 105 int bus; 106 107 if (acpi_resource_discovery == 0) 108 return; 109 110 for (bus = 0; bus <= pci_bios_maxbus; bus++) { 111 dev_info_t *dip; 112 113 dip = prd_upcalls->pru_bus2dip_f(bus); 114 if (dip == NULL || 115 (ACPI_FAILURE(acpica_get_handle(dip, &ah)))) 116 continue; 117 118 (void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb, 119 (void *)(uintptr_t)bus); 120 } 121 122 if (acpi_cb_cnt > 0) { 123 acpi_resource_discovery = 1; 124 acpi_trim_bus_ranges(); 125 } 126 } 127 128 /* 129 * Trim overlapping bus ranges in acpi_bus_res[] 130 * Some BIOSes report root-bridges with bus ranges that 131 * overlap, for example:"0..255" and "8..255". Lower-numbered 132 * ranges are trimmed by upper-numbered ranges (so "0..255" would 133 * be trimmed to "0..7", in the example). 134 */ 135 static void 136 acpi_trim_bus_ranges(void) 137 { 138 struct memlist *ranges, *current; 139 int bus; 140 141 ranges = NULL; 142 143 /* 144 * Assumptions: 145 * - there exists at most 1 bus range entry for each bus number 146 * - there are no (broken) ranges that start at the same bus number 147 */ 148 for (bus = 0; bus < PCI_MAX_BUS_NUM; bus++) { 149 struct memlist *prev, *orig, *new; 150 /* skip buses with no range entry */ 151 if ((orig = acpi_bus_res[bus]) == NULL) 152 continue; 153 154 /* 155 * create copy of existing range and overload 156 * 'prev' pointer to link existing to new copy 157 */ 158 new = memlist_alloc(); 159 new->ml_address = orig->ml_address; 160 new->ml_size = orig->ml_size; 161 new->ml_prev = orig; 162 163 /* sorted insertion of 'new' into ranges list */ 164 for (current = ranges, prev = NULL; current != NULL; 165 prev = current, current = current->ml_next) 166 if (new->ml_address < current->ml_address) 167 break; 168 169 if (prev == NULL) { 170 /* place at beginning of (possibly) empty list */ 171 new->ml_next = ranges; 172 ranges = new; 173 } else { 174 /* place in list (possibly at end) */ 175 new->ml_next = current; 176 prev->ml_next = new; 177 } 178 } 179 180 /* scan the list, perform trimming */ 181 current = ranges; 182 while (current != NULL) { 183 struct memlist *next = current->ml_next; 184 185 /* done when no range above current */ 186 if (next == NULL) 187 break; 188 189 /* 190 * trim size in original range element 191 * (current->ml_prev points to the original range) 192 */ 193 if ((current->ml_address + current->ml_size) > next->ml_address) 194 current->ml_prev->ml_size = 195 next->ml_address - current->ml_address; 196 197 current = next; 198 } 199 200 /* discard the list */ 201 memlist_free_all(&ranges); /* OK if ranges == NULL */ 202 } 203 204 static int 205 acpi_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res) 206 { 207 ASSERT3U(bus, <, PCI_MAX_BUS_NUM); 208 209 switch (type) { 210 case PCI_PRD_R_IO: 211 *res = acpi_io_res[bus]; 212 break; 213 case PCI_PRD_R_MMIO: 214 *res = acpi_mem_res[bus]; 215 break; 216 case PCI_PRD_R_PREFETCH: 217 *res = acpi_pmem_res[bus]; 218 break; 219 case PCI_PRD_R_BUS: 220 *res = acpi_bus_res[bus]; 221 break; 222 default: 223 *res = NULL; 224 break; 225 } 226 227 /* memlist_count() treats NULL head as zero-length */ 228 return (memlist_count(*res)); 229 } 230 231 static struct memlist ** 232 rlistpp(UINT8 t, UINT8 caching, int bus) 233 { 234 switch (t) { 235 case ACPI_MEMORY_RANGE: 236 if (caching == ACPI_PREFETCHABLE_MEMORY) 237 return (&acpi_pmem_res[bus]); 238 else 239 return (&acpi_mem_res[bus]); 240 break; 241 242 case ACPI_IO_RANGE: 243 return (&acpi_io_res[bus]); 244 break; 245 246 case ACPI_BUS_NUMBER_RANGE: 247 return (&acpi_bus_res[bus]); 248 break; 249 } 250 251 return (NULL); 252 } 253 254 static void 255 acpi_dbg(uint_t bus, uint64_t addr, uint64_t len, uint8_t caching, uint8_t type, 256 char *tag) 257 { 258 char *s; 259 260 switch (type) { 261 case ACPI_MEMORY_RANGE: 262 s = "MEM"; 263 break; 264 case ACPI_IO_RANGE: 265 s = "IO"; 266 break; 267 case ACPI_BUS_NUMBER_RANGE: 268 s = "BUS"; 269 break; 270 default: 271 s = "???"; 272 break; 273 } 274 275 dprintf("ACPI: bus %x %s/%s %lx/%lx (Caching: %x)\n", bus, 276 tag, s, addr, len, caching); 277 } 278 279 280 static ACPI_STATUS 281 acpi_wr_cb(ACPI_RESOURCE *rp, void *context) 282 { 283 int bus = (intptr_t)context; 284 285 /* ignore consumed resources */ 286 if (rp->Data.Address.ProducerConsumer == 1) 287 return (AE_OK); 288 289 switch (rp->Type) { 290 case ACPI_RESOURCE_TYPE_IRQ: 291 /* never expect to see a PCI bus produce an Interrupt */ 292 dprintf("%s\n", "IRQ"); 293 break; 294 295 case ACPI_RESOURCE_TYPE_DMA: 296 /* never expect to see a PCI bus produce DMA */ 297 dprintf("%s\n", "DMA"); 298 break; 299 300 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 301 dprintf("%s\n", "START_DEPENDENT"); 302 break; 303 304 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 305 dprintf("%s\n", "END_DEPENDENT"); 306 break; 307 308 case ACPI_RESOURCE_TYPE_IO: 309 if (rp->Data.Io.AddressLength == 0) 310 break; 311 acpi_cb_cnt++; 312 memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum, 313 rp->Data.Io.AddressLength); 314 if (pci_prd_debug != 0) { 315 acpi_dbg(bus, rp->Data.Io.Minimum, 316 rp->Data.Io.AddressLength, 0, ACPI_IO_RANGE, "IO"); 317 } 318 break; 319 320 case ACPI_RESOURCE_TYPE_FIXED_IO: 321 /* only expect to see this as a consumer */ 322 dprintf("%s\n", "FIXED_IO"); 323 break; 324 325 case ACPI_RESOURCE_TYPE_VENDOR: 326 dprintf("%s\n", "VENDOR"); 327 break; 328 329 case ACPI_RESOURCE_TYPE_END_TAG: 330 dprintf("%s\n", "END_TAG"); 331 break; 332 333 case ACPI_RESOURCE_TYPE_MEMORY24: 334 /* only expect to see this as a consumer */ 335 dprintf("%s\n", "MEMORY24"); 336 break; 337 338 case ACPI_RESOURCE_TYPE_MEMORY32: 339 /* only expect to see this as a consumer */ 340 dprintf("%s\n", "MEMORY32"); 341 break; 342 343 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 344 /* only expect to see this as a consumer */ 345 dprintf("%s\n", "FIXED_MEMORY32"); 346 break; 347 348 case ACPI_RESOURCE_TYPE_ADDRESS16: 349 if (rp->Data.Address16.Address.AddressLength == 0) 350 break; 351 acpi_cb_cnt++; 352 memlist_insert(rlistpp(rp->Data.Address16.ResourceType, 353 rp->Data.Address.Info.Mem.Caching, bus), 354 rp->Data.Address16.Address.Minimum, 355 rp->Data.Address16.Address.AddressLength); 356 if (pci_prd_debug != 0) { 357 acpi_dbg(bus, 358 rp->Data.Address16.Address.Minimum, 359 rp->Data.Address16.Address.AddressLength, 360 rp->Data.Address.Info.Mem.Caching, 361 rp->Data.Address16.ResourceType, "ADDRESS16"); 362 } 363 break; 364 365 case ACPI_RESOURCE_TYPE_ADDRESS32: 366 if (rp->Data.Address32.Address.AddressLength == 0) 367 break; 368 acpi_cb_cnt++; 369 memlist_insert(rlistpp(rp->Data.Address32.ResourceType, 370 rp->Data.Address.Info.Mem.Caching, bus), 371 rp->Data.Address32.Address.Minimum, 372 rp->Data.Address32.Address.AddressLength); 373 if (pci_prd_debug != 0) { 374 acpi_dbg(bus, 375 rp->Data.Address32.Address.Minimum, 376 rp->Data.Address32.Address.AddressLength, 377 rp->Data.Address.Info.Mem.Caching, 378 rp->Data.Address32.ResourceType, "ADDRESS32"); 379 } 380 break; 381 382 case ACPI_RESOURCE_TYPE_ADDRESS64: 383 if (rp->Data.Address64.Address.AddressLength == 0) 384 break; 385 386 acpi_cb_cnt++; 387 memlist_insert(rlistpp(rp->Data.Address64.ResourceType, 388 rp->Data.Address.Info.Mem.Caching, bus), 389 rp->Data.Address64.Address.Minimum, 390 rp->Data.Address64.Address.AddressLength); 391 if (pci_prd_debug != 0) { 392 acpi_dbg(bus, 393 rp->Data.Address64.Address.Minimum, 394 rp->Data.Address64.Address.AddressLength, 395 rp->Data.Address.Info.Mem.Caching, 396 rp->Data.Address64.ResourceType, "ADDRESS64"); 397 } 398 break; 399 400 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 401 if (rp->Data.ExtAddress64.Address.AddressLength == 0) 402 break; 403 acpi_cb_cnt++; 404 memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType, 405 rp->Data.Address.Info.Mem.Caching, bus), 406 rp->Data.ExtAddress64.Address.Minimum, 407 rp->Data.ExtAddress64.Address.AddressLength); 408 if (pci_prd_debug != 0) { 409 acpi_dbg(bus, 410 rp->Data.ExtAddress64.Address.Minimum, 411 rp->Data.ExtAddress64.Address.AddressLength, 412 rp->Data.Address.Info.Mem.Caching, 413 rp->Data.ExtAddress64.ResourceType, "EXTADDRESS64"); 414 } 415 break; 416 417 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 418 /* never expect to see a PCI bus produce an Interrupt */ 419 dprintf("%s\n", "EXTENDED_IRQ"); 420 break; 421 422 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 423 /* never expect to see a PCI bus produce an GAS */ 424 dprintf("%s\n", "GENERIC_REGISTER"); 425 break; 426 } 427 428 return (AE_OK); 429 } 430 431 static void 432 mps_probe(void) 433 { 434 uchar_t *extp; 435 struct mps_fps_hdr *fpp = NULL; 436 struct mps_ct_hdr *ctp; 437 uintptr_t ebda_start, base_end; 438 ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg; 439 440 base_size = *((ushort_t *)(0x413)); 441 ebda_seg = *((ushort_t *)(0x40e)); 442 ebda_start = ((uint32_t)ebda_seg) << 4; 443 if (ebda_seg != 0) { 444 fpp = (struct mps_fps_hdr *)find_sig( 445 (uchar_t *)ebda_start, 1024, "_MP_"); 446 } 447 if (fpp == NULL) { 448 base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0; 449 if (base_end_seg != ebda_seg) { 450 base_end = ((uintptr_t)base_end_seg) << 4; 451 fpp = (struct mps_fps_hdr *)find_sig( 452 (uchar_t *)base_end, 1024, "_MP_"); 453 } 454 } 455 if (fpp == NULL) { 456 fpp = (struct mps_fps_hdr *)find_sig( 457 (uchar_t *)0xF0000, 0x10000, "_MP_"); 458 } 459 460 if (fpp == NULL) { 461 dprintf("MP Spec table doesn't exist"); 462 return; 463 } else { 464 dprintf("Found MP Floating Pointer Structure at %p\n", 465 (void *)fpp); 466 } 467 468 if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) { 469 dprintf("MP Floating Pointer Structure checksum error"); 470 return; 471 } 472 473 ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr; 474 if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */ 475 dprintf("MP Configuration Table signature is wrong"); 476 return; 477 } 478 479 base_len = ctp->ct_len; 480 if (checksum((uchar_t *)ctp, base_len) != 0) { 481 dprintf("MP Configuration Table checksum error"); 482 return; 483 } 484 if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */ 485 dprintf("MP Spec 1.1 found - extended table doesn't exist"); 486 return; 487 } 488 if ((ext_len = ctp->ct_ext_tbl_len) == 0) { 489 dprintf("MP Spec 1.4 found - extended table doesn't exist"); 490 return; 491 } 492 extp = (uchar_t *)ctp + base_len; 493 if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) { 494 dprintf("MP Extended Table checksum error"); 495 return; 496 } 497 mps_extp = extp; 498 mps_ext_endp = mps_extp + ext_len; 499 } 500 501 502 static int 503 mps_find_bus_res(uint32_t bus, pci_prd_rsrc_t rsrc, struct memlist **res) 504 { 505 struct sasm *sasmp; 506 uchar_t *extp; 507 int res_cnt, type; 508 509 ASSERT3U(bus, <, PCI_MAX_BUS_NUM); 510 511 if (mps_extp == NULL) 512 return (0); 513 514 switch (rsrc) { 515 case PCI_PRD_R_IO: 516 type = IO_TYPE; 517 break; 518 case PCI_PRD_R_MMIO: 519 type = MEM_TYPE; 520 break; 521 case PCI_PRD_R_PREFETCH: 522 type = PREFETCH_TYPE; 523 break; 524 case PCI_PRD_R_BUS: 525 type = BUSRANGE_TYPE; 526 break; 527 default: 528 *res = NULL; 529 return (0); 530 } 531 532 extp = mps_extp; 533 res_cnt = 0; 534 while (extp < mps_ext_endp) { 535 switch (*extp) { 536 case SYS_AS_MAPPING: 537 sasmp = (struct sasm *)extp; 538 if (sasmp->sasm_as_type == type && 539 sasmp->sasm_bus_id == bus) { 540 uint64_t base, len; 541 542 base = (uint64_t)sasmp->sasm_as_base | 543 (uint64_t)sasmp->sasm_as_base_hi << 32; 544 len = (uint64_t)sasmp->sasm_as_len | 545 (uint64_t)sasmp->sasm_as_len_hi << 32; 546 memlist_insert(res, base, len); 547 res_cnt++; 548 } 549 extp += SYS_AS_MAPPING_SIZE; 550 break; 551 case BUS_HIERARCHY_DESC: 552 extp += BUS_HIERARCHY_DESC_SIZE; 553 break; 554 case COMP_BUS_AS_MODIFIER: 555 extp += COMP_BUS_AS_MODIFIER_SIZE; 556 break; 557 default: 558 cmn_err(CE_WARN, "Unknown descriptor type %d" 559 " in BIOS Multiprocessor Spec table.", 560 *extp); 561 memlist_free_all(res); 562 return (0); 563 } 564 } 565 return (res_cnt); 566 } 567 568 static void 569 hrt_probe(void) 570 { 571 struct hrt_hdr *hrtp; 572 573 dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n"); 574 if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000, 575 0x10000, "$HRT")) == NULL) { 576 dprintf("NO PCI Hot-Plug Resource Table"); 577 return; 578 } 579 dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp); 580 if (hrtp->hrt_ver != 1) { 581 dprintf("PCI Hot-Plug Resource Table version no. <> 1\n"); 582 return; 583 } 584 hrt_entry_cnt = (uint_t)hrtp->hrt_entry_cnt; 585 dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt); 586 hrt_hpep = (struct php_entry *)(hrtp + 1); 587 } 588 589 static int 590 hrt_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res) 591 { 592 int res_cnt; 593 struct php_entry *hpep; 594 595 ASSERT3U(bus, <, PCI_MAX_BUS_NUM); 596 597 if (hrt_hpep == NULL || hrt_entry_cnt == 0) 598 return (0); 599 hpep = hrt_hpep; 600 res_cnt = 0; 601 for (uint_t i = 0; i < hrt_entry_cnt; i++, hpep++) { 602 if (hpep->php_pri_bus != bus) 603 continue; 604 if (type == PCI_PRD_R_IO) { 605 if (hpep->php_io_start == 0 || hpep->php_io_size == 0) 606 continue; 607 memlist_insert(res, (uint64_t)hpep->php_io_start, 608 (uint64_t)hpep->php_io_size); 609 res_cnt++; 610 } else if (type == PCI_PRD_R_MMIO) { 611 if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0) 612 continue; 613 memlist_insert(res, 614 ((uint64_t)hpep->php_mem_start) << 16, 615 ((uint64_t)hpep->php_mem_size) << 16); 616 res_cnt++; 617 } else if (type == PCI_PRD_R_PREFETCH) { 618 if (hpep->php_pfmem_start == 0 || 619 hpep->php_pfmem_size == 0) 620 continue; 621 memlist_insert(res, 622 ((uint64_t)hpep->php_pfmem_start) << 16, 623 ((uint64_t)hpep->php_pfmem_size) << 16); 624 res_cnt++; 625 } 626 } 627 return (res_cnt); 628 } 629 630 static uchar_t * 631 find_sig(uchar_t *cp, int len, char *sig) 632 { 633 long i; 634 635 /* Search for the "_MP_" or "$HRT" signature */ 636 for (i = 0; i < len; i += 16) { 637 if (cp[0] == sig[0] && cp[1] == sig[1] && 638 cp[2] == sig[2] && cp[3] == sig[3]) 639 return (cp); 640 cp += 16; 641 } 642 return (NULL); 643 } 644 645 static int 646 checksum(unsigned char *cp, int len) 647 { 648 int i; 649 unsigned int cksum; 650 651 for (i = cksum = 0; i < len; i++) 652 cksum += (unsigned int) *cp++; 653 654 return ((int)(cksum & 0xFF)); 655 } 656 657 uint32_t 658 pci_prd_max_bus(void) 659 { 660 return ((uint32_t)pci_bios_maxbus); 661 } 662 663 struct memlist * 664 pci_prd_find_resource(uint32_t bus, pci_prd_rsrc_t rsrc) 665 { 666 struct memlist *res = NULL; 667 668 if (bus > pci_bios_maxbus) 669 return (NULL); 670 671 if (tbl_init == 0) { 672 tbl_init = 1; 673 acpi_pci_probe(); 674 if (pci_prd_have_bios) { 675 hrt_probe(); 676 mps_probe(); 677 } 678 } 679 680 if (acpi_find_bus_res(bus, rsrc, &res) > 0) 681 return (res); 682 683 if (pci_prd_have_bios && hrt_find_bus_res(bus, rsrc, &res) > 0) 684 return (res); 685 686 if (pci_prd_have_bios) 687 (void) mps_find_bus_res(bus, rsrc, &res); 688 return (res); 689 } 690 691 typedef struct { 692 pci_prd_root_complex_f ppac_func; 693 void *ppac_arg; 694 } pci_prd_acpi_cb_t; 695 696 static ACPI_STATUS 697 pci_process_acpi_device(ACPI_HANDLE hdl, UINT32 level, void *ctx, void **rv) 698 { 699 ACPI_DEVICE_INFO *adi; 700 int busnum; 701 pci_prd_acpi_cb_t *cb = ctx; 702 703 /* 704 * Use AcpiGetObjectInfo() to find the device _HID 705 * If not a PCI root-bus, ignore this device and continue 706 * the walk 707 */ 708 if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &adi))) 709 return (AE_OK); 710 711 if (!(adi->Valid & ACPI_VALID_HID)) { 712 AcpiOsFree(adi); 713 return (AE_OK); 714 } 715 716 if (strncmp(adi->HardwareId.String, PCI_ROOT_HID_STRING, 717 sizeof (PCI_ROOT_HID_STRING)) && 718 strncmp(adi->HardwareId.String, PCI_EXPRESS_ROOT_HID_STRING, 719 sizeof (PCI_EXPRESS_ROOT_HID_STRING))) { 720 AcpiOsFree(adi); 721 return (AE_OK); 722 } 723 724 AcpiOsFree(adi); 725 726 /* 727 * acpica_get_busno() will check the presence of _BBN and 728 * fail if not present. It will then use the _CRS method to 729 * retrieve the actual bus number assigned, it will fall back 730 * to _BBN should the _CRS method fail. 731 */ 732 if (ACPI_SUCCESS(acpica_get_busno(hdl, &busnum))) { 733 /* 734 * Ignore invalid _BBN return values here (rather 735 * than panic) and emit a warning; something else 736 * may suffer failure as a result of the broken BIOS. 737 */ 738 if (busnum < 0) { 739 dcmn_err(CE_NOTE, 740 "pci_process_acpi_device: invalid _BBN 0x%x", 741 busnum); 742 return (AE_CTRL_DEPTH); 743 } 744 745 if (cb->ppac_func((uint32_t)busnum, cb->ppac_arg)) 746 return (AE_CTRL_DEPTH); 747 return (AE_CTRL_TERMINATE); 748 } 749 750 /* PCI and no _BBN, continue walk */ 751 return (AE_OK); 752 } 753 754 void 755 pci_prd_root_complex_iter(pci_prd_root_complex_f func, void *arg) 756 { 757 void *rv; 758 pci_prd_acpi_cb_t cb; 759 760 cb.ppac_func = func; 761 cb.ppac_arg = arg; 762 763 /* 764 * First scan ACPI devices for anything that might be here. After that, 765 * go through and check the old BIOS IRQ routing table for additional 766 * buses. Note, slot naming from the IRQ table comes later. 767 */ 768 (void) AcpiGetDevices(NULL, pci_process_acpi_device, &cb, &rv); 769 pci_bios_bus_iter(func, arg); 770 771 } 772 773 774 /* 775 * If there is actually a PCI IRQ routing table present, then we want to use 776 * this to go back and update the slot name. In particular, if we have no PCI 777 * IRQ routing table, then we use the existing slot names that were already set 778 * up for us in picex_slot_names_prop() from the capability register. Otherwise, 779 * we actually delete all slot-names properties from buses and instead use 780 * something from the IRQ routing table if it exists. 781 * 782 * Note, the property is always deleted regardless of whether or not it exists 783 * in the IRQ routing table. Finally, we have traditionally kept "pcie0" names 784 * as special as apparently that can't be represented in the IRQ routing table. 785 */ 786 void 787 pci_prd_slot_name(uint32_t bus, dev_info_t *dip) 788 { 789 char slotprop[256]; 790 int len; 791 char *slotcap_name; 792 793 if (pci_irq_nroutes == 0) 794 return; 795 796 if (dip != NULL) { 797 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pci_bus_res[bus].dip, 798 DDI_PROP_DONTPASS, "slot-names", &slotcap_name) != 799 DDI_SUCCESS || strcmp(slotcap_name, "pcie0") != 0) { 800 (void) ndi_prop_remove(DDI_DEV_T_NONE, 801 pci_bus_res[bus].dip, "slot-names"); 802 } 803 } 804 805 806 len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop)); 807 if (len > 0) { 808 if (dip != NULL) { 809 ASSERT((len % sizeof (int)) == 0); 810 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 811 pci_bus_res[bus].dip, "slot-names", 812 (int *)slotprop, len / sizeof (int)); 813 } else { 814 cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI " 815 "IRQ routing table; Not adding slot-names " 816 "property for incorrect bus %d", bus); 817 } 818 } 819 } 820 821 boolean_t 822 pci_prd_multi_root_ok(void) 823 { 824 return (acpi_resource_discovery > 0); 825 } 826 827 int 828 pci_prd_init(pci_prd_upcalls_t *upcalls) 829 { 830 if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, 831 "efi-systab")) { 832 pci_prd_have_bios = B_FALSE; 833 } 834 835 prd_upcalls = upcalls; 836 837 return (0); 838 } 839 840 void 841 pci_prd_fini(void) 842 { 843 int bus; 844 845 for (bus = 0; bus <= pci_bios_maxbus; bus++) { 846 memlist_free_all(&acpi_io_res[bus]); 847 memlist_free_all(&acpi_mem_res[bus]); 848 memlist_free_all(&acpi_pmem_res[bus]); 849 memlist_free_all(&acpi_bus_res[bus]); 850 } 851 } 852 853 static struct modlmisc pci_prd_modlmisc_i86pc = { 854 .misc_modops = &mod_miscops, 855 .misc_linkinfo = "i86pc PCI Resource Discovery" 856 }; 857 858 static struct modlinkage pci_prd_modlinkage_i86pc = { 859 .ml_rev = MODREV_1, 860 .ml_linkage = { &pci_prd_modlmisc_i86pc, NULL } 861 }; 862 863 int 864 _init(void) 865 { 866 return (mod_install(&pci_prd_modlinkage_i86pc)); 867 } 868 869 int 870 _info(struct modinfo *modinfop) 871 { 872 return (mod_info(&pci_prd_modlinkage_i86pc, modinfop)); 873 } 874 875 int 876 _fini(void) 877 { 878 return (mod_remove(&pci_prd_modlinkage_i86pc)); 879 } 880