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(__i386__) || 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(__i386__) || 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 uint64 1178 PCI::_BarSize(uint64 bits) 1179 { 1180 if (!bits) 1181 return 0; 1182 1183 uint64 size = 1; 1184 while ((bits & size) == 0) 1185 size <<= 1; 1186 1187 return size; 1188 } 1189 1190 1191 size_t 1192 PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 &_ramAddress, 1193 uint32 &_pciAddress, uint32 &_size, uint8 &flags, uint32 *_highRAMAddress, 1194 uint32 *_highPCIAddress, uint32 *_highSize) 1195 { 1196 uint64 pciAddress = ReadConfig(dev->domain, dev->bus, dev->device, 1197 dev->function, offset, 4); 1198 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1199 0xffffffff); 1200 uint64 size = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1201 offset, 4); 1202 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1203 pciAddress); 1204 1205 uint32 mask = PCI_address_memory_32_mask; 1206 bool is64bit = false; 1207 if ((pciAddress & PCI_address_space) != 0) 1208 mask = PCI_address_io_mask; 1209 else { 1210 is64bit = (pciAddress & PCI_address_type) == PCI_address_type_64; 1211 1212 if (is64bit && _highRAMAddress != NULL) { 1213 uint64 highPCIAddress = ReadConfig(dev->domain, dev->bus, 1214 dev->device, dev->function, offset + 4, 4); 1215 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1216 offset + 4, 4, 0xffffffff); 1217 uint64 highSize = ReadConfig(dev->domain, dev->bus, dev->device, 1218 dev->function, offset + 4, 4); 1219 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1220 offset + 4, 4, highPCIAddress); 1221 1222 pciAddress |= highPCIAddress << 32; 1223 size |= highSize << 32; 1224 } 1225 } 1226 1227 flags = (uint32)pciAddress & ~mask; 1228 pciAddress &= ((uint64)0xffffffff << 32) | mask; 1229 size &= ((uint64)0xffffffff << 32) | mask; 1230 1231 size = _BarSize(size); 1232 uint64 ramAddress = pci_ram_address(pciAddress); 1233 1234 _ramAddress = ramAddress; 1235 _pciAddress = pciAddress; 1236 _size = size; 1237 if (!is64bit) 1238 return 1; 1239 1240 if (_highRAMAddress == NULL || _highPCIAddress == NULL || _highSize == NULL) 1241 panic("64 bit PCI BAR but no space to store high values\n"); 1242 else { 1243 *_highRAMAddress = ramAddress >> 32; 1244 *_highPCIAddress = pciAddress >> 32; 1245 *_highSize = size >> 32; 1246 } 1247 1248 return 2; 1249 } 1250 1251 1252 void 1253 PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 &_address, uint32 *_size, 1254 uint8 *_flags) 1255 { 1256 uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1257 offset, 4); 1258 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1259 0xfffffffe); // LSB must be 0 1260 uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1261 offset, 4); 1262 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1263 oldValue); 1264 1265 _address = oldValue & PCI_rom_address_mask; 1266 if (_size != NULL) 1267 *_size = _BarSize(newValue & PCI_rom_address_mask); 1268 if (_flags != NULL) 1269 *_flags = newValue & 0xf; 1270 } 1271 1272 1273 void 1274 PCI::_ReadBasicInfo(PCIDev *dev) 1275 { 1276 uint8 virtualBus; 1277 1278 if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) { 1279 dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus); 1280 return; 1281 } 1282 1283 dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device, 1284 dev->function, PCI_vendor_id, 2); 1285 dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device, 1286 dev->function, PCI_device_id, 2); 1287 dev->info.bus = virtualBus; 1288 dev->info.device = dev->device; 1289 dev->info.function = dev->function; 1290 dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device, 1291 dev->function, PCI_revision, 1); 1292 dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device, 1293 dev->function, PCI_class_api, 1); 1294 dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device, 1295 dev->function, PCI_class_sub, 1); 1296 dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device, 1297 dev->function, PCI_class_base, 1); 1298 dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device, 1299 dev->function, PCI_line_size, 1); 1300 dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device, 1301 dev->function, PCI_latency, 1); 1302 // BeOS does not mask off the multifunction bit, developer must use 1303 // (header_type & PCI_header_type_mask) 1304 dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device, 1305 dev->function, PCI_header_type, 1); 1306 dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device, 1307 dev->function, PCI_bist, 1); 1308 dev->info.reserved = 0; 1309 } 1310 1311 1312 void 1313 PCI::_ReadHeaderInfo(PCIDev *dev) 1314 { 1315 switch (dev->info.header_type & PCI_header_type_mask) { 1316 case PCI_header_type_generic: 1317 { 1318 // disable PCI device address decoding (io and memory) while BARs 1319 // are modified 1320 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device, 1321 dev->function, PCI_command, 2); 1322 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1323 PCI_command, 2, 1324 pcicmd & ~(PCI_command_io | PCI_command_memory)); 1325 1326 // get BAR size infos 1327 _GetRomBarInfo(dev, PCI_rom_base, dev->info.u.h0.rom_base_pci, 1328 &dev->info.u.h0.rom_size); 1329 for (int i = 0; i < 6;) { 1330 i += _GetBarInfo(dev, PCI_base_registers + 4 * i, 1331 dev->info.u.h0.base_registers[i], 1332 dev->info.u.h0.base_registers_pci[i], 1333 dev->info.u.h0.base_register_sizes[i], 1334 dev->info.u.h0.base_register_flags[i], 1335 i < 5 ? &dev->info.u.h0.base_registers[i + 1] : NULL, 1336 i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL, 1337 i < 5 ? &dev->info.u.h0.base_register_sizes[i + 1] : NULL); 1338 } 1339 1340 // restore PCI device address decoding 1341 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1342 PCI_command, 2, pcicmd); 1343 1344 dev->info.u.h0.rom_base = (uint32)pci_ram_address( 1345 dev->info.u.h0.rom_base_pci); 1346 1347 dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus, 1348 dev->device, dev->function, PCI_cardbus_cis, 4); 1349 dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus, 1350 dev->device, dev->function, PCI_subsystem_id, 2); 1351 dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain, 1352 dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id, 1353 2); 1354 dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus, 1355 dev->device, dev->function, PCI_interrupt_line, 1); 1356 dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus, 1357 dev->device, dev->function, PCI_interrupt_pin, 1); 1358 dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus, 1359 dev->device, dev->function, PCI_min_grant, 1); 1360 dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus, 1361 dev->device, dev->function, PCI_max_latency, 1); 1362 break; 1363 } 1364 1365 case PCI_header_type_PCI_to_PCI_bridge: 1366 { 1367 // disable PCI device address decoding (io and memory) while BARs 1368 // are modified 1369 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device, 1370 dev->function, PCI_command, 2); 1371 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1372 PCI_command, 2, 1373 pcicmd & ~(PCI_command_io | PCI_command_memory)); 1374 1375 _GetRomBarInfo(dev, PCI_bridge_rom_base, 1376 dev->info.u.h1.rom_base_pci); 1377 for (int i = 0; i < 2;) { 1378 i += _GetBarInfo(dev, PCI_base_registers + 4 * i, 1379 dev->info.u.h1.base_registers[i], 1380 dev->info.u.h1.base_registers_pci[i], 1381 dev->info.u.h1.base_register_sizes[i], 1382 dev->info.u.h1.base_register_flags[i], 1383 i < 1 ? &dev->info.u.h1.base_registers[i + 1] : NULL, 1384 i < 1 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL, 1385 i < 1 ? &dev->info.u.h1.base_register_sizes[i + 1] : NULL); 1386 } 1387 1388 // restore PCI device address decoding 1389 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1390 PCI_command, 2, pcicmd); 1391 1392 dev->info.u.h1.rom_base = (uint32)pci_ram_address( 1393 dev->info.u.h1.rom_base_pci); 1394 1395 dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus, 1396 dev->device, dev->function, PCI_primary_bus, 1); 1397 dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus, 1398 dev->device, dev->function, PCI_secondary_bus, 1); 1399 dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain, 1400 dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1); 1401 dev->info.u.h1.secondary_latency = ReadConfig(dev->domain, 1402 dev->bus, dev->device, dev->function, PCI_secondary_latency, 1); 1403 dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus, 1404 dev->device, dev->function, PCI_io_base, 1); 1405 dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus, 1406 dev->device, dev->function, PCI_io_limit, 1); 1407 dev->info.u.h1.secondary_status = ReadConfig(dev->domain, 1408 dev->bus, dev->device, dev->function, PCI_secondary_status, 2); 1409 dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus, 1410 dev->device, dev->function, PCI_memory_base, 2); 1411 dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus, 1412 dev->device, dev->function, PCI_memory_limit, 2); 1413 dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain, 1414 dev->bus, dev->device, dev->function, 1415 PCI_prefetchable_memory_base, 2); 1416 dev->info.u.h1.prefetchable_memory_limit = ReadConfig( 1417 dev->domain, dev->bus, dev->device, dev->function, 1418 PCI_prefetchable_memory_limit, 2); 1419 dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig( 1420 dev->domain, dev->bus, dev->device, dev->function, 1421 PCI_prefetchable_memory_base_upper32, 4); 1422 dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig( 1423 dev->domain, dev->bus, dev->device, dev->function, 1424 PCI_prefetchable_memory_limit_upper32, 4); 1425 dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain, 1426 dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2); 1427 dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain, 1428 dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2); 1429 dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus, 1430 dev->device, dev->function, PCI_interrupt_line, 1); 1431 dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus, 1432 dev->device, dev->function, PCI_interrupt_pin, 1); 1433 dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus, 1434 dev->device, dev->function, PCI_bridge_control, 2); 1435 dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus, 1436 dev->device, dev->function, PCI_sub_device_id_1, 2); 1437 dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain, 1438 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2); 1439 break; 1440 } 1441 1442 case PCI_header_type_cardbus: 1443 { 1444 // for testing only, not final: 1445 dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus, 1446 dev->device, dev->function, PCI_sub_device_id_2, 2); 1447 dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain, 1448 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2); 1449 dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus, 1450 dev->device, dev->function, PCI_primary_bus_2, 1); 1451 dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus, 1452 dev->device, dev->function, PCI_secondary_bus_2, 1); 1453 dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain, 1454 dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1); 1455 dev->info.u.h2.secondary_latency = ReadConfig(dev->domain, 1456 dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1); 1457 dev->info.u.h2.reserved = 0; 1458 dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus, 1459 dev->device, dev->function, PCI_memory_base0_2, 4); 1460 dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus, 1461 dev->device, dev->function, PCI_memory_limit0_2, 4); 1462 dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain, 1463 dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4); 1464 dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain, 1465 dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4); 1466 dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus, 1467 dev->device, dev->function, PCI_io_base0_2, 4); 1468 dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus, 1469 dev->device, dev->function, PCI_io_limit0_2, 4); 1470 dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain, 1471 dev->bus, dev->device, dev->function, PCI_io_base1_2, 4); 1472 dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain, 1473 dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4); 1474 dev->info.u.h2.secondary_status = ReadConfig(dev->domain, 1475 dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2); 1476 dev->info.u.h2.bridge_control = ReadConfig(dev->domain, 1477 dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2); 1478 break; 1479 } 1480 1481 default: 1482 TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type)); 1483 break; 1484 } 1485 } 1486 1487 1488 void 1489 PCI::RefreshDeviceInfo() 1490 { 1491 if (fRootBus == NULL) 1492 return; 1493 1494 _RefreshDeviceInfo(fRootBus); 1495 } 1496 1497 1498 void 1499 PCI::_RefreshDeviceInfo(PCIBus *bus) 1500 { 1501 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 1502 _ReadBasicInfo(dev); 1503 _ReadHeaderInfo(dev); 1504 #if defined(__i386__) || defined(__x86_64__) 1505 pci_read_arch_info(dev); 1506 #endif 1507 if (dev->child) 1508 _RefreshDeviceInfo(dev->child); 1509 } 1510 1511 if (bus->next) 1512 _RefreshDeviceInfo(bus->next); 1513 } 1514 1515 1516 status_t 1517 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1518 uint16 offset, uint8 size, uint32 *value) 1519 { 1520 domain_data *info = _GetDomainData(domain); 1521 if (!info) 1522 return B_ERROR; 1523 1524 if (device > (info->max_bus_devices - 1) 1525 || function > 7 1526 || (size != 1 && size != 2 && size != 4) 1527 || (size == 2 && (offset & 3) == 3) 1528 || (size == 4 && (offset & 3) != 0)) { 1529 dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n", 1530 domain, bus, device, function, offset, size); 1531 return B_ERROR; 1532 } 1533 1534 return (*info->controller->read_pci_config)(info->controller_cookie, bus, 1535 device, function, offset, size, value); 1536 } 1537 1538 1539 uint32 1540 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1541 uint16 offset, uint8 size) 1542 { 1543 uint32 value; 1544 if (ReadConfig(domain, bus, device, function, offset, size, &value) 1545 != B_OK) 1546 return 0xffffffff; 1547 1548 return value; 1549 } 1550 1551 1552 uint32 1553 PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size) 1554 { 1555 uint32 value; 1556 if (ReadConfig(device->domain, device->bus, device->device, 1557 device->function, offset, size, &value) != B_OK) 1558 return 0xffffffff; 1559 1560 return value; 1561 } 1562 1563 1564 status_t 1565 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1566 uint16 offset, uint8 size, uint32 value) 1567 { 1568 domain_data *info = _GetDomainData(domain); 1569 if (!info) 1570 return B_ERROR; 1571 1572 if (device > (info->max_bus_devices - 1) 1573 || function > 7 1574 || (size != 1 && size != 2 && size != 4) 1575 || (size == 2 && (offset & 3) == 3) 1576 || (size == 4 && (offset & 3) != 0)) { 1577 dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n", 1578 domain, bus, device, function, offset, size); 1579 return B_ERROR; 1580 } 1581 1582 return (*info->controller->write_pci_config)(info->controller_cookie, bus, 1583 device, function, offset, size, value); 1584 } 1585 1586 1587 status_t 1588 PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value) 1589 { 1590 return WriteConfig(device->domain, device->bus, device->device, 1591 device->function, offset, size, value); 1592 } 1593 1594 1595 status_t 1596 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function, 1597 uint8 capID, uint8 *offset) 1598 { 1599 uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2); 1600 if (!(status & PCI_status_capabilities)) { 1601 FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x " 1602 "not supported\n", bus, device, function, capID); 1603 return B_ERROR; 1604 } 1605 1606 uint8 headerType = ReadConfig(domain, bus, device, function, 1607 PCI_header_type, 1); 1608 uint8 capPointer; 1609 1610 switch (headerType & PCI_header_type_mask) { 1611 case PCI_header_type_generic: 1612 case PCI_header_type_PCI_to_PCI_bridge: 1613 capPointer = PCI_capabilities_ptr; 1614 break; 1615 case PCI_header_type_cardbus: 1616 capPointer = PCI_capabilities_ptr_2; 1617 break; 1618 default: 1619 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability " 1620 "%#02x unknown header type\n", bus, device, function, capID); 1621 return B_ERROR; 1622 } 1623 1624 capPointer = ReadConfig(domain, bus, device, function, capPointer, 1); 1625 capPointer &= ~3; 1626 if (capPointer == 0) { 1627 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x " 1628 "empty list\n", bus, device, function, capID); 1629 return B_NAME_NOT_FOUND; 1630 } 1631 1632 for (int i = 0; i < 48; i++) { 1633 if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) { 1634 if (offset != NULL) 1635 *offset = capPointer; 1636 return B_OK; 1637 } 1638 1639 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1, 1640 1); 1641 capPointer &= ~3; 1642 1643 if (capPointer == 0) 1644 return B_NAME_NOT_FOUND; 1645 } 1646 1647 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID); 1648 return B_ERROR; 1649 } 1650 1651 1652 status_t 1653 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset) 1654 { 1655 return FindCapability(device->domain, device->bus, device->device, 1656 device->function, capID, offset); 1657 } 1658 1659 1660 status_t 1661 PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device, 1662 uint8 function, uint16 capID, uint16 *offset) 1663 { 1664 if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie) 1665 != B_OK) { 1666 FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x " 1667 "not supported\n", bus, device, function, capID); 1668 return B_ERROR; 1669 } 1670 uint16 capPointer = PCI_extended_capability; 1671 uint32 capability = ReadConfig(domain, bus, device, function, 1672 capPointer, 4); 1673 1674 if (capability == 0 || capability == 0xffffffff) 1675 return B_NAME_NOT_FOUND; 1676 1677 for (int i = 0; i < 48; i++) { 1678 if (PCI_extcap_id(capability) == capID) { 1679 if (offset != NULL) 1680 *offset = capPointer; 1681 return B_OK; 1682 } 1683 1684 capPointer = PCI_extcap_next_ptr(capability) & ~3; 1685 if (capPointer < PCI_extended_capability) 1686 return B_NAME_NOT_FOUND; 1687 capability = ReadConfig(domain, bus, device, function, 1688 capPointer, 4); 1689 } 1690 1691 TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x " 1692 "circular list\n", bus, device, function, capID); 1693 return B_ERROR; 1694 } 1695 1696 1697 status_t 1698 PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset) 1699 { 1700 return FindExtendedCapability(device->domain, device->bus, device->device, 1701 device->function, capID, offset); 1702 } 1703 1704 1705 status_t 1706 PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device, 1707 uint8 function, uint16 capID, uint8 *offset) 1708 { 1709 uint8 capPointer; 1710 // consider the passed offset as the current ht capability block pointer 1711 // when it's non zero 1712 if (offset != NULL && *offset != 0) { 1713 capPointer = ReadConfig(domain, bus, device, function, *offset + 1, 1714 1); 1715 } else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht, 1716 &capPointer) != B_OK) { 1717 FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x " 1718 "not supported\n", bus, device, function, capID); 1719 return B_NAME_NOT_FOUND; 1720 } 1721 1722 uint16 mask = PCI_ht_command_cap_mask_5_bits; 1723 if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host) 1724 mask = PCI_ht_command_cap_mask_3_bits; 1725 for (int i = 0; i < 48; i++) { 1726 capPointer &= ~3; 1727 if (capPointer == 0) 1728 return B_NAME_NOT_FOUND; 1729 1730 uint8 capability = ReadConfig(domain, bus, device, function, 1731 capPointer, 1); 1732 if (capability == PCI_cap_id_ht) { 1733 if ((ReadConfig(domain, bus, device, function, 1734 capPointer + PCI_ht_command, 2) & mask) == capID) { 1735 if (offset != NULL) 1736 *offset = capPointer; 1737 return B_OK; 1738 } 1739 } 1740 1741 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1, 1742 1); 1743 } 1744 1745 TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x " 1746 "circular list\n", bus, device, function, capID); 1747 return B_ERROR; 1748 } 1749 1750 1751 status_t 1752 PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset) 1753 { 1754 return FindHTCapability(device->domain, device->bus, device->device, 1755 device->function, capID, offset); 1756 } 1757 1758 1759 PCIDev * 1760 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function) 1761 { 1762 return _FindDevice(fRootBus, domain, bus, device, function); 1763 } 1764 1765 1766 PCIDev * 1767 PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device, 1768 uint8 function) 1769 { 1770 if (current->domain == domain) { 1771 // search device on this bus 1772 1773 for (PCIDev *child = current->child; child != NULL; 1774 child = child->next) { 1775 if (child->bus == bus && child->device == device 1776 && child->function == function) 1777 return child; 1778 1779 if (child->child != NULL) { 1780 // search child busses 1781 PCIDev *found = _FindDevice(child->child, domain, bus, device, 1782 function); 1783 if (found != NULL) 1784 return found; 1785 } 1786 } 1787 } 1788 1789 // search other busses 1790 if (current->next != NULL) 1791 return _FindDevice(current->next, domain, bus, device, function); 1792 1793 return NULL; 1794 } 1795 1796 1797 status_t 1798 PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function, 1799 uint8 newInterruptLineValue) 1800 { 1801 PCIDev *device = FindDevice(domain, bus, _device, function); 1802 if (device == NULL) 1803 return B_ERROR; 1804 1805 pci_info &info = device->info; 1806 switch (info.header_type & PCI_header_type_mask) { 1807 case PCI_header_type_generic: 1808 info.u.h0.interrupt_line = newInterruptLineValue; 1809 break; 1810 1811 case PCI_header_type_PCI_to_PCI_bridge: 1812 info.u.h1.interrupt_line = newInterruptLineValue; 1813 break; 1814 1815 default: 1816 return B_ERROR; 1817 } 1818 1819 return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue); 1820 } 1821 1822 1823 uint8 1824 PCI::GetPowerstate(PCIDev *device) 1825 { 1826 uint8 capabilityOffset; 1827 status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset); 1828 if (res == B_OK) { 1829 uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2); 1830 return (state & PCI_pm_mask); 1831 } 1832 return PCI_pm_state_d0; 1833 } 1834 1835 1836 void 1837 PCI::SetPowerstate(PCIDev *device, uint8 newState) 1838 { 1839 uint8 capabilityOffset; 1840 status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset); 1841 if (res == B_OK) { 1842 uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2); 1843 if ((state & PCI_pm_mask) != newState) { 1844 WriteConfig(device, capabilityOffset + PCI_pm_status, 2, 1845 (state & ~PCI_pm_mask) | newState); 1846 if ((state & PCI_pm_mask) == PCI_pm_state_d3) 1847 snooze(10); 1848 } 1849 } 1850 } 1851 1852