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