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