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