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 if (sasmp->sasm_as_base_hi != 0 || 477 sasmp->sasm_as_len_hi != 0) { 478 printf("64 bits address space\n"); 479 extp += SYS_AS_MAPPING_SIZE; 480 break; 481 } 482 memlist_insert(res, 483 (uint64_t)sasmp->sasm_as_base, 484 sasmp->sasm_as_len); 485 res_cnt++; 486 } 487 extp += SYS_AS_MAPPING_SIZE; 488 break; 489 case BUS_HIERARCHY_DESC: 490 extp += BUS_HIERARCHY_DESC_SIZE; 491 break; 492 case COMP_BUS_AS_MODIFIER: 493 extp += COMP_BUS_AS_MODIFIER_SIZE; 494 break; 495 default: 496 cmn_err(CE_WARN, "Unknown descriptor type %d" 497 " in BIOS Multiprocessor Spec table.", 498 *extp); 499 while (*res) { 500 struct memlist *tmp = *res; 501 *res = tmp->ml_next; 502 memlist_free(tmp); 503 } 504 return (0); 505 } 506 } 507 return (res_cnt); 508 } 509 510 static void 511 hrt_probe() 512 { 513 struct hrt_hdr *hrtp; 514 515 dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n"); 516 if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000, 517 0x10000, "$HRT")) == NULL) { 518 dprintf("NO PCI Hot-Plug Resource Table"); 519 return; 520 } 521 dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp); 522 if (hrtp->hrt_ver != 1) { 523 dprintf("PCI Hot-Plug Resource Table version no. <> 1\n"); 524 return; 525 } 526 hrt_entry_cnt = (int)hrtp->hrt_entry_cnt; 527 dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt); 528 hrt_hpep = (struct php_entry *)(hrtp + 1); 529 } 530 531 static int 532 hrt_find_bus_res(int bus, int type, struct memlist **res) 533 { 534 int res_cnt, i; 535 struct php_entry *hpep; 536 537 if (hrt_hpep == NULL || hrt_entry_cnt == 0) 538 return (0); 539 hpep = hrt_hpep; 540 res_cnt = 0; 541 for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 542 if (hpep->php_pri_bus != bus) 543 continue; 544 if (type == IO_TYPE) { 545 if (hpep->php_io_start == 0 || hpep->php_io_size == 0) 546 continue; 547 memlist_insert(res, (uint64_t)hpep->php_io_start, 548 (uint64_t)hpep->php_io_size); 549 res_cnt++; 550 } else if (type == MEM_TYPE) { 551 if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0) 552 continue; 553 memlist_insert(res, 554 (uint64_t)(((int)hpep->php_mem_start) << 16), 555 (uint64_t)(((int)hpep->php_mem_size) << 16)); 556 res_cnt++; 557 } else if (type == PREFETCH_TYPE) { 558 if (hpep->php_pfmem_start == 0 || 559 hpep->php_pfmem_size == 0) 560 continue; 561 memlist_insert(res, 562 (uint64_t)(((int)hpep->php_pfmem_start) << 16), 563 (uint64_t)(((int)hpep->php_pfmem_size) << 16)); 564 res_cnt++; 565 } 566 } 567 return (res_cnt); 568 } 569 570 static uchar_t * 571 find_sig(uchar_t *cp, int len, char *sig) 572 { 573 long i; 574 575 /* Search for the "_MP_" or "$HRT" signature */ 576 for (i = 0; i < len; i += 16) { 577 if (cp[0] == sig[0] && cp[1] == sig[1] && 578 cp[2] == sig[2] && cp[3] == sig[3]) 579 return (cp); 580 cp += 16; 581 } 582 return (NULL); 583 } 584 585 static int 586 checksum(unsigned char *cp, int len) 587 { 588 int i; 589 unsigned int cksum; 590 591 for (i = cksum = 0; i < len; i++) 592 cksum += (unsigned int) *cp++; 593 594 return ((int)(cksum & 0xFF)); 595 } 596 597 #ifdef UNUSED_BUS_HIERARY_INFO 598 599 /* 600 * At this point, the bus hierarchy entries do not appear to 601 * provide anything we can't find out from PCI config space. 602 * The only interesting bit is the ISA bus number, which we 603 * don't care. 604 */ 605 int 606 mps_find_parent_bus(int bus) 607 { 608 struct sasm *sasmp; 609 uchar_t *extp; 610 611 if (mps_extp == NULL) 612 return (-1); 613 614 extp = mps_extp; 615 while (extp < mps_ext_endp) { 616 bhdp = (struct bhd *)extp; 617 switch (*extp) { 618 case SYS_AS_MAPPING: 619 extp += SYS_AS_MAPPING_SIZE; 620 break; 621 case BUS_HIERARCHY_DESC: 622 if (bhdp->bhd_bus_id == bus) 623 return (bhdp->bhd_parent); 624 extp += BUS_HIERARCHY_DESC_SIZE; 625 break; 626 case COMP_BUS_AS_MODIFIER: 627 extp += COMP_BUS_AS_MODIFIER_SIZE; 628 break; 629 default: 630 cmn_err(CE_WARN, "Unknown descriptor type %d" 631 " in BIOS Multiprocessor Spec table.", 632 *extp); 633 return (-1); 634 } 635 } 636 return (-1); 637 } 638 639 int 640 hrt_find_bus_range(int bus) 641 { 642 int i, max_bus, sub_bus; 643 struct php_entry *hpep; 644 645 if (hrt_hpep == NULL || hrt_entry_cnt == 0) { 646 return (-1); 647 } 648 hpep = hrt_hpep; 649 max_bus = -1; 650 for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 651 if (hpep->php_pri_bus != bus) 652 continue; 653 sub_bus = (int)hpep->php_subord_bus; 654 if (sub_bus > max_bus) 655 max_bus = sub_bus; 656 } 657 return (max_bus); 658 } 659 660 #endif /* UNUSED_BUS_HIERARY_INFO */ 661