1 /* 2 * Copyright 2003-2008, Marcus Overhagen. All rights reserved. 3 * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include <string.h> 10 #include <KernelExport.h> 11 #define __HAIKU_PCI_BUS_MANAGER_TESTING 1 12 #include <PCI.h> 13 14 #include "util/kernel_cpp.h" 15 #include "pci_fixup.h" 16 #include "pci_info.h" 17 #include "pci_private.h" 18 #include "pci.h" 19 20 #define TRACE_CAP(x...) dprintf(x) 21 #define FLOW(x...) 22 //#define FLOW(x...) dprintf(x) 23 24 25 PCI *gPCI; 26 27 28 // #pragma mark bus manager exports 29 30 31 status_t 32 pci_controller_add(pci_controller *controller, void *cookie) 33 { 34 return gPCI->AddController(controller, cookie); 35 } 36 37 38 long 39 pci_get_nth_pci_info(long index, pci_info *outInfo) 40 { 41 return gPCI->GetNthInfo(index, outInfo); 42 } 43 44 45 uint32 46 pci_read_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset, 47 uint8 size) 48 { 49 uint8 bus; 50 uint8 domain; 51 uint32 value; 52 53 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 54 return 0xffffffff; 55 56 if (gPCI->ReadConfig(domain, bus, device, function, offset, size, 57 &value) != B_OK) 58 return 0xffffffff; 59 60 return value; 61 } 62 63 64 void 65 pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset, 66 uint8 size, uint32 value) 67 { 68 uint8 bus; 69 uint8 domain; 70 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 71 return; 72 73 gPCI->WriteConfig(domain, bus, device, function, offset, size, value); 74 } 75 76 77 status_t 78 pci_find_capability(uint8 virtualBus, uint8 device, uint8 function, 79 uint8 capID, uint8 *offset) 80 { 81 uint8 bus; 82 uint8 domain; 83 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 84 return B_ERROR; 85 86 return gPCI->FindCapability(domain, bus, device, function, capID, offset); 87 } 88 89 90 status_t 91 pci_find_extended_capability(uint8 virtualBus, uint8 device, uint8 function, 92 uint16 capID, uint16 *offset) 93 { 94 uint8 bus; 95 uint8 domain; 96 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 97 return B_ERROR; 98 99 return gPCI->FindExtendedCapability(domain, bus, device, function, capID, 100 offset); 101 } 102 103 104 status_t 105 pci_reserve_device(uchar virtualBus, uchar device, uchar function, 106 const char *driverName, void *nodeCookie) 107 { 108 status_t status; 109 uint8 bus; 110 uint8 domain; 111 TRACE(("pci_reserve_device(%d, %d, %d, %s)\n", virtualBus, device, function, 112 driverName)); 113 114 /* 115 * we add 2 nodes to the PCI devices, one with constant attributes, 116 * so adding for another driver fails, and a subnode with the 117 * driver-provided informations. 118 */ 119 120 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 121 return B_ERROR; 122 123 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus, 124 // domain, bus, device, function, driverName, nodeCookie)); 125 126 device_attr matchPCIRoot[] = { 127 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}}, 128 {NULL} 129 }; 130 device_attr matchThis[] = { 131 // info about device 132 {B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}}, 133 134 // location on PCI bus 135 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {ui8: domain}}, 136 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}}, 137 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}}, 138 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}}, 139 {NULL} 140 }; 141 device_attr legacyAttrs[] = { 142 // info about device 143 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, 144 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}}, 145 {NULL} 146 }; 147 device_attr drvAttrs[] = { 148 // info about device 149 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, 150 {"legacy_driver", B_STRING_TYPE, {string: driverName}}, 151 {"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}}, 152 {NULL} 153 }; 154 device_node *root, *pci, *node, *legacy; 155 156 status = B_DEVICE_NOT_FOUND; 157 root = gDeviceManager->get_root_node(); 158 if (!root) 159 return status; 160 161 pci = NULL; 162 if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK) 163 goto err0; 164 165 node = NULL; 166 if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK) 167 goto err1; 168 169 // common API for all legacy modules ? 170 //status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME); 171 172 status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME, 173 legacyAttrs, NULL, &legacy); 174 if (status < B_OK) 175 goto err2; 176 177 status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME, 178 drvAttrs, NULL, NULL); 179 if (status < B_OK) 180 goto err3; 181 182 gDeviceManager->put_node(node); 183 gDeviceManager->put_node(pci); 184 gDeviceManager->put_node(root); 185 186 return B_OK; 187 188 err3: 189 gDeviceManager->unregister_node(legacy); 190 err2: 191 gDeviceManager->put_node(node); 192 err1: 193 gDeviceManager->put_node(pci); 194 err0: 195 gDeviceManager->put_node(root); 196 TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName, 197 strerror(status))); 198 return status; 199 } 200 201 202 status_t 203 pci_unreserve_device(uchar virtualBus, uchar device, uchar function, 204 const char *driverName, void *nodeCookie) 205 { 206 status_t status; 207 uint8 bus; 208 uint8 domain; 209 TRACE(("pci_unreserve_device(%d, %d, %d, %s)\n", virtualBus, device, 210 function, driverName)); 211 212 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 213 return B_ERROR; 214 215 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus, 216 // domain, bus, device, function, driverName, nodeCookie)); 217 218 device_attr matchPCIRoot[] = { 219 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}}, 220 {NULL} 221 }; 222 device_attr matchThis[] = { 223 // info about device 224 {B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}}, 225 226 // location on PCI bus 227 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {ui8: domain}}, 228 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}}, 229 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}}, 230 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}}, 231 {NULL} 232 }; 233 device_attr legacyAttrs[] = { 234 // info about device 235 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, 236 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}}, 237 {NULL} 238 }; 239 device_attr drvAttrs[] = { 240 // info about device 241 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, 242 {"legacy_driver", B_STRING_TYPE, {string: driverName}}, 243 {"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}}, 244 {NULL} 245 }; 246 device_node *root, *pci, *node, *legacy, *drv; 247 248 status = B_DEVICE_NOT_FOUND; 249 root = gDeviceManager->get_root_node(); 250 if (!root) 251 return status; 252 253 pci = NULL; 254 if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK) 255 goto err0; 256 257 node = NULL; 258 if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK) 259 goto err1; 260 261 // common API for all legacy modules ? 262 //status = legacy_driver_unregister(node, driverName, nodeCookie); 263 264 legacy = NULL; 265 if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK) 266 goto err2; 267 268 drv = NULL; 269 if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK) 270 goto err3; 271 272 gDeviceManager->put_node(drv); 273 status = gDeviceManager->unregister_node(drv); 274 //dprintf("unreg:drv:%s\n", strerror(status)); 275 276 gDeviceManager->put_node(legacy); 277 status = gDeviceManager->unregister_node(legacy); 278 //dprintf("unreg:legacy:%s\n", strerror(status)); 279 // we'll get EBUSY here anyway... 280 281 gDeviceManager->put_node(node); 282 gDeviceManager->put_node(pci); 283 gDeviceManager->put_node(root); 284 return B_OK; 285 286 err3: 287 gDeviceManager->put_node(legacy); 288 err2: 289 gDeviceManager->put_node(node); 290 err1: 291 gDeviceManager->put_node(pci); 292 err0: 293 gDeviceManager->put_node(root); 294 TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName, 295 strerror(status))); 296 return status; 297 } 298 299 300 status_t 301 pci_update_interrupt_line(uchar virtualBus, uchar device, uchar function, 302 uchar newInterruptLineValue) 303 { 304 uint8 bus; 305 uint8 domain; 306 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 307 return B_ERROR; 308 309 return gPCI->UpdateInterruptLine(domain, bus, device, function, 310 newInterruptLineValue); 311 } 312 313 314 // used by pci_info.cpp print_info_basic() 315 void 316 __pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus) 317 { 318 if (gPCI->ResolveVirtualBus(virtualBus, domain, bus) < B_OK) 319 panic("ResolveVirtualBus failed"); 320 } 321 322 323 // #pragma mark kernel debugger commands 324 325 326 static int 327 display_io(int argc, char **argv) 328 { 329 int32 displayWidth; 330 int32 itemSize; 331 int32 num = 1; 332 int address; 333 int i = 1, j; 334 335 switch (argc) { 336 case 3: 337 num = atoi(argv[2]); 338 case 2: 339 address = strtoul(argv[1], NULL, 0); 340 break; 341 default: 342 kprintf("usage: %s <address> [num]\n", argv[0]); 343 return 0; 344 } 345 346 // build the format string 347 if (strcmp(argv[0], "inb") == 0 || strcmp(argv[0], "in8") == 0) { 348 itemSize = 1; 349 displayWidth = 16; 350 } else if (strcmp(argv[0], "ins") == 0 || strcmp(argv[0], "in16") == 0) { 351 itemSize = 2; 352 displayWidth = 8; 353 } else if (strcmp(argv[0], "inw") == 0 || strcmp(argv[0], "in32") == 0) { 354 itemSize = 4; 355 displayWidth = 4; 356 } else { 357 kprintf("display_io called in an invalid way!\n"); 358 return 0; 359 } 360 361 for (i = 0; i < num; i++) { 362 if ((i % displayWidth) == 0) { 363 int32 displayed = min_c(displayWidth, (num-i)) * itemSize; 364 if (i != 0) 365 kprintf("\n"); 366 367 kprintf("[0x%" B_PRIx32 "] ", address + i * itemSize); 368 369 if (num > displayWidth) { 370 // make sure the spacing in the last line is correct 371 for (j = displayed; j < displayWidth * itemSize; j++) 372 kprintf(" "); 373 } 374 kprintf(" "); 375 } 376 377 switch (itemSize) { 378 case 1: 379 kprintf(" %02" B_PRIx8, pci_read_io_8(address + i * itemSize)); 380 break; 381 case 2: 382 kprintf(" %04" B_PRIx16, pci_read_io_16(address + i * itemSize)); 383 break; 384 case 4: 385 kprintf(" %08" B_PRIx32, pci_read_io_32(address + i * itemSize)); 386 break; 387 } 388 } 389 390 kprintf("\n"); 391 return 0; 392 } 393 394 395 static int 396 write_io(int argc, char **argv) 397 { 398 int32 itemSize; 399 uint32 value; 400 int address; 401 int i = 1; 402 403 if (argc < 3) { 404 kprintf("usage: %s <address> <value> [value [...]]\n", argv[0]); 405 return 0; 406 } 407 408 address = strtoul(argv[1], NULL, 0); 409 410 if (strcmp(argv[0], "outb") == 0 || strcmp(argv[0], "out8") == 0) { 411 itemSize = 1; 412 } else if (strcmp(argv[0], "outs") == 0 || strcmp(argv[0], "out16") == 0) { 413 itemSize = 2; 414 } else if (strcmp(argv[0], "outw") == 0 || strcmp(argv[0], "out32") == 0) { 415 itemSize = 4; 416 } else { 417 kprintf("write_io called in an invalid way!\n"); 418 return 0; 419 } 420 421 // skip cmd name and address 422 argv += 2; 423 argc -= 2; 424 425 for (i = 0; i < argc; i++) { 426 value = strtoul(argv[i], NULL, 0); 427 switch (itemSize) { 428 case 1: 429 pci_write_io_8(address + i * itemSize, value); 430 break; 431 case 2: 432 pci_write_io_16(address + i * itemSize, value); 433 break; 434 case 4: 435 pci_write_io_32(address + i * itemSize, value); 436 break; 437 } 438 } 439 440 return 0; 441 } 442 443 444 static int 445 pcistatus(int argc, char **argv) 446 { 447 gPCI->ClearDeviceStatus(NULL, true); 448 return 0; 449 } 450 451 452 static int 453 pcirefresh(int argc, char **argv) 454 { 455 gPCI->RefreshDeviceInfo(); 456 pci_print_info(); 457 return 0; 458 } 459 460 461 // #pragma mark bus manager init/uninit 462 463 464 status_t 465 pci_init(void) 466 { 467 gPCI = new PCI; 468 469 if (pci_io_init() != B_OK) { 470 TRACE(("PCI: pci_io_init failed\n")); 471 return B_ERROR; 472 } 473 474 add_debugger_command("inw", &display_io, "dump io words (32-bit)"); 475 add_debugger_command("in32", &display_io, "dump io words (32-bit)"); 476 add_debugger_command("ins", &display_io, "dump io shorts (16-bit)"); 477 add_debugger_command("in16", &display_io, "dump io shorts (16-bit)"); 478 add_debugger_command("inb", &display_io, "dump io bytes (8-bit)"); 479 add_debugger_command("in8", &display_io, "dump io bytes (8-bit)"); 480 481 add_debugger_command("outw", &write_io, "write io words (32-bit)"); 482 add_debugger_command("out32", &write_io, "write io words (32-bit)"); 483 add_debugger_command("outs", &write_io, "write io shorts (16-bit)"); 484 add_debugger_command("out16", &write_io, "write io shorts (16-bit)"); 485 add_debugger_command("outb", &write_io, "write io bytes (8-bit)"); 486 add_debugger_command("out8", &write_io, "write io bytes (8-bit)"); 487 488 if (pci_controller_init() != B_OK) { 489 TRACE(("PCI: pci_controller_init failed\n")); 490 panic("PCI: pci_controller_init failed\n"); 491 return B_ERROR; 492 } 493 494 gPCI->InitDomainData(); 495 gPCI->InitBus(); 496 497 add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers"); 498 add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info"); 499 500 return B_OK; 501 } 502 503 504 void 505 pci_uninit(void) 506 { 507 remove_debugger_command("outw", &write_io); 508 remove_debugger_command("out32", &write_io); 509 remove_debugger_command("outs", &write_io); 510 remove_debugger_command("out16", &write_io); 511 remove_debugger_command("outb", &write_io); 512 remove_debugger_command("out8", &write_io); 513 514 remove_debugger_command("inw", &display_io); 515 remove_debugger_command("in32", &display_io); 516 remove_debugger_command("ins", &display_io); 517 remove_debugger_command("in16", &display_io); 518 remove_debugger_command("inb", &display_io); 519 remove_debugger_command("in8", &display_io); 520 521 remove_debugger_command("pcistatus", &pcistatus); 522 remove_debugger_command("pcirefresh", &pcirefresh); 523 524 delete gPCI; 525 } 526 527 528 // #pragma mark PCI class 529 530 531 PCI::PCI() 532 : 533 fRootBus(0), 534 fDomainCount(0), 535 fBusEnumeration(false), 536 fVirtualBusMap(), 537 fNextVirtualBus(0) 538 { 539 #if defined(__POWERPC__) || defined(__M68K__) 540 fBusEnumeration = true; 541 #endif 542 } 543 544 545 void 546 PCI::InitBus() 547 { 548 PCIBus **nextBus = &fRootBus; 549 for (uint8 i = 0; i < fDomainCount; i++) { 550 PCIBus *bus = new PCIBus; 551 bus->next = NULL; 552 bus->parent = NULL; 553 bus->child = NULL; 554 bus->domain = i; 555 bus->bus = 0; 556 *nextBus = bus; 557 nextBus = &bus->next; 558 } 559 560 if (fBusEnumeration) { 561 for (uint8 i = 0; i < fDomainCount; i++) { 562 _EnumerateBus(i, 0); 563 } 564 } 565 566 if (1) { 567 for (uint8 i = 0; i < fDomainCount; i++) { 568 _FixupDevices(i, 0); 569 } 570 } 571 572 if (fRootBus) { 573 _DiscoverBus(fRootBus); 574 _ConfigureBridges(fRootBus); 575 ClearDeviceStatus(fRootBus, false); 576 _RefreshDeviceInfo(fRootBus); 577 } 578 } 579 580 581 PCI::~PCI() 582 { 583 } 584 585 586 status_t 587 PCI::_CreateVirtualBus(uint8 domain, uint8 bus, uint8 *virtualBus) 588 { 589 #if defined(__INTEL__) || defined(__x86_64__) 590 591 // IA32 doesn't use domains 592 if (domain) 593 panic("PCI::CreateVirtualBus domain != 0"); 594 *virtualBus = bus; 595 return B_OK; 596 597 #else 598 599 if (fNextVirtualBus > 0xff) 600 panic("PCI::CreateVirtualBus: virtual bus number space exhausted"); 601 602 uint16 value = domain << 8 | bus; 603 604 for (VirtualBusMap::Iterator it = fVirtualBusMap.Begin(); 605 it != fVirtualBusMap.End(); ++it) { 606 if (it->Value() == value) { 607 *virtualBus = it->Key(); 608 FLOW("PCI::CreateVirtualBus: domain %d, bus %d already in map => " 609 "virtualBus %d\n", domain, bus, *virtualBus); 610 return B_OK; 611 } 612 } 613 614 *virtualBus = fNextVirtualBus++; 615 616 FLOW("PCI::CreateVirtualBus: domain %d, bus %d => virtualBus %d\n", domain, 617 bus, *virtualBus); 618 619 return fVirtualBusMap.Insert(*virtualBus, value); 620 621 #endif 622 } 623 624 625 status_t 626 PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus) 627 { 628 #if defined(__INTEL__) || defined(__x86_64__) 629 630 // IA32 doesn't use domains 631 *bus = virtualBus; 632 *domain = 0; 633 return B_OK; 634 635 #else 636 637 if (virtualBus >= fNextVirtualBus) 638 return B_ERROR; 639 640 uint16 value = fVirtualBusMap.Get(virtualBus); 641 *domain = value >> 8; 642 *bus = value & 0xff; 643 return B_OK; 644 645 #endif 646 } 647 648 649 status_t 650 PCI::AddController(pci_controller *controller, void *controller_cookie) 651 { 652 if (fDomainCount == MAX_PCI_DOMAINS) 653 return B_ERROR; 654 655 fDomainData[fDomainCount].controller = controller; 656 fDomainData[fDomainCount].controller_cookie = controller_cookie; 657 658 // initialized later to avoid call back into controller at this point 659 fDomainData[fDomainCount].max_bus_devices = -1; 660 661 fDomainCount++; 662 return B_OK; 663 } 664 665 void 666 PCI::InitDomainData() 667 { 668 for (uint8 i = 0; i < fDomainCount; i++) { 669 int32 count; 670 status_t status; 671 672 status = (*fDomainData[i].controller->get_max_bus_devices)( 673 fDomainData[i].controller_cookie, &count); 674 fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0; 675 } 676 } 677 678 679 domain_data * 680 PCI::_GetDomainData(uint8 domain) 681 { 682 if (domain >= fDomainCount) 683 return NULL; 684 685 return &fDomainData[domain]; 686 } 687 688 689 inline int 690 PCI::_NumFunctions(uint8 domain, uint8 bus, uint8 device) 691 { 692 uint8 type = ReadConfig(domain, bus, device, 693 0, PCI_header_type, 1); 694 return (type & PCI_multifunction) != 0 ? 8 : 1; 695 } 696 697 698 status_t 699 PCI::GetNthInfo(long index, pci_info *outInfo) 700 { 701 long currentIndex = 0; 702 if (!fRootBus) 703 return B_ERROR; 704 705 return _GetNthInfo(fRootBus, ¤tIndex, index, outInfo); 706 } 707 708 709 status_t 710 PCI::_GetNthInfo(PCIBus *bus, long *currentIndex, long wantIndex, 711 pci_info *outInfo) 712 { 713 // maps tree structure to linear indexed view 714 PCIDev *dev = bus->child; 715 while (dev) { 716 if (*currentIndex == wantIndex) { 717 *outInfo = dev->info; 718 return B_OK; 719 } 720 *currentIndex += 1; 721 if (dev->child && B_OK == _GetNthInfo(dev->child, currentIndex, 722 wantIndex, outInfo)) 723 return B_OK; 724 dev = dev->next; 725 } 726 727 if (bus->next) 728 return _GetNthInfo(bus->next, currentIndex, wantIndex, outInfo); 729 730 return B_ERROR; 731 } 732 733 734 void 735 PCI::_EnumerateBus(uint8 domain, uint8 bus, uint8 *subordinateBus) 736 { 737 TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus)); 738 739 int maxBusDevices = _GetDomainData(domain)->max_bus_devices; 740 741 // step 1: disable all bridges on this bus 742 for (int dev = 0; dev < maxBusDevices; dev++) { 743 uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2); 744 if (vendor_id == 0xffff) 745 continue; 746 747 int numFunctions = _NumFunctions(domain, bus, dev); 748 for (int function = 0; function < numFunctions; function++) { 749 uint16 device_id = ReadConfig(domain, bus, dev, function, 750 PCI_device_id, 2); 751 if (device_id == 0xffff) 752 continue; 753 754 uint8 baseClass = ReadConfig(domain, bus, dev, function, 755 PCI_class_base, 1); 756 uint8 subClass = ReadConfig(domain, bus, dev, function, 757 PCI_class_sub, 1); 758 if (baseClass != PCI_bridge || subClass != PCI_pci) 759 continue; 760 761 // skip incorrectly configured devices 762 uint8 headerType = ReadConfig(domain, bus, dev, function, 763 PCI_header_type, 1) & PCI_header_type_mask; 764 if (headerType != PCI_header_type_PCI_to_PCI_bridge) 765 continue; 766 767 TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n", 768 domain, bus, dev, function)); 769 TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus " 770 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 771 "%" B_PRIu32 "\n", 772 ReadConfig(domain, bus, dev, function, PCI_command, 2), 773 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 774 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 775 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 776 777 // disable decoding 778 uint16 pcicmd; 779 pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2); 780 pcicmd &= ~(PCI_command_io | PCI_command_memory 781 | PCI_command_master); 782 WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd); 783 784 // disable busses 785 WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, 0); 786 WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 0); 787 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 0); 788 789 TRACE(("PCI: disabled settings: pcicmd %04" B_PRIx32 ", primary-bus " 790 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 791 "%" B_PRIu32 "\n", 792 ReadConfig(domain, bus, dev, function, PCI_command, 2), 793 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 794 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 795 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 796 } 797 } 798 799 uint8 lastUsedBusNumber = bus; 800 801 // step 2: assign busses to all bridges, and enable them again 802 for (int dev = 0; dev < maxBusDevices; dev++) { 803 uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2); 804 if (vendor_id == 0xffff) 805 continue; 806 807 int numFunctions = _NumFunctions(domain, bus, dev); 808 for (int function = 0; function < numFunctions; function++) { 809 uint16 deviceID = ReadConfig(domain, bus, dev, function, 810 PCI_device_id, 2); 811 if (deviceID == 0xffff) 812 continue; 813 814 uint8 baseClass = ReadConfig(domain, bus, dev, function, 815 PCI_class_base, 1); 816 uint8 subClass = ReadConfig(domain, bus, dev, function, 817 PCI_class_sub, 1); 818 if (baseClass != PCI_bridge || subClass != PCI_pci) 819 continue; 820 821 // skip incorrectly configured devices 822 uint8 headerType = ReadConfig(domain, bus, dev, function, 823 PCI_header_type, 1) & PCI_header_type_mask; 824 if (headerType != PCI_header_type_PCI_to_PCI_bridge) 825 continue; 826 827 TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n", 828 domain, bus, dev, function)); 829 830 // open Scheunentor for enumerating the bus behind the bridge 831 WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, bus); 832 WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 833 lastUsedBusNumber + 1); 834 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 255); 835 836 // enable decoding (too early here?) 837 uint16 pcicmd; 838 pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2); 839 pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master; 840 WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd); 841 842 TRACE(("PCI: probing settings: pcicmd %04" B_PRIx32 ", primary-bus " 843 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 844 "%" B_PRIu32 "\n", 845 ReadConfig(domain, bus, dev, function, PCI_command, 2), 846 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 847 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 848 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 849 850 // enumerate bus 851 _EnumerateBus(domain, lastUsedBusNumber + 1, &lastUsedBusNumber); 852 853 // close Scheunentor 854 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, lastUsedBusNumber); 855 856 TRACE(("PCI: configured settings: pcicmd %04" B_PRIx32 ", primary-bus " 857 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 858 "%" B_PRIu32 "\n", 859 ReadConfig(domain, bus, dev, function, PCI_command, 2), 860 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 861 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 862 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 863 } 864 } 865 if (subordinateBus) 866 *subordinateBus = lastUsedBusNumber; 867 868 TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, lastUsedBusNumber)); 869 } 870 871 872 void 873 PCI::_FixupDevices(uint8 domain, uint8 bus) 874 { 875 FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus); 876 877 int maxBusDevices = _GetDomainData(domain)->max_bus_devices; 878 static int recursed = 0; 879 880 if (recursed++ > 10) { 881 // guard against buggy chipsets 882 // XXX: is there any official limit ? 883 dprintf("PCI: FixupDevices: too many recursions (buggy chipset?)\n"); 884 recursed--; 885 return; 886 } 887 888 for (int dev = 0; dev < maxBusDevices; dev++) { 889 uint16 vendorId = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2); 890 if (vendorId == 0xffff) 891 continue; 892 893 int numFunctions = _NumFunctions(domain, bus, dev); 894 for (int function = 0; function < numFunctions; function++) { 895 uint16 deviceId = ReadConfig(domain, bus, dev, function, 896 PCI_device_id, 2); 897 if (deviceId == 0xffff) 898 continue; 899 900 pci_fixup_device(this, domain, bus, dev, function); 901 902 uint8 baseClass = ReadConfig(domain, bus, dev, function, 903 PCI_class_base, 1); 904 if (baseClass != PCI_bridge) 905 continue; 906 uint8 subClass = ReadConfig(domain, bus, dev, function, 907 PCI_class_sub, 1); 908 if (subClass != PCI_pci) 909 continue; 910 911 // some FIC motherboards have a buggy BIOS... 912 // make sure the header type is correct for a bridge, 913 uint8 headerType = ReadConfig(domain, bus, dev, function, 914 PCI_header_type, 1) & PCI_header_type_mask; 915 if (headerType != PCI_header_type_PCI_to_PCI_bridge) { 916 dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge" 917 " class but wrong header type 0x%02x, ignoring.\n", 918 domain, bus, dev, function, headerType); 919 continue; 920 } 921 922 923 int busBehindBridge = ReadConfig(domain, bus, dev, function, 924 PCI_secondary_bus, 1); 925 926 TRACE(("PCI: FixupDevices: checking bus %d behind %04x:%04x\n", 927 busBehindBridge, vendorId, deviceId)); 928 _FixupDevices(domain, busBehindBridge); 929 } 930 } 931 recursed--; 932 } 933 934 935 void 936 PCI::_ConfigureBridges(PCIBus *bus) 937 { 938 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 939 if (dev->info.class_base == PCI_bridge 940 && dev->info.class_sub == PCI_pci 941 && (dev->info.header_type & PCI_header_type_mask) 942 == PCI_header_type_PCI_to_PCI_bridge) { 943 uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus, 944 dev->device, dev->function, PCI_bridge_control, 2); 945 uint16 bridgeControlNew = bridgeControlOld; 946 // Enable: Parity Error Response, SERR, Master Abort Mode, Discard 947 // Timer SERR 948 // Clear: Discard Timer Status 949 bridgeControlNew |= PCI_bridge_parity_error_response 950 | PCI_bridge_serr | PCI_bridge_master_abort 951 | PCI_bridge_discard_timer_status 952 | PCI_bridge_discard_timer_serr; 953 // Set discard timer to 2^15 PCI clocks 954 bridgeControlNew &= ~(PCI_bridge_primary_discard_timeout 955 | PCI_bridge_secondary_discard_timeout); 956 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 957 PCI_bridge_control, 2, bridgeControlNew); 958 bridgeControlNew = ReadConfig(dev->domain, dev->bus, dev->device, 959 dev->function, PCI_bridge_control, 2); 960 dprintf("PCI: dom %u, bus %u, dev %2u, func %u, changed PCI bridge" 961 " control from 0x%04x to 0x%04x\n", dev->domain, dev->bus, 962 dev->device, dev->function, bridgeControlOld, 963 bridgeControlNew); 964 } 965 966 if (dev->child) 967 _ConfigureBridges(dev->child); 968 } 969 970 if (bus->next) 971 _ConfigureBridges(bus->next); 972 } 973 974 975 void 976 PCI::ClearDeviceStatus(PCIBus *bus, bool dumpStatus) 977 { 978 if (!bus) { 979 if (!fRootBus) 980 return; 981 bus = fRootBus; 982 } 983 984 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 985 // Clear and dump PCI device status 986 uint16 status = ReadConfig(dev->domain, dev->bus, dev->device, 987 dev->function, PCI_status, 2); 988 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 989 PCI_status, 2, status); 990 if (dumpStatus) { 991 kprintf("domain %u, bus %u, dev %2u, func %u, PCI device status " 992 "0x%04x\n", dev->domain, dev->bus, dev->device, dev->function, 993 status); 994 if (status & PCI_status_parity_error_detected) 995 kprintf(" Detected Parity Error\n"); 996 if (status & PCI_status_serr_signalled) 997 kprintf(" Signalled System Error\n"); 998 if (status & PCI_status_master_abort_received) 999 kprintf(" Received Master-Abort\n"); 1000 if (status & PCI_status_target_abort_received) 1001 kprintf(" Received Target-Abort\n"); 1002 if (status & PCI_status_target_abort_signalled) 1003 kprintf(" Signalled Target-Abort\n"); 1004 if (status & PCI_status_parity_signalled) 1005 kprintf(" Master Data Parity Error\n"); 1006 } 1007 1008 if (dev->info.class_base == PCI_bridge 1009 && dev->info.class_sub == PCI_pci) { 1010 // Clear and dump PCI bridge secondary status 1011 uint16 secondaryStatus = ReadConfig(dev->domain, dev->bus, 1012 dev->device, dev->function, PCI_secondary_status, 2); 1013 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1014 PCI_secondary_status, 2, secondaryStatus); 1015 if (dumpStatus) { 1016 kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge " 1017 "secondary status 0x%04x\n", dev->domain, dev->bus, 1018 dev->device, dev->function, secondaryStatus); 1019 if (secondaryStatus & PCI_status_parity_error_detected) 1020 kprintf(" Detected Parity Error\n"); 1021 if (secondaryStatus & PCI_status_serr_signalled) 1022 kprintf(" Received System Error\n"); 1023 if (secondaryStatus & PCI_status_master_abort_received) 1024 kprintf(" Received Master-Abort\n"); 1025 if (secondaryStatus & PCI_status_target_abort_received) 1026 kprintf(" Received Target-Abort\n"); 1027 if (secondaryStatus & PCI_status_target_abort_signalled) 1028 kprintf(" Signalled Target-Abort\n"); 1029 if (secondaryStatus & PCI_status_parity_signalled) 1030 kprintf(" Data Parity Reported\n"); 1031 } 1032 1033 // Clear and dump the discard-timer error bit located in bridge-control register 1034 uint16 bridgeControl = ReadConfig(dev->domain, dev->bus, 1035 dev->device, dev->function, PCI_bridge_control, 2); 1036 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1037 PCI_bridge_control, 2, bridgeControl); 1038 if (dumpStatus) { 1039 kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge " 1040 "control 0x%04x\n", dev->domain, dev->bus, dev->device, 1041 dev->function, bridgeControl); 1042 if (bridgeControl & PCI_bridge_discard_timer_status) { 1043 kprintf(" bridge-control: Discard Timer Error\n"); 1044 } 1045 } 1046 } 1047 1048 if (dev->child) 1049 ClearDeviceStatus(dev->child, dumpStatus); 1050 } 1051 1052 if (bus->next) 1053 ClearDeviceStatus(bus->next, dumpStatus); 1054 } 1055 1056 1057 void 1058 PCI::_DiscoverBus(PCIBus *bus) 1059 { 1060 FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus); 1061 1062 int maxBusDevices = _GetDomainData(bus->domain)->max_bus_devices; 1063 static int recursed = 0; 1064 1065 if (recursed++ > 10) { 1066 // guard against buggy chipsets 1067 // XXX: is there any official limit ? 1068 dprintf("PCI: DiscoverBus: too many recursions (buggy chipset?)\n"); 1069 recursed--; 1070 return; 1071 } 1072 1073 for (int dev = 0; dev < maxBusDevices; dev++) { 1074 uint16 vendorID = ReadConfig(bus->domain, bus->bus, dev, 0, 1075 PCI_vendor_id, 2); 1076 if (vendorID == 0xffff) 1077 continue; 1078 1079 int numFunctions = _NumFunctions(bus->domain, bus->bus, dev); 1080 for (int function = 0; function < numFunctions; function++) 1081 _DiscoverDevice(bus, dev, function); 1082 } 1083 1084 if (bus->next) 1085 _DiscoverBus(bus->next); 1086 recursed--; 1087 } 1088 1089 1090 void 1091 PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function) 1092 { 1093 FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, function); 1094 1095 uint16 deviceID = ReadConfig(bus->domain, bus->bus, dev, function, 1096 PCI_device_id, 2); 1097 if (deviceID == 0xffff) 1098 return; 1099 1100 PCIDev *newDev = _CreateDevice(bus, dev, function); 1101 1102 uint8 baseClass = ReadConfig(bus->domain, bus->bus, dev, function, 1103 PCI_class_base, 1); 1104 uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function, 1105 PCI_class_sub, 1); 1106 uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function, 1107 PCI_header_type, 1) & PCI_header_type_mask; 1108 if (baseClass == PCI_bridge && subClass == PCI_pci 1109 && headerType == PCI_header_type_PCI_to_PCI_bridge) { 1110 uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function, 1111 PCI_secondary_bus, 1); 1112 PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus); 1113 _DiscoverBus(newBus); 1114 } 1115 } 1116 1117 1118 PCIBus * 1119 PCI::_CreateBus(PCIDev *parent, uint8 domain, uint8 bus) 1120 { 1121 PCIBus *newBus = new(std::nothrow) PCIBus; 1122 if (newBus == NULL) 1123 return NULL; 1124 1125 newBus->next = NULL; 1126 newBus->parent = parent; 1127 newBus->child = NULL; 1128 newBus->domain = domain; 1129 newBus->bus = bus; 1130 1131 // append 1132 parent->child = newBus; 1133 1134 return newBus; 1135 } 1136 1137 1138 PCIDev * 1139 PCI::_CreateDevice(PCIBus *parent, uint8 device, uint8 function) 1140 { 1141 FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain, 1142 parent->bus, device, function); 1143 1144 PCIDev *newDev = new(std::nothrow) PCIDev; 1145 if (newDev == NULL) 1146 return NULL; 1147 1148 newDev->next = NULL; 1149 newDev->parent = parent; 1150 newDev->child = NULL; 1151 newDev->domain = parent->domain; 1152 newDev->bus = parent->bus; 1153 newDev->device = device; 1154 newDev->function = function; 1155 memset(&newDev->info, 0, sizeof(newDev->info)); 1156 1157 _ReadBasicInfo(newDev); 1158 1159 FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, " 1160 "class_sub 0x%02x\n", newDev->info.vendor_id, newDev->info.device_id, 1161 newDev->info.class_base, newDev->info.class_sub); 1162 1163 // append 1164 if (parent->child == NULL) { 1165 parent->child = newDev; 1166 } else { 1167 PCIDev *sub = parent->child; 1168 while (sub->next) 1169 sub = sub->next; 1170 sub->next = newDev; 1171 } 1172 1173 return newDev; 1174 } 1175 1176 1177 uint32 1178 PCI::_BarSize(uint32 bits, uint32 mask) 1179 { 1180 bits &= mask; 1181 if (!bits) 1182 return 0; 1183 uint32 size = 1; 1184 while (!(bits & size)) 1185 size <<= 1; 1186 return size; 1187 } 1188 1189 1190 size_t 1191 PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 *_address, uint32 *_size, 1192 uint8 *_flags, uint32 *_highAddress) 1193 { 1194 uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1195 offset, 4); 1196 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1197 0xffffffff); 1198 uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1199 offset, 4); 1200 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1201 oldValue); 1202 1203 uint32 mask = PCI_address_memory_32_mask; 1204 bool is64bit = (oldValue & PCI_address_type_64) != 0; 1205 if ((oldValue & PCI_address_space) == PCI_address_space) 1206 mask = PCI_address_io_mask; 1207 else if (is64bit && _highAddress != NULL) { 1208 *_highAddress = ReadConfig(dev->domain, dev->bus, dev->device, 1209 dev->function, offset + 4, 4); 1210 } 1211 1212 *_address = oldValue & mask; 1213 if (_size != NULL) 1214 *_size = _BarSize(newValue, mask); 1215 if (_flags != NULL) 1216 *_flags = oldValue & ~mask; 1217 return is64bit ? 2 : 1; 1218 } 1219 1220 1221 void 1222 PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *_address, uint32 *_size, 1223 uint8 *_flags) 1224 { 1225 uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1226 offset, 4); 1227 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1228 0xfffffffe); // LSB must be 0 1229 uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1230 offset, 4); 1231 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1232 oldValue); 1233 1234 *_address = oldValue & PCI_rom_address_mask; 1235 if (_size != NULL) 1236 *_size = _BarSize(newValue, PCI_rom_address_mask); 1237 if (_flags != NULL) 1238 *_flags = newValue & 0xf; 1239 } 1240 1241 1242 void 1243 PCI::_ReadBasicInfo(PCIDev *dev) 1244 { 1245 uint8 virtualBus; 1246 1247 if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) { 1248 dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus); 1249 return; 1250 } 1251 1252 dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device, 1253 dev->function, PCI_vendor_id, 2); 1254 dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device, 1255 dev->function, PCI_device_id, 2); 1256 dev->info.bus = virtualBus; 1257 dev->info.device = dev->device; 1258 dev->info.function = dev->function; 1259 dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device, 1260 dev->function, PCI_revision, 1); 1261 dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device, 1262 dev->function, PCI_class_api, 1); 1263 dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device, 1264 dev->function, PCI_class_sub, 1); 1265 dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device, 1266 dev->function, PCI_class_base, 1); 1267 dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device, 1268 dev->function, PCI_line_size, 1); 1269 dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device, 1270 dev->function, PCI_latency, 1); 1271 // BeOS does not mask off the multifunction bit, developer must use 1272 // (header_type & PCI_header_type_mask) 1273 dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device, 1274 dev->function, PCI_header_type, 1); 1275 dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device, 1276 dev->function, PCI_bist, 1); 1277 dev->info.reserved = 0; 1278 } 1279 1280 1281 void 1282 PCI::_ReadHeaderInfo(PCIDev *dev) 1283 { 1284 switch (dev->info.header_type & PCI_header_type_mask) { 1285 case PCI_header_type_generic: 1286 { 1287 // disable PCI device address decoding (io and memory) while BARs 1288 // are modified 1289 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device, 1290 dev->function, PCI_command, 2); 1291 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1292 PCI_command, 2, 1293 pcicmd & ~(PCI_command_io | PCI_command_memory)); 1294 1295 // get BAR size infos 1296 _GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci, 1297 &dev->info.u.h0.rom_size); 1298 for (int i = 0; i < 6;) { 1299 size_t barSize = _GetBarInfo(dev, PCI_base_registers + 4 * i, 1300 &dev->info.u.h0.base_registers_pci[i], 1301 &dev->info.u.h0.base_register_sizes[i], 1302 &dev->info.u.h0.base_register_flags[i], 1303 i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL); 1304 dev->info.u.h0.base_registers[i] = (addr_t)pci_ram_address( 1305 (void *)(addr_t)dev->info.u.h0.base_registers_pci[i]); 1306 i += barSize; 1307 } 1308 1309 // restore PCI device address decoding 1310 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1311 PCI_command, 2, pcicmd); 1312 1313 dev->info.u.h0.rom_base = (addr_t)pci_ram_address( 1314 (void *)(addr_t)dev->info.u.h0.rom_base_pci); 1315 1316 dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus, 1317 dev->device, dev->function, PCI_cardbus_cis, 4); 1318 dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus, 1319 dev->device, dev->function, PCI_subsystem_id, 2); 1320 dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain, 1321 dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id, 2); 1322 dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus, 1323 dev->device, dev->function, PCI_interrupt_line, 1); 1324 dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus, 1325 dev->device, dev->function, PCI_interrupt_pin, 1); 1326 dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus, 1327 dev->device, dev->function, PCI_min_grant, 1); 1328 dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus, 1329 dev->device, dev->function, PCI_max_latency, 1); 1330 break; 1331 } 1332 1333 case PCI_header_type_PCI_to_PCI_bridge: 1334 { 1335 // disable PCI device address decoding (io and memory) while BARs are modified 1336 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device, 1337 dev->function, PCI_command, 2); 1338 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1339 PCI_command, 2, 1340 pcicmd & ~(PCI_command_io | PCI_command_memory)); 1341 1342 _GetRomBarInfo(dev, PCI_bridge_rom_base, 1343 &dev->info.u.h1.rom_base_pci); 1344 for (int i = 0; i < 2;) { 1345 size_t barSize = _GetBarInfo(dev, PCI_base_registers + 4 * i, 1346 &dev->info.u.h1.base_registers_pci[i], 1347 &dev->info.u.h1.base_register_sizes[i], 1348 &dev->info.u.h1.base_register_flags[i], 1349 i < 5 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL); 1350 dev->info.u.h1.base_registers[i] = (addr_t)pci_ram_address( 1351 (void *)(addr_t)dev->info.u.h1.base_registers_pci[i]); 1352 i += barSize; 1353 } 1354 1355 // restore PCI device address decoding 1356 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1357 PCI_command, 2, pcicmd); 1358 1359 dev->info.u.h1.rom_base = (addr_t)pci_ram_address( 1360 (void *)(addr_t)dev->info.u.h1.rom_base_pci); 1361 1362 dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus, 1363 dev->device, dev->function, PCI_primary_bus, 1); 1364 dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus, 1365 dev->device, dev->function, PCI_secondary_bus, 1); 1366 dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain, 1367 dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1); 1368 dev->info.u.h1.secondary_latency = ReadConfig(dev->domain, 1369 dev->bus, dev->device, dev->function, PCI_secondary_latency, 1); 1370 dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus, 1371 dev->device, dev->function, PCI_io_base, 1); 1372 dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus, 1373 dev->device, dev->function, PCI_io_limit, 1); 1374 dev->info.u.h1.secondary_status = ReadConfig(dev->domain, 1375 dev->bus, dev->device, dev->function, PCI_secondary_status, 2); 1376 dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus, 1377 dev->device, dev->function, PCI_memory_base, 2); 1378 dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus, 1379 dev->device, dev->function, PCI_memory_limit, 2); 1380 dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain, 1381 dev->bus, dev->device, dev->function, PCI_prefetchable_memory_base, 2); 1382 dev->info.u.h1.prefetchable_memory_limit = ReadConfig( 1383 dev->domain, dev->bus, dev->device, dev->function, 1384 PCI_prefetchable_memory_limit, 2); 1385 dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig( 1386 dev->domain, dev->bus, dev->device, dev->function, 1387 PCI_prefetchable_memory_base_upper32, 4); 1388 dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig( 1389 dev->domain, dev->bus, dev->device, dev->function, 1390 PCI_prefetchable_memory_limit_upper32, 4); 1391 dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain, 1392 dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2); 1393 dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain, 1394 dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2); 1395 dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus, 1396 dev->device, dev->function, PCI_interrupt_line, 1); 1397 dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus, 1398 dev->device, dev->function, PCI_interrupt_pin, 1); 1399 dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus, 1400 dev->device, dev->function, PCI_bridge_control, 2); 1401 dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus, 1402 dev->device, dev->function, PCI_sub_device_id_1, 2); 1403 dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain, 1404 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2); 1405 break; 1406 } 1407 1408 case PCI_header_type_cardbus: 1409 { 1410 // for testing only, not final: 1411 dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus, 1412 dev->device, dev->function, PCI_sub_device_id_2, 2); 1413 dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain, 1414 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2); 1415 dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus, 1416 dev->device, dev->function, PCI_primary_bus_2, 1); 1417 dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus, 1418 dev->device, dev->function, PCI_secondary_bus_2, 1); 1419 dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain, 1420 dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1); 1421 dev->info.u.h2.secondary_latency = ReadConfig(dev->domain, 1422 dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1); 1423 dev->info.u.h2.reserved = 0; 1424 dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus, 1425 dev->device, dev->function, PCI_memory_base0_2, 4); 1426 dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus, 1427 dev->device, dev->function, PCI_memory_limit0_2, 4); 1428 dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain, 1429 dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4); 1430 dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain, 1431 dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4); 1432 dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus, 1433 dev->device, dev->function, PCI_io_base0_2, 4); 1434 dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus, 1435 dev->device, dev->function, PCI_io_limit0_2, 4); 1436 dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain, 1437 dev->bus, dev->device, dev->function, PCI_io_base1_2, 4); 1438 dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain, 1439 dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4); 1440 dev->info.u.h2.secondary_status = ReadConfig(dev->domain, 1441 dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2); 1442 dev->info.u.h2.bridge_control = ReadConfig(dev->domain, 1443 dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2); 1444 break; 1445 } 1446 1447 default: 1448 TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type)); 1449 break; 1450 } 1451 } 1452 1453 1454 void 1455 PCI::RefreshDeviceInfo() 1456 { 1457 if (fRootBus == NULL) 1458 return; 1459 1460 _RefreshDeviceInfo(fRootBus); 1461 } 1462 1463 1464 void 1465 PCI::_RefreshDeviceInfo(PCIBus *bus) 1466 { 1467 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 1468 _ReadBasicInfo(dev); 1469 _ReadHeaderInfo(dev); 1470 #if defined(__INTEL__) || defined(__x86_64__) 1471 pci_read_arch_info(dev); 1472 #endif 1473 if (dev->child) 1474 _RefreshDeviceInfo(dev->child); 1475 } 1476 1477 if (bus->next) 1478 _RefreshDeviceInfo(bus->next); 1479 } 1480 1481 1482 status_t 1483 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1484 uint16 offset, uint8 size, uint32 *value) 1485 { 1486 domain_data *info = _GetDomainData(domain); 1487 if (!info) 1488 return B_ERROR; 1489 1490 if (device > (info->max_bus_devices - 1) 1491 || function > 7 1492 || (size != 1 && size != 2 && size != 4) 1493 || (size == 2 && (offset & 3) == 3) 1494 || (size == 4 && (offset & 3) != 0)) { 1495 dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n", 1496 domain, bus, device, function, offset, size); 1497 return B_ERROR; 1498 } 1499 1500 return (*info->controller->read_pci_config)(info->controller_cookie, bus, 1501 device, function, offset, size, value); 1502 } 1503 1504 1505 uint32 1506 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1507 uint16 offset, uint8 size) 1508 { 1509 uint32 value; 1510 if (ReadConfig(domain, bus, device, function, offset, size, &value) 1511 != B_OK) 1512 return 0xffffffff; 1513 1514 return value; 1515 } 1516 1517 1518 uint32 1519 PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size) 1520 { 1521 uint32 value; 1522 if (ReadConfig(device->domain, device->bus, device->device, 1523 device->function, offset, size, &value) != B_OK) 1524 return 0xffffffff; 1525 1526 return value; 1527 } 1528 1529 1530 status_t 1531 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1532 uint16 offset, uint8 size, uint32 value) 1533 { 1534 domain_data *info = _GetDomainData(domain); 1535 if (!info) 1536 return B_ERROR; 1537 1538 if (device > (info->max_bus_devices - 1) 1539 || function > 7 1540 || (size != 1 && size != 2 && size != 4) 1541 || (size == 2 && (offset & 3) == 3) 1542 || (size == 4 && (offset & 3) != 0)) { 1543 dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n", 1544 domain, bus, device, function, offset, size); 1545 return B_ERROR; 1546 } 1547 1548 return (*info->controller->write_pci_config)(info->controller_cookie, bus, 1549 device, function, offset, size, value); 1550 } 1551 1552 1553 status_t 1554 PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value) 1555 { 1556 return WriteConfig(device->domain, device->bus, device->device, 1557 device->function, offset, size, value); 1558 } 1559 1560 1561 status_t 1562 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function, 1563 uint8 capID, uint8 *offset) 1564 { 1565 uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2); 1566 if (!(status & PCI_status_capabilities)) { 1567 FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x " 1568 "not supported\n", bus, device, function, capID); 1569 return B_ERROR; 1570 } 1571 1572 uint8 headerType = ReadConfig(domain, bus, device, function, 1573 PCI_header_type, 1); 1574 uint8 capPointer; 1575 1576 switch (headerType & PCI_header_type_mask) { 1577 case PCI_header_type_generic: 1578 case PCI_header_type_PCI_to_PCI_bridge: 1579 capPointer = PCI_capabilities_ptr; 1580 break; 1581 case PCI_header_type_cardbus: 1582 capPointer = PCI_capabilities_ptr_2; 1583 break; 1584 default: 1585 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability " 1586 "%#02x unknown header type\n", bus, device, function, capID); 1587 return B_ERROR; 1588 } 1589 1590 capPointer = ReadConfig(domain, bus, device, function, capPointer, 1); 1591 capPointer &= ~3; 1592 if (capPointer == 0) { 1593 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x " 1594 "empty list\n", bus, device, function, capID); 1595 return B_NAME_NOT_FOUND; 1596 } 1597 1598 for (int i = 0; i < 48; i++) { 1599 if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) { 1600 if (offset != NULL) 1601 *offset = capPointer; 1602 return B_OK; 1603 } 1604 1605 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1, 1606 1); 1607 capPointer &= ~3; 1608 1609 if (capPointer == 0) 1610 return B_NAME_NOT_FOUND; 1611 } 1612 1613 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID); 1614 return B_ERROR; 1615 } 1616 1617 1618 status_t 1619 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset) 1620 { 1621 return FindCapability(device->domain, device->bus, device->device, 1622 device->function, capID, offset); 1623 } 1624 1625 1626 status_t 1627 PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device, 1628 uint8 function, uint16 capID, uint16 *offset) 1629 { 1630 if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie) 1631 != B_OK) { 1632 FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x " 1633 "not supported\n", bus, device, function, capID); 1634 return B_ERROR; 1635 } 1636 uint16 capPointer = PCI_extended_capability; 1637 uint32 capability = ReadConfig(domain, bus, device, function, 1638 capPointer, 4); 1639 1640 if (capability == 0 || capability == 0xffffffff) 1641 return B_NAME_NOT_FOUND; 1642 1643 for (int i = 0; i < 48; i++) { 1644 if (PCI_extcap_id(capability) == capID) { 1645 if (offset != NULL) 1646 *offset = capPointer; 1647 return B_OK; 1648 } 1649 1650 capPointer = PCI_extcap_next_ptr(capability) & ~3; 1651 if (capPointer < PCI_extended_capability) 1652 return B_NAME_NOT_FOUND; 1653 capability = ReadConfig(domain, bus, device, function, 1654 capPointer, 4); 1655 } 1656 1657 TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x " 1658 "circular list\n", bus, device, function, capID); 1659 return B_ERROR; 1660 } 1661 1662 1663 status_t 1664 PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset) 1665 { 1666 return FindExtendedCapability(device->domain, device->bus, device->device, 1667 device->function, capID, offset); 1668 } 1669 1670 1671 status_t 1672 PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device, 1673 uint8 function, uint16 capID, uint8 *offset) 1674 { 1675 uint8 capPointer; 1676 // consider the passed offset as the current ht capability block pointer 1677 // when it's non zero 1678 if (offset != NULL && *offset != 0) { 1679 capPointer = ReadConfig(domain, bus, device, function, *offset + 1, 1680 1); 1681 } else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht, 1682 &capPointer) != B_OK) { 1683 FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x " 1684 "not supported\n", bus, device, function, capID); 1685 return B_NAME_NOT_FOUND; 1686 } 1687 1688 uint16 mask = PCI_ht_command_cap_mask_5_bits; 1689 if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host) 1690 mask = PCI_ht_command_cap_mask_3_bits; 1691 for (int i = 0; i < 48; i++) { 1692 capPointer &= ~3; 1693 if (capPointer == 0) 1694 return B_NAME_NOT_FOUND; 1695 1696 uint8 capability = ReadConfig(domain, bus, device, function, 1697 capPointer, 1); 1698 if (capability == PCI_cap_id_ht) { 1699 if ((ReadConfig(domain, bus, device, function, 1700 capPointer + PCI_ht_command, 2) & mask) == capID) { 1701 if (offset != NULL) 1702 *offset = capPointer; 1703 return B_OK; 1704 } 1705 } 1706 1707 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1, 1708 1); 1709 } 1710 1711 TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x " 1712 "circular list\n", bus, device, function, capID); 1713 return B_ERROR; 1714 } 1715 1716 1717 status_t 1718 PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset) 1719 { 1720 return FindHTCapability(device->domain, device->bus, device->device, 1721 device->function, capID, offset); 1722 } 1723 1724 1725 PCIDev * 1726 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function) 1727 { 1728 return _FindDevice(fRootBus, domain, bus, device, function); 1729 } 1730 1731 1732 PCIDev * 1733 PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device, 1734 uint8 function) 1735 { 1736 if (current->domain == domain) { 1737 // search device on this bus 1738 1739 for (PCIDev *child = current->child; child != NULL; 1740 child = child->next) { 1741 if (child->bus == bus && child->device == device 1742 && child->function == function) 1743 return child; 1744 1745 if (child->child != NULL) { 1746 // search child busses 1747 PCIDev *found = _FindDevice(child->child, domain, bus, device, 1748 function); 1749 if (found != NULL) 1750 return found; 1751 } 1752 } 1753 } 1754 1755 // search other busses 1756 if (current->next != NULL) 1757 return _FindDevice(current->next, domain, bus, device, function); 1758 1759 return NULL; 1760 } 1761 1762 1763 status_t 1764 PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function, 1765 uint8 newInterruptLineValue) 1766 { 1767 PCIDev *device = FindDevice(domain, bus, _device, function); 1768 if (device == NULL) 1769 return B_ERROR; 1770 1771 pci_info &info = device->info; 1772 switch (info.header_type & PCI_header_type_mask) { 1773 case PCI_header_type_generic: 1774 info.u.h0.interrupt_line = newInterruptLineValue; 1775 break; 1776 1777 case PCI_header_type_PCI_to_PCI_bridge: 1778 info.u.h1.interrupt_line = newInterruptLineValue; 1779 break; 1780 1781 default: 1782 return B_ERROR; 1783 } 1784 1785 return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue); 1786 } 1787