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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2016 Joyent, Inc. 26 * 27 * pci_resource.c -- routines to retrieve available bus resources from 28 * the MP Spec. Table and Hotplug Resource Table 29 */ 30 31 #include <sys/types.h> 32 #include <sys/memlist.h> 33 #include <sys/pci_impl.h> 34 #include <sys/systm.h> 35 #include <sys/cmn_err.h> 36 #include <sys/acpi/acpi.h> 37 #include <sys/acpica.h> 38 #include "mps_table.h" 39 #include "pcihrt.h" 40 41 extern int pci_boot_debug; 42 extern int pci_bios_maxbus; 43 #define dprintf if (pci_boot_debug) printf 44 45 static int tbl_init = 0; 46 static uchar_t *mps_extp = NULL; 47 static uchar_t *mps_ext_endp = NULL; 48 static struct php_entry *hrt_hpep; 49 static int hrt_entry_cnt = 0; 50 static int acpi_cb_cnt = 0; 51 52 static void mps_probe(void); 53 static void acpi_pci_probe(void); 54 static int mps_find_bus_res(int, int, struct memlist **); 55 static void hrt_probe(void); 56 static int hrt_find_bus_res(int, int, struct memlist **); 57 static int acpi_find_bus_res(int, int, struct memlist **); 58 static uchar_t *find_sig(uchar_t *cp, int len, char *sig); 59 static int checksum(unsigned char *cp, int len); 60 static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context); 61 void bus_res_fini(void); 62 static void acpi_trim_bus_ranges(void); 63 64 struct memlist *acpi_io_res[256]; 65 struct memlist *acpi_mem_res[256]; 66 struct memlist *acpi_pmem_res[256]; 67 struct memlist *acpi_bus_res[256]; 68 69 /* 70 * -1 = attempt ACPI resource discovery 71 * 0 = don't attempt ACPI resource discovery 72 * 1 = ACPI resource discovery successful 73 */ 74 volatile int acpi_resource_discovery = -1; 75 76 struct memlist * 77 find_bus_res(int bus, int type) 78 { 79 struct memlist *res = NULL; 80 81 if (tbl_init == 0) { 82 tbl_init = 1; 83 acpi_pci_probe(); 84 hrt_probe(); 85 mps_probe(); 86 } 87 88 if (acpi_find_bus_res(bus, type, &res) > 0) 89 return (res); 90 91 if (hrt_find_bus_res(bus, type, &res) > 0) 92 return (res); 93 94 (void) mps_find_bus_res(bus, type, &res); 95 return (res); 96 } 97 98 99 static void 100 acpi_pci_probe(void) 101 { 102 ACPI_HANDLE ah; 103 dev_info_t *dip; 104 int bus; 105 106 if (acpi_resource_discovery == 0) 107 return; 108 109 for (bus = 0; bus <= pci_bios_maxbus; bus++) { 110 /* if no dip or no ACPI handle, no resources to discover */ 111 dip = pci_bus_res[bus].dip; 112 if ((dip == NULL) || 113 (ACPI_FAILURE(acpica_get_handle(dip, &ah)))) 114 continue; 115 116 (void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb, 117 (void *)(uintptr_t)bus); 118 } 119 120 if (acpi_cb_cnt > 0) { 121 acpi_resource_discovery = 1; 122 acpi_trim_bus_ranges(); 123 } 124 } 125 126 /* 127 * Trim overlapping bus ranges in acpi_bus_res[] 128 * Some BIOSes report root-bridges with bus ranges that 129 * overlap, for example:"0..255" and "8..255". Lower-numbered 130 * ranges are trimmed by upper-numbered ranges (so "0..255" would 131 * be trimmed to "0..7", in the example). 132 */ 133 static void 134 acpi_trim_bus_ranges() 135 { 136 struct memlist *ranges, *current; 137 int bus; 138 139 ranges = NULL; 140 141 /* 142 * Assumptions: 143 * - there exists at most 1 bus range entry for each bus number 144 * - there are no (broken) ranges that start at the same bus number 145 */ 146 for (bus = 0; bus < 256; bus++) { 147 struct memlist *prev, *orig, *new; 148 /* skip buses with no range entry */ 149 if ((orig = acpi_bus_res[bus]) == NULL) 150 continue; 151 152 /* 153 * create copy of existing range and overload 154 * 'prev' pointer to link existing to new copy 155 */ 156 new = memlist_alloc(); 157 new->ml_address = orig->ml_address; 158 new->ml_size = orig->ml_size; 159 new->ml_prev = orig; 160 161 /* sorted insertion of 'new' into ranges list */ 162 for (current = ranges, prev = NULL; current != NULL; 163 prev = current, current = current->ml_next) 164 if (new->ml_address < current->ml_address) 165 break; 166 167 if (prev == NULL) { 168 /* place at beginning of (possibly) empty list */ 169 new->ml_next = ranges; 170 ranges = new; 171 } else { 172 /* place in list (possibly at end) */ 173 new->ml_next = current; 174 prev->ml_next = new; 175 } 176 } 177 178 /* scan the list, perform trimming */ 179 current = ranges; 180 while (current != NULL) { 181 struct memlist *next = current->ml_next; 182 183 /* done when no range above current */ 184 if (next == NULL) 185 break; 186 187 /* 188 * trim size in original range element 189 * (current->ml_prev points to the original range) 190 */ 191 if ((current->ml_address + current->ml_size) > next->ml_address) 192 current->ml_prev->ml_size = 193 next->ml_address - current->ml_address; 194 195 current = next; 196 } 197 198 /* discard the list */ 199 memlist_free_all(&ranges); /* OK if ranges == NULL */ 200 } 201 202 static int 203 acpi_find_bus_res(int bus, int type, struct memlist **res) 204 { 205 206 switch (type) { 207 case IO_TYPE: 208 *res = acpi_io_res[bus]; 209 break; 210 case MEM_TYPE: 211 *res = acpi_mem_res[bus]; 212 break; 213 case PREFETCH_TYPE: 214 *res = acpi_pmem_res[bus]; 215 break; 216 case BUSRANGE_TYPE: 217 *res = acpi_bus_res[bus]; 218 break; 219 default: 220 *res = NULL; 221 break; 222 } 223 224 /* memlist_count() treats NULL head as zero-length */ 225 return (memlist_count(*res)); 226 } 227 228 void 229 bus_res_fini(void) 230 { 231 int bus; 232 233 for (bus = 0; bus <= pci_bios_maxbus; bus++) { 234 memlist_free_all(&acpi_io_res[bus]); 235 memlist_free_all(&acpi_mem_res[bus]); 236 memlist_free_all(&acpi_pmem_res[bus]); 237 memlist_free_all(&acpi_bus_res[bus]); 238 } 239 } 240 241 242 struct memlist ** 243 rlistpp(UINT8 t, UINT8 flags, int bus) 244 { 245 switch (t) { 246 247 case ACPI_MEMORY_RANGE: 248 /* is this really the best we've got? */ 249 if (((flags >> 1) & 0x3) == ACPI_PREFETCHABLE_MEMORY) 250 return (&acpi_pmem_res[bus]); 251 else 252 return (&acpi_mem_res[bus]); 253 254 case ACPI_IO_RANGE: return &acpi_io_res[bus]; 255 case ACPI_BUS_NUMBER_RANGE: return &acpi_bus_res[bus]; 256 } 257 return ((struct memlist **)NULL); 258 } 259 260 261 ACPI_STATUS 262 acpi_wr_cb(ACPI_RESOURCE *rp, void *context) 263 { 264 int bus = (intptr_t)context; 265 266 /* ignore consumed resources */ 267 if (rp->Data.Address.ProducerConsumer == 1) 268 return (AE_OK); 269 270 switch (rp->Type) { 271 case ACPI_RESOURCE_TYPE_IRQ: 272 /* never expect to see a PCI bus produce an Interrupt */ 273 dprintf("%s\n", "IRQ"); 274 break; 275 276 case ACPI_RESOURCE_TYPE_DMA: 277 /* never expect to see a PCI bus produce DMA */ 278 dprintf("%s\n", "DMA"); 279 break; 280 281 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 282 dprintf("%s\n", "START_DEPENDENT"); 283 break; 284 285 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 286 dprintf("%s\n", "END_DEPENDENT"); 287 break; 288 289 case ACPI_RESOURCE_TYPE_IO: 290 if (rp->Data.Io.AddressLength == 0) 291 break; 292 acpi_cb_cnt++; 293 memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum, 294 rp->Data.Io.AddressLength); 295 break; 296 297 case ACPI_RESOURCE_TYPE_FIXED_IO: 298 /* only expect to see this as a consumer */ 299 dprintf("%s\n", "FIXED_IO"); 300 break; 301 302 case ACPI_RESOURCE_TYPE_VENDOR: 303 dprintf("%s\n", "VENDOR"); 304 break; 305 306 case ACPI_RESOURCE_TYPE_END_TAG: 307 dprintf("%s\n", "END_TAG"); 308 break; 309 310 case ACPI_RESOURCE_TYPE_MEMORY24: 311 /* only expect to see this as a consumer */ 312 dprintf("%s\n", "MEMORY24"); 313 break; 314 315 case ACPI_RESOURCE_TYPE_MEMORY32: 316 /* only expect to see this as a consumer */ 317 dprintf("%s\n", "MEMORY32"); 318 break; 319 320 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 321 /* only expect to see this as a consumer */ 322 dprintf("%s\n", "FIXED_MEMORY32"); 323 break; 324 325 case ACPI_RESOURCE_TYPE_ADDRESS16: 326 if (rp->Data.Address16.Address.AddressLength == 0) 327 break; 328 acpi_cb_cnt++; 329 memlist_insert(rlistpp(rp->Data.Address16.ResourceType, 330 rp->Data.Address16.Info.TypeSpecific, bus), 331 rp->Data.Address16.Address.Minimum, 332 rp->Data.Address16.Address.AddressLength); 333 break; 334 335 case ACPI_RESOURCE_TYPE_ADDRESS32: 336 if (rp->Data.Address32.Address.AddressLength == 0) 337 break; 338 acpi_cb_cnt++; 339 memlist_insert(rlistpp(rp->Data.Address32.ResourceType, 340 rp->Data.Address32.Info.TypeSpecific, bus), 341 rp->Data.Address32.Address.Minimum, 342 rp->Data.Address32.Address.AddressLength); 343 break; 344 345 case ACPI_RESOURCE_TYPE_ADDRESS64: 346 /* 347 * We comment out this block because we currently cannot deal with 348 * PCI 64-bit addresses. Will revisit this when we add PCI 64-bit MMIO 349 * support. 350 */ 351 #if 0 352 if (rp->Data.Address64.AddressLength == 0) 353 break; 354 acpi_cb_cnt++; 355 memlist_insert(rlistpp(rp->Data.Address64.ResourceType, 356 rp->Data.Address64.Info.TypeSpecific, bus), 357 rp->Data.Address64.Minimum, 358 rp->Data.Address64.AddressLength); 359 #endif 360 break; 361 362 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 363 #if 0 /* Will revisit this when we add PCI 64-bit MMIO support */ 364 if (rp->Data.ExtAddress64.AddressLength == 0) 365 break; 366 acpi_cb_cnt++; 367 memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType, 368 rp->Data.ExtAddress64.Info.TypeSpecific, bus), 369 rp->Data.ExtAddress64.Minimum, 370 rp->Data.ExtAddress64.AddressLength); 371 #endif 372 break; 373 374 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 375 /* never expect to see a PCI bus produce an Interrupt */ 376 dprintf("%s\n", "EXTENDED_IRQ"); 377 break; 378 379 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 380 /* never expect to see a PCI bus produce an GAS */ 381 dprintf("%s\n", "GENERIC_REGISTER"); 382 break; 383 } 384 385 return (AE_OK); 386 } 387 388 static void 389 mps_probe() 390 { 391 uchar_t *extp; 392 struct mps_fps_hdr *fpp = NULL; 393 struct mps_ct_hdr *ctp; 394 uintptr_t ebda_start, base_end; 395 ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg; 396 397 base_size = *((ushort_t *)(0x413)); 398 ebda_seg = *((ushort_t *)(0x40e)); 399 ebda_start = ((uint32_t)ebda_seg) << 4; 400 if (ebda_seg != 0) { 401 fpp = (struct mps_fps_hdr *)find_sig( 402 (uchar_t *)ebda_start, 1024, "_MP_"); 403 } 404 if (fpp == NULL) { 405 base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0; 406 if (base_end_seg != ebda_seg) { 407 base_end = ((uintptr_t)base_end_seg) << 4; 408 fpp = (struct mps_fps_hdr *)find_sig( 409 (uchar_t *)base_end, 1024, "_MP_"); 410 } 411 } 412 if (fpp == NULL) { 413 fpp = (struct mps_fps_hdr *)find_sig( 414 (uchar_t *)0xF0000, 0x10000, "_MP_"); 415 } 416 417 if (fpp == NULL) { 418 dprintf("MP Spec table doesn't exist"); 419 return; 420 } else { 421 dprintf("Found MP Floating Pointer Structure at %p\n", 422 (void *)fpp); 423 } 424 425 if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) { 426 dprintf("MP Floating Pointer Structure checksum error"); 427 return; 428 } 429 430 ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr; 431 if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */ 432 dprintf("MP Configuration Table signature is wrong"); 433 return; 434 } 435 436 base_len = ctp->ct_len; 437 if (checksum((uchar_t *)ctp, base_len) != 0) { 438 dprintf("MP Configuration Table checksum error"); 439 return; 440 } 441 if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */ 442 dprintf("MP Spec 1.1 found - extended table doesn't exist"); 443 return; 444 } 445 if ((ext_len = ctp->ct_ext_tbl_len) == 0) { 446 dprintf("MP Spec 1.4 found - extended table doesn't exist"); 447 return; 448 } 449 extp = (uchar_t *)ctp + base_len; 450 if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) { 451 dprintf("MP Extended Table checksum error"); 452 return; 453 } 454 mps_extp = extp; 455 mps_ext_endp = mps_extp + ext_len; 456 } 457 458 459 static int 460 mps_find_bus_res(int bus, int type, struct memlist **res) 461 { 462 struct sasm *sasmp; 463 uchar_t *extp; 464 int res_cnt; 465 466 if (mps_extp == NULL) 467 return (0); 468 extp = mps_extp; 469 res_cnt = 0; 470 while (extp < mps_ext_endp) { 471 switch (*extp) { 472 case SYS_AS_MAPPING: 473 sasmp = (struct sasm *)extp; 474 if (((int)sasmp->sasm_as_type) == type && 475 ((int)sasmp->sasm_bus_id) == bus) { 476 uint64_t base, len; 477 478 base = (uint64_t)sasmp->sasm_as_base | 479 (uint64_t)sasmp->sasm_as_base_hi << 32; 480 len = (uint64_t)sasmp->sasm_as_len | 481 (uint64_t)sasmp->sasm_as_len_hi << 32; 482 memlist_insert(res, base, len); 483 res_cnt++; 484 } 485 extp += SYS_AS_MAPPING_SIZE; 486 break; 487 case BUS_HIERARCHY_DESC: 488 extp += BUS_HIERARCHY_DESC_SIZE; 489 break; 490 case COMP_BUS_AS_MODIFIER: 491 extp += COMP_BUS_AS_MODIFIER_SIZE; 492 break; 493 default: 494 cmn_err(CE_WARN, "Unknown descriptor type %d" 495 " in BIOS Multiprocessor Spec table.", 496 *extp); 497 while (*res) { 498 struct memlist *tmp = *res; 499 *res = tmp->ml_next; 500 memlist_free(tmp); 501 } 502 return (0); 503 } 504 } 505 return (res_cnt); 506 } 507 508 static void 509 hrt_probe() 510 { 511 struct hrt_hdr *hrtp; 512 513 dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n"); 514 if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000, 515 0x10000, "$HRT")) == NULL) { 516 dprintf("NO PCI Hot-Plug Resource Table"); 517 return; 518 } 519 dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp); 520 if (hrtp->hrt_ver != 1) { 521 dprintf("PCI Hot-Plug Resource Table version no. <> 1\n"); 522 return; 523 } 524 hrt_entry_cnt = (int)hrtp->hrt_entry_cnt; 525 dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt); 526 hrt_hpep = (struct php_entry *)(hrtp + 1); 527 } 528 529 static int 530 hrt_find_bus_res(int bus, int type, struct memlist **res) 531 { 532 int res_cnt, i; 533 struct php_entry *hpep; 534 535 if (hrt_hpep == NULL || hrt_entry_cnt == 0) 536 return (0); 537 hpep = hrt_hpep; 538 res_cnt = 0; 539 for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 540 if (hpep->php_pri_bus != bus) 541 continue; 542 if (type == IO_TYPE) { 543 if (hpep->php_io_start == 0 || hpep->php_io_size == 0) 544 continue; 545 memlist_insert(res, (uint64_t)hpep->php_io_start, 546 (uint64_t)hpep->php_io_size); 547 res_cnt++; 548 } else if (type == MEM_TYPE) { 549 if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0) 550 continue; 551 memlist_insert(res, 552 (uint64_t)(((int)hpep->php_mem_start) << 16), 553 (uint64_t)(((int)hpep->php_mem_size) << 16)); 554 res_cnt++; 555 } else if (type == PREFETCH_TYPE) { 556 if (hpep->php_pfmem_start == 0 || 557 hpep->php_pfmem_size == 0) 558 continue; 559 memlist_insert(res, 560 (uint64_t)(((int)hpep->php_pfmem_start) << 16), 561 (uint64_t)(((int)hpep->php_pfmem_size) << 16)); 562 res_cnt++; 563 } 564 } 565 return (res_cnt); 566 } 567 568 static uchar_t * 569 find_sig(uchar_t *cp, int len, char *sig) 570 { 571 long i; 572 573 /* Search for the "_MP_" or "$HRT" signature */ 574 for (i = 0; i < len; i += 16) { 575 if (cp[0] == sig[0] && cp[1] == sig[1] && 576 cp[2] == sig[2] && cp[3] == sig[3]) 577 return (cp); 578 cp += 16; 579 } 580 return (NULL); 581 } 582 583 static int 584 checksum(unsigned char *cp, int len) 585 { 586 int i; 587 unsigned int cksum; 588 589 for (i = cksum = 0; i < len; i++) 590 cksum += (unsigned int) *cp++; 591 592 return ((int)(cksum & 0xFF)); 593 } 594 595 #ifdef UNUSED_BUS_HIERARY_INFO 596 597 /* 598 * At this point, the bus hierarchy entries do not appear to 599 * provide anything we can't find out from PCI config space. 600 * The only interesting bit is the ISA bus number, which we 601 * don't care. 602 */ 603 int 604 mps_find_parent_bus(int bus) 605 { 606 struct sasm *sasmp; 607 uchar_t *extp; 608 609 if (mps_extp == NULL) 610 return (-1); 611 612 extp = mps_extp; 613 while (extp < mps_ext_endp) { 614 bhdp = (struct bhd *)extp; 615 switch (*extp) { 616 case SYS_AS_MAPPING: 617 extp += SYS_AS_MAPPING_SIZE; 618 break; 619 case BUS_HIERARCHY_DESC: 620 if (bhdp->bhd_bus_id == bus) 621 return (bhdp->bhd_parent); 622 extp += BUS_HIERARCHY_DESC_SIZE; 623 break; 624 case COMP_BUS_AS_MODIFIER: 625 extp += COMP_BUS_AS_MODIFIER_SIZE; 626 break; 627 default: 628 cmn_err(CE_WARN, "Unknown descriptor type %d" 629 " in BIOS Multiprocessor Spec table.", 630 *extp); 631 return (-1); 632 } 633 } 634 return (-1); 635 } 636 637 int 638 hrt_find_bus_range(int bus) 639 { 640 int i, max_bus, sub_bus; 641 struct php_entry *hpep; 642 643 if (hrt_hpep == NULL || hrt_entry_cnt == 0) { 644 return (-1); 645 } 646 hpep = hrt_hpep; 647 max_bus = -1; 648 for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 649 if (hpep->php_pri_bus != bus) 650 continue; 651 sub_bus = (int)hpep->php_subord_bus; 652 if (sub_bus > max_bus) 653 max_bus = sub_bus; 654 } 655 return (max_bus); 656 } 657 658 #endif /* UNUSED_BUS_HIERARY_INFO */ 659