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 #include <arch/generic/msi.h> 14 #if defined(__i386__) || defined(__x86_64__) 15 #include <arch/x86/msi.h> 16 #endif 17 18 #include "util/kernel_cpp.h" 19 #include "pci_fixup.h" 20 #include "pci_info.h" 21 #include "pci_private.h" 22 #include "pci.h" 23 24 25 #define TRACE_CAP(x...) dprintf(x) 26 #define FLOW(x...) 27 //#define FLOW(x...) dprintf(x) 28 29 30 PCI *gPCI; 31 32 33 // #pragma mark bus manager exports 34 35 36 long 37 pci_get_nth_pci_info(long index, pci_info *outInfo) 38 { 39 return gPCI->GetNthInfo(index, outInfo); 40 } 41 42 43 uint32 44 pci_read_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset, 45 uint8 size) 46 { 47 uint8 bus; 48 uint8 domain; 49 uint32 value; 50 51 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 52 return 0xffffffff; 53 54 if (gPCI->ReadConfig(domain, bus, device, function, offset, size, 55 &value) != B_OK) 56 return 0xffffffff; 57 58 return value; 59 } 60 61 62 void 63 pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset, 64 uint8 size, uint32 value) 65 { 66 uint8 bus; 67 uint8 domain; 68 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 69 return; 70 71 gPCI->WriteConfig(domain, bus, device, function, offset, size, value); 72 } 73 74 75 phys_addr_t 76 pci_ram_address(phys_addr_t childAdr) 77 { 78 phys_addr_t hostAdr = 0; 79 #if defined(__i386__) || defined(__x86_64__) 80 hostAdr = childAdr; 81 #else 82 uint8 domain; 83 pci_resource_range range; 84 if (gPCI->LookupRange(kPciRangeMmio, childAdr, domain, range) >= B_OK) 85 hostAdr = childAdr - range.pci_addr + range.host_addr; 86 #endif 87 //dprintf("pci_ram_address(%#" B_PRIx64 ") -> %#" B_PRIx64 "\n", childAdr, hostAdr); 88 return hostAdr; 89 } 90 91 92 status_t 93 pci_find_capability(uint8 virtualBus, uint8 device, uint8 function, 94 uint8 capID, uint8 *offset) 95 { 96 uint8 bus; 97 uint8 domain; 98 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 99 return B_ERROR; 100 101 return gPCI->FindCapability(domain, bus, device, function, capID, offset); 102 } 103 104 105 status_t 106 pci_find_extended_capability(uint8 virtualBus, uint8 device, uint8 function, 107 uint16 capID, uint16 *offset) 108 { 109 uint8 bus; 110 uint8 domain; 111 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 112 return B_ERROR; 113 114 return gPCI->FindExtendedCapability(domain, bus, device, function, capID, 115 offset); 116 } 117 118 119 status_t 120 pci_reserve_device(uchar virtualBus, uchar device, uchar function, 121 const char *driverName, void *nodeCookie) 122 { 123 status_t status; 124 uint8 bus; 125 uint8 domain; 126 TRACE(("pci_reserve_device(%d, %d, %d, %s)\n", virtualBus, device, function, 127 driverName)); 128 129 /* 130 * we add 2 nodes to the PCI devices, one with constant attributes, 131 * so adding for another driver fails, and a subnode with the 132 * driver-provided informations. 133 */ 134 135 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 136 return B_ERROR; 137 138 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus, 139 // domain, bus, device, function, driverName, nodeCookie)); 140 141 device_attr matchThis[] = { 142 // info about device 143 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}}, 144 145 // location on PCI bus 146 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {.ui8 = domain}}, 147 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {.ui8 = bus}}, 148 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {.ui8 = device}}, 149 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {.ui8 = function}}, 150 {NULL} 151 }; 152 device_attr legacyAttrs[] = { 153 // info about device 154 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}}, 155 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Legacy Driver Reservation"}}, 156 {NULL} 157 }; 158 device_attr drvAttrs[] = { 159 // info about device 160 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}}, 161 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = driverName}}, 162 {"legacy_driver", B_STRING_TYPE, {.string = driverName}}, 163 {"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}}, 164 {NULL} 165 }; 166 device_node *node, *legacy; 167 168 status = B_DEVICE_NOT_FOUND; 169 device_node *root_pci_node = gPCI->_GetDomainData(domain)->root_node; 170 171 node = NULL; 172 if (gDeviceManager->get_next_child_node(root_pci_node, 173 matchThis, &node) < B_OK) { 174 goto err1; 175 } 176 177 // common API for all legacy modules ? 178 //status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME); 179 180 status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME, 181 legacyAttrs, NULL, &legacy); 182 if (status < B_OK) 183 goto err2; 184 185 status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME, 186 drvAttrs, NULL, NULL); 187 if (status < B_OK) 188 goto err3; 189 190 gDeviceManager->put_node(node); 191 192 return B_OK; 193 194 err3: 195 gDeviceManager->unregister_node(legacy); 196 err2: 197 gDeviceManager->put_node(node); 198 err1: 199 TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName, 200 strerror(status))); 201 return status; 202 } 203 204 205 status_t 206 pci_unreserve_device(uchar virtualBus, uchar device, uchar function, 207 const char *driverName, void *nodeCookie) 208 { 209 status_t status; 210 uint8 bus; 211 uint8 domain; 212 TRACE(("pci_unreserve_device(%d, %d, %d, %s)\n", virtualBus, device, 213 function, driverName)); 214 215 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) 216 return B_ERROR; 217 218 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus, 219 // domain, bus, device, function, driverName, nodeCookie)); 220 221 device_attr matchThis[] = { 222 // info about device 223 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}}, 224 225 // location on PCI bus 226 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {.ui8 = domain}}, 227 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {.ui8 = bus}}, 228 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {.ui8 = device}}, 229 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {.ui8 = function}}, 230 {NULL} 231 }; 232 device_attr legacyAttrs[] = { 233 // info about device 234 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}}, 235 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Legacy Driver Reservation"}}, 236 {NULL} 237 }; 238 device_attr drvAttrs[] = { 239 // info about device 240 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}}, 241 {"legacy_driver", B_STRING_TYPE, {.string = driverName}}, 242 {"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}}, 243 {NULL} 244 }; 245 device_node *pci, *node, *legacy, *drv; 246 247 status = B_DEVICE_NOT_FOUND; 248 249 pci = gPCI->_GetDomainData(domain)->root_node; 250 251 node = NULL; 252 if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK) 253 goto err1; 254 255 // common API for all legacy modules ? 256 //status = legacy_driver_unregister(node, driverName, nodeCookie); 257 258 legacy = NULL; 259 if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK) 260 goto err2; 261 262 drv = NULL; 263 if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK) 264 goto err3; 265 266 gDeviceManager->put_node(drv); 267 status = gDeviceManager->unregister_node(drv); 268 //dprintf("unreg:drv:%s\n", strerror(status)); 269 270 gDeviceManager->put_node(legacy); 271 status = gDeviceManager->unregister_node(legacy); 272 //dprintf("unreg:legacy:%s\n", strerror(status)); 273 // we'll get EBUSY here anyway... 274 275 gDeviceManager->put_node(node); 276 return B_OK; 277 278 err3: 279 gDeviceManager->put_node(legacy); 280 err2: 281 gDeviceManager->put_node(node); 282 err1: 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 480 pci_init_deferred(void) 481 { 482 dprintf("pci_init_deferred()\n"); 483 484 if (sInitDone) 485 return B_OK; 486 487 add_debugger_command("inw", &display_io, "dump io words (32-bit)"); 488 add_debugger_command("in32", &display_io, "dump io words (32-bit)"); 489 add_debugger_command("ins", &display_io, "dump io shorts (16-bit)"); 490 add_debugger_command("in16", &display_io, "dump io shorts (16-bit)"); 491 add_debugger_command("inb", &display_io, "dump io bytes (8-bit)"); 492 add_debugger_command("in8", &display_io, "dump io bytes (8-bit)"); 493 494 add_debugger_command("outw", &write_io, "write io words (32-bit)"); 495 add_debugger_command("out32", &write_io, "write io words (32-bit)"); 496 add_debugger_command("outs", &write_io, "write io shorts (16-bit)"); 497 add_debugger_command("out16", &write_io, "write io shorts (16-bit)"); 498 add_debugger_command("outb", &write_io, "write io bytes (8-bit)"); 499 add_debugger_command("out8", &write_io, "write io bytes (8-bit)"); 500 501 gPCI->InitDomainData(); 502 gPCI->InitBus(); 503 504 add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers"); 505 add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info"); 506 507 if (gPCI->Finalize() != B_OK) { 508 TRACE(("PCI: pci_controller_finalize failed\n")); 509 return B_ERROR; 510 } 511 512 pci_print_info(); 513 514 sInitDone = true; 515 return B_OK; 516 } 517 518 519 status_t 520 pci_init(void) 521 { 522 gPCI = new PCI; 523 return B_OK; 524 } 525 526 527 void 528 pci_uninit(void) 529 { 530 delete gPCI; 531 532 if (!sInitDone) 533 return; 534 535 sInitDone = false; 536 537 remove_debugger_command("outw", &write_io); 538 remove_debugger_command("out32", &write_io); 539 remove_debugger_command("outs", &write_io); 540 remove_debugger_command("out16", &write_io); 541 remove_debugger_command("outb", &write_io); 542 remove_debugger_command("out8", &write_io); 543 544 remove_debugger_command("inw", &display_io); 545 remove_debugger_command("in32", &display_io); 546 remove_debugger_command("ins", &display_io); 547 remove_debugger_command("in16", &display_io); 548 remove_debugger_command("inb", &display_io); 549 remove_debugger_command("in8", &display_io); 550 551 remove_debugger_command("pcistatus", &pcistatus); 552 remove_debugger_command("pcirefresh", &pcirefresh); 553 } 554 555 556 // #pragma mark PCI class 557 558 559 PCI::PCI() 560 : 561 fRootBus(0), 562 fDomainCount(0), 563 fBusEnumeration(false), 564 fVirtualBusMap(), 565 fNextVirtualBus(0) 566 { 567 #if defined(__POWERPC__) || defined(__M68K__) 568 fBusEnumeration = true; 569 #endif 570 } 571 572 573 void 574 PCI::InitBus() 575 { 576 PCIBus **nextBus = &fRootBus; 577 for (uint8 i = 0; i < fDomainCount; i++) { 578 PCIBus *bus = new PCIBus; 579 bus->next = NULL; 580 bus->parent = NULL; 581 bus->child = NULL; 582 bus->domain = i; 583 bus->bus = 0; 584 *nextBus = bus; 585 nextBus = &bus->next; 586 } 587 588 if (fBusEnumeration) { 589 for (uint8 i = 0; i < fDomainCount; i++) { 590 _EnumerateBus(i, 0); 591 } 592 } 593 594 if (1) { 595 for (uint8 i = 0; i < fDomainCount; i++) { 596 _FixupDevices(i, 0); 597 } 598 } 599 600 if (fRootBus) { 601 _DiscoverBus(fRootBus); 602 _ConfigureBridges(fRootBus); 603 ClearDeviceStatus(fRootBus, false); 604 _RefreshDeviceInfo(fRootBus); 605 } 606 } 607 608 609 status_t 610 PCI::Finalize() 611 { 612 // TODO: Properly handle multiple domains. Currently finalize fill be called twice for first 613 // domain is second domain is added, but should be called only once. 614 615 for (uint8 i = 0; i < fDomainCount; i++) { 616 pci_controller_module_info* controller = fDomainData[i].controller; 617 if (controller->finalize != NULL) { 618 status_t res = controller->finalize(fDomainData[i].controller_cookie); 619 if (res < B_OK) 620 return res; 621 } 622 } 623 624 return B_OK; 625 } 626 627 628 PCI::~PCI() 629 { 630 } 631 632 633 status_t 634 PCI::_CreateVirtualBus(uint8 domain, uint8 bus, uint8 *virtualBus) 635 { 636 #if defined(__i386__) || defined(__x86_64__) 637 638 // IA32 doesn't use domains 639 if (domain) 640 panic("PCI::CreateVirtualBus domain != 0"); 641 *virtualBus = bus; 642 return B_OK; 643 644 #else 645 646 if (fNextVirtualBus > 0xff) 647 panic("PCI::CreateVirtualBus: virtual bus number space exhausted"); 648 649 uint16 value = domain << 8 | bus; 650 651 for (VirtualBusMap::Iterator it = fVirtualBusMap.Begin(); 652 it != fVirtualBusMap.End(); ++it) { 653 if (it->Value() == value) { 654 *virtualBus = it->Key(); 655 FLOW("PCI::CreateVirtualBus: domain %d, bus %d already in map => " 656 "virtualBus %d\n", domain, bus, *virtualBus); 657 return B_OK; 658 } 659 } 660 661 *virtualBus = fNextVirtualBus++; 662 663 FLOW("PCI::CreateVirtualBus: domain %d, bus %d => virtualBus %d\n", domain, 664 bus, *virtualBus); 665 666 return fVirtualBusMap.Insert(*virtualBus, value); 667 668 #endif 669 } 670 671 672 status_t 673 PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus) 674 { 675 #if defined(__i386__) || defined(__x86_64__) 676 677 // IA32 doesn't use domains 678 *bus = virtualBus; 679 *domain = 0; 680 return B_OK; 681 682 #else 683 684 if (virtualBus >= fNextVirtualBus) 685 return B_ERROR; 686 687 uint16 value = fVirtualBusMap.Get(virtualBus); 688 *domain = value >> 8; 689 *bus = value & 0xff; 690 return B_OK; 691 692 #endif 693 } 694 695 696 status_t 697 PCI::AddController(pci_controller_module_info *controller, void *controller_cookie, 698 device_node *root_node) 699 { 700 if (fDomainCount == MAX_PCI_DOMAINS) 701 return B_ERROR; 702 703 fDomainData[fDomainCount].controller = controller; 704 fDomainData[fDomainCount].controller_cookie = controller_cookie; 705 fDomainData[fDomainCount].root_node = root_node; 706 707 // initialized later to avoid call back into controller at this point 708 fDomainData[fDomainCount].max_bus_devices = -1; 709 710 fDomainCount++; 711 return B_OK; 712 } 713 714 715 status_t 716 PCI::LookupRange(uint32 type, phys_addr_t pciAddr, 717 uint8 &domain, pci_resource_range &range, uint8 **mappedAdr) 718 { 719 if (type >= kPciRangeEnd) 720 return B_BAD_VALUE; 721 722 for (uint8 curDomain = 0; curDomain < fDomainCount; curDomain++) { 723 pci_resource_range const *const &ranges = fDomainData[curDomain].ranges; 724 725 uint32 typeBeg, typeEnd; 726 if (type == kPciRangeMmio) { 727 typeBeg = kPciRangeMmio; 728 typeEnd = kPciRangeMmioEnd; 729 } else { 730 typeBeg = type; 731 typeEnd = type + 1; 732 } 733 for (uint32 curType = typeBeg; curType < typeEnd; curType++) { 734 const pci_resource_range curRange = ranges[curType]; 735 if (pciAddr >= curRange.pci_addr && pciAddr < curRange.pci_addr + curRange.size) { 736 domain = curDomain; 737 range = curRange; 738 #if !(defined(__i386__) || defined(__x86_64__)) 739 if (type == kPciRangeIoPort && mappedAdr != NULL) 740 *mappedAdr = fDomainData[curDomain].io_port_adr; 741 #endif 742 return B_OK; 743 } 744 } 745 } 746 return B_ENTRY_NOT_FOUND; 747 } 748 749 750 void 751 PCI::InitDomainData() 752 { 753 for (uint8 i = 0; i < fDomainCount; i++) { 754 int32 count; 755 status_t status; 756 757 pci_controller_module_info *ctrlModule = fDomainData[i].controller; 758 void *ctrl = fDomainData[i].controller_cookie; 759 760 status = ctrlModule->get_max_bus_devices(ctrl, &count); 761 fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0; 762 763 memset(fDomainData[i].ranges, 0, sizeof(fDomainData[i].ranges)); 764 pci_resource_range range; 765 for (uint32 j = 0; ctrlModule->get_range(ctrl, j, &range) >= B_OK; j++) { 766 if (range.type < kPciRangeEnd && range.size > 0) 767 fDomainData[i].ranges[range.type] = range; 768 } 769 770 #if !(defined(__i386__) || defined(__x86_64__)) 771 // TODO: free resources when domain is detached 772 pci_resource_range &ioPortRange = fDomainData[i].ranges[kPciRangeIoPort]; 773 if (ioPortRange.size > 0) { 774 fDomainData[i].io_port_area = map_physical_memory("PCI IO Ports", 775 ioPortRange.host_addr, ioPortRange.size, B_ANY_KERNEL_ADDRESS, 776 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&fDomainData[i].io_port_adr); 777 778 if (fDomainData[i].io_port_area < B_OK) 779 fDomainData[i].io_port_adr = NULL; 780 } 781 #endif 782 } 783 } 784 785 786 domain_data * 787 PCI::_GetDomainData(uint8 domain) 788 { 789 if (domain >= fDomainCount) 790 return NULL; 791 792 return &fDomainData[domain]; 793 } 794 795 796 inline int 797 PCI::_NumFunctions(uint8 domain, uint8 bus, uint8 device) 798 { 799 uint8 type = ReadConfig(domain, bus, device, 800 0, PCI_header_type, 1); 801 return (type & PCI_multifunction) != 0 ? 8 : 1; 802 } 803 804 805 status_t 806 PCI::GetNthInfo(long index, pci_info *outInfo) 807 { 808 long currentIndex = 0; 809 if (!fRootBus) 810 return B_ERROR; 811 812 return _GetNthInfo(fRootBus, ¤tIndex, index, outInfo); 813 } 814 815 816 status_t 817 PCI::_GetNthInfo(PCIBus *bus, long *currentIndex, long wantIndex, 818 pci_info *outInfo) 819 { 820 // maps tree structure to linear indexed view 821 PCIDev *dev = bus->child; 822 while (dev) { 823 if (*currentIndex == wantIndex) { 824 *outInfo = dev->info; 825 return B_OK; 826 } 827 *currentIndex += 1; 828 if (dev->child && B_OK == _GetNthInfo(dev->child, currentIndex, 829 wantIndex, outInfo)) 830 return B_OK; 831 dev = dev->next; 832 } 833 834 if (bus->next) 835 return _GetNthInfo(bus->next, currentIndex, wantIndex, outInfo); 836 837 return B_ERROR; 838 } 839 840 841 void 842 PCI::_EnumerateBus(uint8 domain, uint8 bus, uint8 *subordinateBus) 843 { 844 TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus)); 845 846 int maxBusDevices = _GetDomainData(domain)->max_bus_devices; 847 848 // step 1: disable all bridges on this bus 849 for (int dev = 0; dev < maxBusDevices; dev++) { 850 uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2); 851 if (vendor_id == 0xffff) 852 continue; 853 854 int numFunctions = _NumFunctions(domain, bus, dev); 855 for (int function = 0; function < numFunctions; function++) { 856 uint16 device_id = ReadConfig(domain, bus, dev, function, 857 PCI_device_id, 2); 858 if (device_id == 0xffff) 859 continue; 860 861 uint8 baseClass = ReadConfig(domain, bus, dev, function, 862 PCI_class_base, 1); 863 uint8 subClass = ReadConfig(domain, bus, dev, function, 864 PCI_class_sub, 1); 865 if (baseClass != PCI_bridge || subClass != PCI_pci) 866 continue; 867 868 // skip incorrectly configured devices 869 uint8 headerType = ReadConfig(domain, bus, dev, function, 870 PCI_header_type, 1) & PCI_header_type_mask; 871 if (headerType != PCI_header_type_PCI_to_PCI_bridge) 872 continue; 873 874 TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n", 875 domain, bus, dev, function)); 876 TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus " 877 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 878 "%" B_PRIu32 "\n", 879 ReadConfig(domain, bus, dev, function, PCI_command, 2), 880 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 881 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 882 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 883 884 // disable decoding 885 uint16 pcicmd; 886 pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2); 887 pcicmd &= ~(PCI_command_io | PCI_command_memory 888 | PCI_command_master); 889 WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd); 890 891 // disable busses 892 WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, 0); 893 WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 0); 894 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 0); 895 896 TRACE(("PCI: disabled settings: pcicmd %04" B_PRIx32 ", primary-bus " 897 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 898 "%" B_PRIu32 "\n", 899 ReadConfig(domain, bus, dev, function, PCI_command, 2), 900 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 901 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 902 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 903 } 904 } 905 906 uint8 lastUsedBusNumber = bus; 907 908 // step 2: assign busses to all bridges, and enable them again 909 for (int dev = 0; dev < maxBusDevices; dev++) { 910 uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2); 911 if (vendor_id == 0xffff) 912 continue; 913 914 int numFunctions = _NumFunctions(domain, bus, dev); 915 for (int function = 0; function < numFunctions; function++) { 916 uint16 deviceID = ReadConfig(domain, bus, dev, function, 917 PCI_device_id, 2); 918 if (deviceID == 0xffff) 919 continue; 920 921 uint8 baseClass = ReadConfig(domain, bus, dev, function, 922 PCI_class_base, 1); 923 uint8 subClass = ReadConfig(domain, bus, dev, function, 924 PCI_class_sub, 1); 925 if (baseClass != PCI_bridge || subClass != PCI_pci) 926 continue; 927 928 // skip incorrectly configured devices 929 uint8 headerType = ReadConfig(domain, bus, dev, function, 930 PCI_header_type, 1) & PCI_header_type_mask; 931 if (headerType != PCI_header_type_PCI_to_PCI_bridge) 932 continue; 933 934 TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n", 935 domain, bus, dev, function)); 936 937 // open Scheunentor for enumerating the bus behind the bridge 938 WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, bus); 939 WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 940 lastUsedBusNumber + 1); 941 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 255); 942 943 // enable decoding (too early here?) 944 uint16 pcicmd; 945 pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2); 946 pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master; 947 WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd); 948 949 TRACE(("PCI: probing settings: pcicmd %04" B_PRIx32 ", primary-bus " 950 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 951 "%" B_PRIu32 "\n", 952 ReadConfig(domain, bus, dev, function, PCI_command, 2), 953 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 954 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 955 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 956 957 // enumerate bus 958 _EnumerateBus(domain, lastUsedBusNumber + 1, &lastUsedBusNumber); 959 960 // close Scheunentor 961 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, lastUsedBusNumber); 962 963 TRACE(("PCI: configured settings: pcicmd %04" B_PRIx32 ", primary-bus " 964 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus " 965 "%" B_PRIu32 "\n", 966 ReadConfig(domain, bus, dev, function, PCI_command, 2), 967 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1), 968 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1), 969 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1))); 970 } 971 } 972 if (subordinateBus) 973 *subordinateBus = lastUsedBusNumber; 974 975 TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, lastUsedBusNumber)); 976 } 977 978 979 void 980 PCI::_FixupDevices(uint8 domain, uint8 bus) 981 { 982 FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus); 983 984 int maxBusDevices = _GetDomainData(domain)->max_bus_devices; 985 static int recursed = 0; 986 987 if (recursed++ > 10) { 988 // guard against buggy chipsets 989 // XXX: is there any official limit ? 990 dprintf("PCI: FixupDevices: too many recursions (buggy chipset?)\n"); 991 recursed--; 992 return; 993 } 994 995 for (int dev = 0; dev < maxBusDevices; dev++) { 996 uint16 vendorId = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2); 997 if (vendorId == 0xffff) 998 continue; 999 1000 int numFunctions = _NumFunctions(domain, bus, dev); 1001 for (int function = 0; function < numFunctions; function++) { 1002 uint16 deviceId = ReadConfig(domain, bus, dev, function, 1003 PCI_device_id, 2); 1004 if (deviceId == 0xffff) 1005 continue; 1006 1007 pci_fixup_device(this, domain, bus, dev, function); 1008 1009 uint8 baseClass = ReadConfig(domain, bus, dev, function, 1010 PCI_class_base, 1); 1011 if (baseClass != PCI_bridge) 1012 continue; 1013 uint8 subClass = ReadConfig(domain, bus, dev, function, 1014 PCI_class_sub, 1); 1015 if (subClass != PCI_pci) 1016 continue; 1017 1018 // some FIC motherboards have a buggy BIOS... 1019 // make sure the header type is correct for a bridge, 1020 uint8 headerType = ReadConfig(domain, bus, dev, function, 1021 PCI_header_type, 1) & PCI_header_type_mask; 1022 if (headerType != PCI_header_type_PCI_to_PCI_bridge) { 1023 dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge" 1024 " class but wrong header type 0x%02x, ignoring.\n", 1025 domain, bus, dev, function, headerType); 1026 continue; 1027 } 1028 1029 1030 int busBehindBridge = ReadConfig(domain, bus, dev, function, 1031 PCI_secondary_bus, 1); 1032 1033 TRACE(("PCI: FixupDevices: checking bus %d behind %04x:%04x\n", 1034 busBehindBridge, vendorId, deviceId)); 1035 _FixupDevices(domain, busBehindBridge); 1036 } 1037 } 1038 recursed--; 1039 } 1040 1041 1042 void 1043 PCI::_ConfigureBridges(PCIBus *bus) 1044 { 1045 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 1046 if (dev->info.class_base == PCI_bridge 1047 && dev->info.class_sub == PCI_pci 1048 && (dev->info.header_type & PCI_header_type_mask) 1049 == PCI_header_type_PCI_to_PCI_bridge) { 1050 uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus, 1051 dev->device, dev->function, PCI_bridge_control, 2); 1052 uint16 bridgeControlNew = bridgeControlOld; 1053 // Enable: Parity Error Response, SERR, Master Abort Mode, Discard 1054 // Timer SERR 1055 // Clear: Discard Timer Status 1056 bridgeControlNew |= PCI_bridge_parity_error_response 1057 | PCI_bridge_serr | PCI_bridge_master_abort 1058 | PCI_bridge_discard_timer_status 1059 | PCI_bridge_discard_timer_serr; 1060 // Set discard timer to 2^15 PCI clocks 1061 bridgeControlNew &= ~(PCI_bridge_primary_discard_timeout 1062 | PCI_bridge_secondary_discard_timeout); 1063 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1064 PCI_bridge_control, 2, bridgeControlNew); 1065 bridgeControlNew = ReadConfig(dev->domain, dev->bus, dev->device, 1066 dev->function, PCI_bridge_control, 2); 1067 dprintf("PCI: dom %u, bus %u, dev %2u, func %u, changed PCI bridge" 1068 " control from 0x%04x to 0x%04x\n", dev->domain, dev->bus, 1069 dev->device, dev->function, bridgeControlOld, 1070 bridgeControlNew); 1071 } 1072 1073 if (dev->child) 1074 _ConfigureBridges(dev->child); 1075 } 1076 1077 if (bus->next) 1078 _ConfigureBridges(bus->next); 1079 } 1080 1081 1082 void 1083 PCI::ClearDeviceStatus(PCIBus *bus, bool dumpStatus) 1084 { 1085 if (!bus) { 1086 if (!fRootBus) 1087 return; 1088 bus = fRootBus; 1089 } 1090 1091 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 1092 // Clear and dump PCI device status 1093 uint16 status = ReadConfig(dev->domain, dev->bus, dev->device, 1094 dev->function, PCI_status, 2); 1095 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1096 PCI_status, 2, status); 1097 if (dumpStatus) { 1098 kprintf("domain %u, bus %u, dev %2u, func %u, PCI device status " 1099 "0x%04x\n", dev->domain, dev->bus, dev->device, dev->function, 1100 status); 1101 if (status & PCI_status_parity_error_detected) 1102 kprintf(" Detected Parity Error\n"); 1103 if (status & PCI_status_serr_signalled) 1104 kprintf(" Signalled System Error\n"); 1105 if (status & PCI_status_master_abort_received) 1106 kprintf(" Received Master-Abort\n"); 1107 if (status & PCI_status_target_abort_received) 1108 kprintf(" Received Target-Abort\n"); 1109 if (status & PCI_status_target_abort_signalled) 1110 kprintf(" Signalled Target-Abort\n"); 1111 if (status & PCI_status_parity_signalled) 1112 kprintf(" Master Data Parity Error\n"); 1113 } 1114 1115 if (dev->info.class_base == PCI_bridge 1116 && dev->info.class_sub == PCI_pci) { 1117 // Clear and dump PCI bridge secondary status 1118 uint16 secondaryStatus = ReadConfig(dev->domain, dev->bus, 1119 dev->device, dev->function, PCI_secondary_status, 2); 1120 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1121 PCI_secondary_status, 2, secondaryStatus); 1122 if (dumpStatus) { 1123 kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge " 1124 "secondary status 0x%04x\n", dev->domain, dev->bus, 1125 dev->device, dev->function, secondaryStatus); 1126 if (secondaryStatus & PCI_status_parity_error_detected) 1127 kprintf(" Detected Parity Error\n"); 1128 if (secondaryStatus & PCI_status_serr_signalled) 1129 kprintf(" Received System Error\n"); 1130 if (secondaryStatus & PCI_status_master_abort_received) 1131 kprintf(" Received Master-Abort\n"); 1132 if (secondaryStatus & PCI_status_target_abort_received) 1133 kprintf(" Received Target-Abort\n"); 1134 if (secondaryStatus & PCI_status_target_abort_signalled) 1135 kprintf(" Signalled Target-Abort\n"); 1136 if (secondaryStatus & PCI_status_parity_signalled) 1137 kprintf(" Data Parity Reported\n"); 1138 } 1139 1140 // Clear and dump the discard-timer error bit located in bridge-control register 1141 uint16 bridgeControl = ReadConfig(dev->domain, dev->bus, 1142 dev->device, dev->function, PCI_bridge_control, 2); 1143 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1144 PCI_bridge_control, 2, bridgeControl); 1145 if (dumpStatus) { 1146 kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge " 1147 "control 0x%04x\n", dev->domain, dev->bus, dev->device, 1148 dev->function, bridgeControl); 1149 if (bridgeControl & PCI_bridge_discard_timer_status) { 1150 kprintf(" bridge-control: Discard Timer Error\n"); 1151 } 1152 } 1153 } 1154 1155 if (dev->child) 1156 ClearDeviceStatus(dev->child, dumpStatus); 1157 } 1158 1159 if (bus->next) 1160 ClearDeviceStatus(bus->next, dumpStatus); 1161 } 1162 1163 1164 void 1165 PCI::_DiscoverBus(PCIBus *bus) 1166 { 1167 FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus); 1168 1169 int maxBusDevices = _GetDomainData(bus->domain)->max_bus_devices; 1170 static int recursed = 0; 1171 1172 if (recursed++ > 10) { 1173 // guard against buggy chipsets 1174 // XXX: is there any official limit ? 1175 dprintf("PCI: DiscoverBus: too many recursions (buggy chipset?)\n"); 1176 recursed--; 1177 return; 1178 } 1179 1180 for (int dev = 0; dev < maxBusDevices; dev++) { 1181 uint16 vendorID = ReadConfig(bus->domain, bus->bus, dev, 0, 1182 PCI_vendor_id, 2); 1183 if (vendorID == 0xffff) 1184 continue; 1185 1186 int numFunctions = _NumFunctions(bus->domain, bus->bus, dev); 1187 for (int function = 0; function < numFunctions; function++) 1188 _DiscoverDevice(bus, dev, function); 1189 } 1190 1191 if (bus->next) 1192 _DiscoverBus(bus->next); 1193 recursed--; 1194 } 1195 1196 1197 void 1198 PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function) 1199 { 1200 FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, function); 1201 1202 uint16 deviceID = ReadConfig(bus->domain, bus->bus, dev, function, 1203 PCI_device_id, 2); 1204 if (deviceID == 0xffff) 1205 return; 1206 1207 PCIDev *newDev = _CreateDevice(bus, dev, function); 1208 1209 uint8 baseClass = ReadConfig(bus->domain, bus->bus, dev, function, 1210 PCI_class_base, 1); 1211 uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function, 1212 PCI_class_sub, 1); 1213 uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function, 1214 PCI_header_type, 1) & PCI_header_type_mask; 1215 if (baseClass == PCI_bridge && subClass == PCI_pci 1216 && headerType == PCI_header_type_PCI_to_PCI_bridge) { 1217 uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function, 1218 PCI_secondary_bus, 1); 1219 PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus); 1220 _DiscoverBus(newBus); 1221 } 1222 } 1223 1224 1225 PCIBus * 1226 PCI::_CreateBus(PCIDev *parent, uint8 domain, uint8 bus) 1227 { 1228 PCIBus *newBus = new(std::nothrow) PCIBus; 1229 if (newBus == NULL) 1230 return NULL; 1231 1232 newBus->next = NULL; 1233 newBus->parent = parent; 1234 newBus->child = NULL; 1235 newBus->domain = domain; 1236 newBus->bus = bus; 1237 1238 // append 1239 parent->child = newBus; 1240 1241 return newBus; 1242 } 1243 1244 1245 PCIDev * 1246 PCI::_CreateDevice(PCIBus *parent, uint8 device, uint8 function) 1247 { 1248 FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain, 1249 parent->bus, device, function); 1250 1251 PCIDev *newDev = new(std::nothrow) PCIDev; 1252 if (newDev == NULL) 1253 return NULL; 1254 1255 newDev->next = NULL; 1256 newDev->parent = parent; 1257 newDev->child = NULL; 1258 newDev->domain = parent->domain; 1259 newDev->bus = parent->bus; 1260 newDev->device = device; 1261 newDev->function = function; 1262 memset(&newDev->info, 0, sizeof(newDev->info)); 1263 1264 _ReadBasicInfo(newDev); 1265 1266 FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, " 1267 "class_sub 0x%02x\n", newDev->info.vendor_id, newDev->info.device_id, 1268 newDev->info.class_base, newDev->info.class_sub); 1269 1270 // append 1271 if (parent->child == NULL) { 1272 parent->child = newDev; 1273 } else { 1274 PCIDev *sub = parent->child; 1275 while (sub->next) 1276 sub = sub->next; 1277 sub->next = newDev; 1278 } 1279 1280 return newDev; 1281 } 1282 1283 1284 uint64 1285 PCI::_BarSize(uint64 bits) 1286 { 1287 if (!bits) 1288 return 0; 1289 1290 uint64 size = 1; 1291 while ((bits & size) == 0) 1292 size <<= 1; 1293 1294 return size; 1295 } 1296 1297 1298 size_t 1299 PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 &_ramAddress, 1300 uint32 &_pciAddress, uint32 &_size, uint8 &flags, uint32 *_highRAMAddress, 1301 uint32 *_highPCIAddress, uint32 *_highSize) 1302 { 1303 uint64 pciAddress = ReadConfig(dev->domain, dev->bus, dev->device, 1304 dev->function, offset, 4); 1305 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1306 0xffffffff); 1307 uint64 size = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1308 offset, 4); 1309 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1310 pciAddress); 1311 1312 uint32 mask = PCI_address_memory_32_mask; 1313 bool is64bit = false; 1314 if ((pciAddress & PCI_address_space) != 0) 1315 mask = PCI_address_io_mask; 1316 else { 1317 is64bit = (pciAddress & PCI_address_type) == PCI_address_type_64; 1318 1319 if (is64bit && _highRAMAddress != NULL) { 1320 uint64 highPCIAddress = ReadConfig(dev->domain, dev->bus, 1321 dev->device, dev->function, offset + 4, 4); 1322 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1323 offset + 4, 4, 0xffffffff); 1324 uint64 highSize = ReadConfig(dev->domain, dev->bus, dev->device, 1325 dev->function, offset + 4, 4); 1326 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1327 offset + 4, 4, highPCIAddress); 1328 1329 pciAddress |= highPCIAddress << 32; 1330 size |= highSize << 32; 1331 } 1332 } 1333 1334 flags = (uint32)pciAddress & ~mask; 1335 pciAddress &= ((uint64)0xffffffff << 32) | mask; 1336 size &= ((uint64)0xffffffff << 32) | mask; 1337 1338 size = _BarSize(size); 1339 uint64 ramAddress = pci_ram_address(pciAddress); 1340 1341 _ramAddress = ramAddress; 1342 _pciAddress = pciAddress; 1343 _size = size; 1344 if (!is64bit) 1345 return 1; 1346 1347 if (_highRAMAddress == NULL || _highPCIAddress == NULL || _highSize == NULL) 1348 panic("64 bit PCI BAR but no space to store high values\n"); 1349 else { 1350 *_highRAMAddress = ramAddress >> 32; 1351 *_highPCIAddress = pciAddress >> 32; 1352 *_highSize = size >> 32; 1353 } 1354 1355 return 2; 1356 } 1357 1358 1359 void 1360 PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 &_address, uint32 *_size, 1361 uint8 *_flags) 1362 { 1363 uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1364 offset, 4); 1365 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1366 0xfffffffe); // LSB must be 0 1367 uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function, 1368 offset, 4); 1369 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4, 1370 oldValue); 1371 1372 _address = oldValue & PCI_rom_address_mask; 1373 if (_size != NULL) 1374 *_size = _BarSize(newValue & PCI_rom_address_mask); 1375 if (_flags != NULL) 1376 *_flags = newValue & 0xf; 1377 } 1378 1379 1380 void 1381 PCI::_ReadBasicInfo(PCIDev *dev) 1382 { 1383 uint8 virtualBus; 1384 1385 if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) { 1386 dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus); 1387 return; 1388 } 1389 1390 dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device, 1391 dev->function, PCI_vendor_id, 2); 1392 dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device, 1393 dev->function, PCI_device_id, 2); 1394 dev->info.bus = virtualBus; 1395 dev->info.device = dev->device; 1396 dev->info.function = dev->function; 1397 dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device, 1398 dev->function, PCI_revision, 1); 1399 dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device, 1400 dev->function, PCI_class_api, 1); 1401 dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device, 1402 dev->function, PCI_class_sub, 1); 1403 dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device, 1404 dev->function, PCI_class_base, 1); 1405 dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device, 1406 dev->function, PCI_line_size, 1); 1407 dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device, 1408 dev->function, PCI_latency, 1); 1409 // BeOS does not mask off the multifunction bit, developer must use 1410 // (header_type & PCI_header_type_mask) 1411 dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device, 1412 dev->function, PCI_header_type, 1); 1413 dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device, 1414 dev->function, PCI_bist, 1); 1415 dev->info.reserved = 0; 1416 } 1417 1418 1419 void 1420 PCI::_ReadHeaderInfo(PCIDev *dev) 1421 { 1422 switch (dev->info.header_type & PCI_header_type_mask) { 1423 case PCI_header_type_generic: 1424 { 1425 // disable PCI device address decoding (io and memory) while BARs 1426 // are modified 1427 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device, 1428 dev->function, PCI_command, 2); 1429 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1430 PCI_command, 2, 1431 pcicmd & ~(PCI_command_io | PCI_command_memory)); 1432 1433 // get BAR size infos 1434 _GetRomBarInfo(dev, PCI_rom_base, dev->info.u.h0.rom_base_pci, 1435 &dev->info.u.h0.rom_size); 1436 for (int i = 0; i < 6;) { 1437 i += _GetBarInfo(dev, PCI_base_registers + 4 * i, 1438 dev->info.u.h0.base_registers[i], 1439 dev->info.u.h0.base_registers_pci[i], 1440 dev->info.u.h0.base_register_sizes[i], 1441 dev->info.u.h0.base_register_flags[i], 1442 i < 5 ? &dev->info.u.h0.base_registers[i + 1] : NULL, 1443 i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL, 1444 i < 5 ? &dev->info.u.h0.base_register_sizes[i + 1] : NULL); 1445 } 1446 1447 // restore PCI device address decoding 1448 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1449 PCI_command, 2, pcicmd); 1450 1451 dev->info.u.h0.rom_base = (uint32)pci_ram_address( 1452 dev->info.u.h0.rom_base_pci); 1453 1454 dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus, 1455 dev->device, dev->function, PCI_cardbus_cis, 4); 1456 dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus, 1457 dev->device, dev->function, PCI_subsystem_id, 2); 1458 dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain, 1459 dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id, 1460 2); 1461 dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus, 1462 dev->device, dev->function, PCI_interrupt_line, 1); 1463 dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus, 1464 dev->device, dev->function, PCI_interrupt_pin, 1); 1465 dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus, 1466 dev->device, dev->function, PCI_min_grant, 1); 1467 dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus, 1468 dev->device, dev->function, PCI_max_latency, 1); 1469 break; 1470 } 1471 1472 case PCI_header_type_PCI_to_PCI_bridge: 1473 { 1474 // disable PCI device address decoding (io and memory) while BARs 1475 // are modified 1476 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device, 1477 dev->function, PCI_command, 2); 1478 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1479 PCI_command, 2, 1480 pcicmd & ~(PCI_command_io | PCI_command_memory)); 1481 1482 _GetRomBarInfo(dev, PCI_bridge_rom_base, 1483 dev->info.u.h1.rom_base_pci); 1484 for (int i = 0; i < 2;) { 1485 i += _GetBarInfo(dev, PCI_base_registers + 4 * i, 1486 dev->info.u.h1.base_registers[i], 1487 dev->info.u.h1.base_registers_pci[i], 1488 dev->info.u.h1.base_register_sizes[i], 1489 dev->info.u.h1.base_register_flags[i], 1490 i < 1 ? &dev->info.u.h1.base_registers[i + 1] : NULL, 1491 i < 1 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL, 1492 i < 1 ? &dev->info.u.h1.base_register_sizes[i + 1] : NULL); 1493 } 1494 1495 // restore PCI device address decoding 1496 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, 1497 PCI_command, 2, pcicmd); 1498 1499 dev->info.u.h1.rom_base = (uint32)pci_ram_address( 1500 dev->info.u.h1.rom_base_pci); 1501 1502 dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus, 1503 dev->device, dev->function, PCI_primary_bus, 1); 1504 dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus, 1505 dev->device, dev->function, PCI_secondary_bus, 1); 1506 dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain, 1507 dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1); 1508 dev->info.u.h1.secondary_latency = ReadConfig(dev->domain, 1509 dev->bus, dev->device, dev->function, PCI_secondary_latency, 1); 1510 dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus, 1511 dev->device, dev->function, PCI_io_base, 1); 1512 dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus, 1513 dev->device, dev->function, PCI_io_limit, 1); 1514 dev->info.u.h1.secondary_status = ReadConfig(dev->domain, 1515 dev->bus, dev->device, dev->function, PCI_secondary_status, 2); 1516 dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus, 1517 dev->device, dev->function, PCI_memory_base, 2); 1518 dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus, 1519 dev->device, dev->function, PCI_memory_limit, 2); 1520 dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain, 1521 dev->bus, dev->device, dev->function, 1522 PCI_prefetchable_memory_base, 2); 1523 dev->info.u.h1.prefetchable_memory_limit = ReadConfig( 1524 dev->domain, dev->bus, dev->device, dev->function, 1525 PCI_prefetchable_memory_limit, 2); 1526 dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig( 1527 dev->domain, dev->bus, dev->device, dev->function, 1528 PCI_prefetchable_memory_base_upper32, 4); 1529 dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig( 1530 dev->domain, dev->bus, dev->device, dev->function, 1531 PCI_prefetchable_memory_limit_upper32, 4); 1532 dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain, 1533 dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2); 1534 dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain, 1535 dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2); 1536 dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus, 1537 dev->device, dev->function, PCI_interrupt_line, 1); 1538 dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus, 1539 dev->device, dev->function, PCI_interrupt_pin, 1); 1540 dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus, 1541 dev->device, dev->function, PCI_bridge_control, 2); 1542 dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus, 1543 dev->device, dev->function, PCI_sub_device_id_1, 2); 1544 dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain, 1545 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2); 1546 break; 1547 } 1548 1549 case PCI_header_type_cardbus: 1550 { 1551 // for testing only, not final: 1552 dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus, 1553 dev->device, dev->function, PCI_sub_device_id_2, 2); 1554 dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain, 1555 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2); 1556 dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus, 1557 dev->device, dev->function, PCI_primary_bus_2, 1); 1558 dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus, 1559 dev->device, dev->function, PCI_secondary_bus_2, 1); 1560 dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain, 1561 dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1); 1562 dev->info.u.h2.secondary_latency = ReadConfig(dev->domain, 1563 dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1); 1564 dev->info.u.h2.reserved = 0; 1565 dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus, 1566 dev->device, dev->function, PCI_memory_base0_2, 4); 1567 dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus, 1568 dev->device, dev->function, PCI_memory_limit0_2, 4); 1569 dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain, 1570 dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4); 1571 dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain, 1572 dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4); 1573 dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus, 1574 dev->device, dev->function, PCI_io_base0_2, 4); 1575 dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus, 1576 dev->device, dev->function, PCI_io_limit0_2, 4); 1577 dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain, 1578 dev->bus, dev->device, dev->function, PCI_io_base1_2, 4); 1579 dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain, 1580 dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4); 1581 dev->info.u.h2.secondary_status = ReadConfig(dev->domain, 1582 dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2); 1583 dev->info.u.h2.bridge_control = ReadConfig(dev->domain, 1584 dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2); 1585 break; 1586 } 1587 1588 default: 1589 TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type)); 1590 break; 1591 } 1592 } 1593 1594 1595 void 1596 PCI::RefreshDeviceInfo() 1597 { 1598 if (fRootBus == NULL) 1599 return; 1600 1601 _RefreshDeviceInfo(fRootBus); 1602 } 1603 1604 1605 void 1606 PCI::_RefreshDeviceInfo(PCIBus *bus) 1607 { 1608 for (PCIDev *dev = bus->child; dev; dev = dev->next) { 1609 _ReadBasicInfo(dev); 1610 _ReadHeaderInfo(dev); 1611 _ReadMSIInfo(dev); 1612 _ReadMSIXInfo(dev); 1613 _ReadHtMappingInfo(dev); 1614 if (dev->child) 1615 _RefreshDeviceInfo(dev->child); 1616 } 1617 1618 if (bus->next) 1619 _RefreshDeviceInfo(bus->next); 1620 } 1621 1622 1623 status_t 1624 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1625 uint16 offset, uint8 size, uint32 *value) 1626 { 1627 domain_data *info = _GetDomainData(domain); 1628 if (!info) 1629 return B_ERROR; 1630 1631 if (device > (info->max_bus_devices - 1) 1632 || function > 7 1633 || (size != 1 && size != 2 && size != 4) 1634 || (size == 2 && (offset & 3) == 3) 1635 || (size == 4 && (offset & 3) != 0)) { 1636 dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n", 1637 domain, bus, device, function, offset, size); 1638 return B_ERROR; 1639 } 1640 1641 return (*info->controller->read_pci_config)(info->controller_cookie, bus, 1642 device, function, offset, size, value); 1643 } 1644 1645 1646 uint32 1647 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1648 uint16 offset, uint8 size) 1649 { 1650 uint32 value; 1651 if (ReadConfig(domain, bus, device, function, offset, size, &value) 1652 != B_OK) 1653 return 0xffffffff; 1654 1655 return value; 1656 } 1657 1658 1659 uint32 1660 PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size) 1661 { 1662 uint32 value; 1663 if (ReadConfig(device->domain, device->bus, device->device, 1664 device->function, offset, size, &value) != B_OK) 1665 return 0xffffffff; 1666 1667 return value; 1668 } 1669 1670 1671 status_t 1672 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function, 1673 uint16 offset, uint8 size, uint32 value) 1674 { 1675 domain_data *info = _GetDomainData(domain); 1676 if (!info) 1677 return B_ERROR; 1678 1679 if (device > (info->max_bus_devices - 1) 1680 || function > 7 1681 || (size != 1 && size != 2 && size != 4) 1682 || (size == 2 && (offset & 3) == 3) 1683 || (size == 4 && (offset & 3) != 0)) { 1684 dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n", 1685 domain, bus, device, function, offset, size); 1686 return B_ERROR; 1687 } 1688 1689 return (*info->controller->write_pci_config)(info->controller_cookie, bus, 1690 device, function, offset, size, value); 1691 } 1692 1693 1694 status_t 1695 PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value) 1696 { 1697 return WriteConfig(device->domain, device->bus, device->device, 1698 device->function, offset, size, value); 1699 } 1700 1701 1702 status_t 1703 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function, 1704 uint8 capID, uint8 *offset) 1705 { 1706 uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2); 1707 if (!(status & PCI_status_capabilities)) { 1708 FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x " 1709 "not supported\n", bus, device, function, capID); 1710 return B_ERROR; 1711 } 1712 1713 uint8 headerType = ReadConfig(domain, bus, device, function, 1714 PCI_header_type, 1); 1715 uint8 capPointer; 1716 1717 switch (headerType & PCI_header_type_mask) { 1718 case PCI_header_type_generic: 1719 case PCI_header_type_PCI_to_PCI_bridge: 1720 capPointer = PCI_capabilities_ptr; 1721 break; 1722 case PCI_header_type_cardbus: 1723 capPointer = PCI_capabilities_ptr_2; 1724 break; 1725 default: 1726 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability " 1727 "%#02x unknown header type\n", bus, device, function, capID); 1728 return B_ERROR; 1729 } 1730 1731 capPointer = ReadConfig(domain, bus, device, function, capPointer, 1); 1732 capPointer &= ~3; 1733 if (capPointer == 0) { 1734 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x " 1735 "empty list\n", bus, device, function, capID); 1736 return B_NAME_NOT_FOUND; 1737 } 1738 1739 for (int i = 0; i < 48; i++) { 1740 if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) { 1741 if (offset != NULL) 1742 *offset = capPointer; 1743 return B_OK; 1744 } 1745 1746 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1, 1747 1); 1748 capPointer &= ~3; 1749 1750 if (capPointer == 0) 1751 return B_NAME_NOT_FOUND; 1752 } 1753 1754 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID); 1755 return B_ERROR; 1756 } 1757 1758 1759 status_t 1760 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset) 1761 { 1762 return FindCapability(device->domain, device->bus, device->device, 1763 device->function, capID, offset); 1764 } 1765 1766 1767 status_t 1768 PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device, 1769 uint8 function, uint16 capID, uint16 *offset) 1770 { 1771 if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie) 1772 != B_OK) { 1773 FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x " 1774 "not supported\n", bus, device, function, capID); 1775 return B_ERROR; 1776 } 1777 uint16 capPointer = PCI_extended_capability; 1778 uint32 capability = ReadConfig(domain, bus, device, function, 1779 capPointer, 4); 1780 1781 if (capability == 0 || capability == 0xffffffff) 1782 return B_NAME_NOT_FOUND; 1783 1784 for (int i = 0; i < 48; i++) { 1785 if (PCI_extcap_id(capability) == capID) { 1786 if (offset != NULL) 1787 *offset = capPointer; 1788 return B_OK; 1789 } 1790 1791 capPointer = PCI_extcap_next_ptr(capability) & ~3; 1792 if (capPointer < PCI_extended_capability) 1793 return B_NAME_NOT_FOUND; 1794 capability = ReadConfig(domain, bus, device, function, 1795 capPointer, 4); 1796 } 1797 1798 TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x " 1799 "circular list\n", bus, device, function, capID); 1800 return B_ERROR; 1801 } 1802 1803 1804 status_t 1805 PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset) 1806 { 1807 return FindExtendedCapability(device->domain, device->bus, device->device, 1808 device->function, capID, offset); 1809 } 1810 1811 1812 status_t 1813 PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device, 1814 uint8 function, uint16 capID, uint8 *offset) 1815 { 1816 uint8 capPointer; 1817 // consider the passed offset as the current ht capability block pointer 1818 // when it's non zero 1819 if (offset != NULL && *offset != 0) { 1820 capPointer = ReadConfig(domain, bus, device, function, *offset + 1, 1821 1); 1822 } else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht, 1823 &capPointer) != B_OK) { 1824 FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x " 1825 "not supported\n", bus, device, function, capID); 1826 return B_NAME_NOT_FOUND; 1827 } 1828 1829 uint16 mask = PCI_ht_command_cap_mask_5_bits; 1830 if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host) 1831 mask = PCI_ht_command_cap_mask_3_bits; 1832 for (int i = 0; i < 48; i++) { 1833 capPointer &= ~3; 1834 if (capPointer == 0) 1835 return B_NAME_NOT_FOUND; 1836 1837 uint8 capability = ReadConfig(domain, bus, device, function, 1838 capPointer, 1); 1839 if (capability == PCI_cap_id_ht) { 1840 if ((ReadConfig(domain, bus, device, function, 1841 capPointer + PCI_ht_command, 2) & mask) == capID) { 1842 if (offset != NULL) 1843 *offset = capPointer; 1844 return B_OK; 1845 } 1846 } 1847 1848 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1, 1849 1); 1850 } 1851 1852 TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x " 1853 "circular list\n", bus, device, function, capID); 1854 return B_ERROR; 1855 } 1856 1857 1858 status_t 1859 PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset) 1860 { 1861 return FindHTCapability(device->domain, device->bus, device->device, 1862 device->function, capID, offset); 1863 } 1864 1865 1866 PCIDev * 1867 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function) 1868 { 1869 return _FindDevice(fRootBus, domain, bus, device, function); 1870 } 1871 1872 1873 PCIDev * 1874 PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device, 1875 uint8 function) 1876 { 1877 if (current->domain == domain) { 1878 // search device on this bus 1879 1880 for (PCIDev *child = current->child; child != NULL; 1881 child = child->next) { 1882 if (child->bus == bus && child->device == device 1883 && child->function == function) 1884 return child; 1885 1886 if (child->child != NULL) { 1887 // search child busses 1888 PCIDev *found = _FindDevice(child->child, domain, bus, device, 1889 function); 1890 if (found != NULL) 1891 return found; 1892 } 1893 } 1894 } 1895 1896 // search other busses 1897 if (current->next != NULL) 1898 return _FindDevice(current->next, domain, bus, device, function); 1899 1900 return NULL; 1901 } 1902 1903 1904 status_t 1905 PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function, 1906 uint8 newInterruptLineValue) 1907 { 1908 PCIDev *device = FindDevice(domain, bus, _device, function); 1909 if (device == NULL) 1910 return B_ERROR; 1911 1912 pci_info &info = device->info; 1913 switch (info.header_type & PCI_header_type_mask) { 1914 case PCI_header_type_generic: 1915 info.u.h0.interrupt_line = newInterruptLineValue; 1916 break; 1917 1918 case PCI_header_type_PCI_to_PCI_bridge: 1919 info.u.h1.interrupt_line = newInterruptLineValue; 1920 break; 1921 1922 default: 1923 return B_ERROR; 1924 } 1925 1926 return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue); 1927 } 1928 1929 1930 uint8 1931 PCI::GetPowerstate(PCIDev *device) 1932 { 1933 uint8 capabilityOffset; 1934 status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset); 1935 if (res == B_OK) { 1936 uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2); 1937 return (state & PCI_pm_mask); 1938 } 1939 return PCI_pm_state_d0; 1940 } 1941 1942 1943 void 1944 PCI::SetPowerstate(PCIDev *device, uint8 newState) 1945 { 1946 uint8 capabilityOffset; 1947 status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset); 1948 if (res == B_OK) { 1949 uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2); 1950 if ((state & PCI_pm_mask) != newState) { 1951 WriteConfig(device, capabilityOffset + PCI_pm_status, 2, 1952 (state & ~PCI_pm_mask) | newState); 1953 if ((state & PCI_pm_mask) == PCI_pm_state_d3) 1954 snooze(10); 1955 } 1956 } 1957 } 1958 1959 1960 status_t 1961 PCI::GetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function, 1962 uint8* state) 1963 { 1964 PCIDev *device = FindDevice(domain, bus, _device, function); 1965 if (device == NULL) 1966 return B_ERROR; 1967 1968 *state = GetPowerstate(device); 1969 return B_OK; 1970 } 1971 1972 1973 status_t 1974 PCI::SetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function, 1975 uint8 newState) 1976 { 1977 PCIDev *device = FindDevice(domain, bus, _device, function); 1978 if (device == NULL) 1979 return B_ERROR; 1980 1981 SetPowerstate(device, newState); 1982 return B_OK; 1983 } 1984 1985 1986 //#pragma mark - MSI 1987 1988 uint8 1989 PCI::GetMSICount(PCIDev *device) 1990 { 1991 if (!msi_supported()) 1992 return 0; 1993 1994 msi_info *info = &device->msi; 1995 if (!info->msi_capable) 1996 return 0; 1997 1998 return info->message_count; 1999 } 2000 2001 2002 status_t 2003 PCI::ConfigureMSI(PCIDev *device, uint8 count, uint8 *startVector) 2004 { 2005 if (!msi_supported()) 2006 return B_UNSUPPORTED; 2007 2008 if (count == 0 || startVector == NULL) 2009 return B_BAD_VALUE; 2010 2011 msi_info *info = &device->msi; 2012 if (!info->msi_capable) 2013 return B_UNSUPPORTED; 2014 2015 if (count > 32 || count > info->message_count 2016 || ((count - 1) & count) != 0 /* needs to be a power of 2 */) { 2017 return B_BAD_VALUE; 2018 } 2019 2020 if (info->configured_count != 0) 2021 return B_BUSY; 2022 2023 status_t result = msi_allocate_vectors(count, &info->start_vector, 2024 &info->address_value, &info->data_value); 2025 if (result != B_OK) 2026 return result; 2027 2028 uint8 offset = info->capability_offset; 2029 WriteConfig(device, offset + PCI_msi_address, 4, 2030 info->address_value & 0xffffffff); 2031 if (info->control_value & PCI_msi_control_64bit) { 2032 WriteConfig(device, offset + PCI_msi_address_high, 4, 2033 info->address_value >> 32); 2034 WriteConfig(device, offset + PCI_msi_data_64bit, 2, 2035 info->data_value); 2036 } else 2037 WriteConfig(device, offset + PCI_msi_data, 2, info->data_value); 2038 2039 info->control_value &= ~PCI_msi_control_mme_mask; 2040 info->control_value |= (ffs(count) - 1) << 4; 2041 WriteConfig(device, offset + PCI_msi_control, 2, info->control_value); 2042 2043 info->configured_count = count; 2044 *startVector = info->start_vector; 2045 return B_OK; 2046 } 2047 2048 2049 status_t 2050 PCI::UnconfigureMSI(PCIDev *device) 2051 { 2052 if (!msi_supported()) 2053 return B_UNSUPPORTED; 2054 2055 // try MSI-X 2056 status_t result = _UnconfigureMSIX(device); 2057 if (result != B_UNSUPPORTED && result != B_NO_INIT) 2058 return result; 2059 2060 msi_info *info = &device->msi; 2061 if (!info->msi_capable) 2062 return B_UNSUPPORTED; 2063 2064 if (info->configured_count == 0) 2065 return B_NO_INIT; 2066 2067 msi_free_vectors(info->configured_count, info->start_vector); 2068 2069 info->control_value &= ~PCI_msi_control_mme_mask; 2070 WriteConfig(device, info->capability_offset + PCI_msi_control, 2, 2071 info->control_value); 2072 2073 info->configured_count = 0; 2074 info->address_value = 0; 2075 info->data_value = 0; 2076 return B_OK; 2077 } 2078 2079 2080 status_t 2081 PCI::EnableMSI(PCIDev *device) 2082 { 2083 if (!msi_supported()) 2084 return B_UNSUPPORTED; 2085 2086 msi_info *info = &device->msi; 2087 if (!info->msi_capable) 2088 return B_UNSUPPORTED; 2089 2090 if (info->configured_count == 0) 2091 return B_NO_INIT; 2092 2093 // ensure the pinned interrupt is disabled 2094 WriteConfig(device, PCI_command, 2, 2095 ReadConfig(device, PCI_command, 2) | PCI_command_int_disable); 2096 2097 // enable msi generation 2098 info->control_value |= PCI_msi_control_enable; 2099 WriteConfig(device, info->capability_offset + PCI_msi_control, 2, 2100 info->control_value); 2101 2102 // enable HT msi mapping (if applicable) 2103 _HtMSIMap(device, info->address_value); 2104 2105 dprintf("msi enabled: 0x%04" B_PRIx32 "\n", 2106 ReadConfig(device, info->capability_offset + PCI_msi_control, 2)); 2107 return B_OK; 2108 } 2109 2110 2111 status_t 2112 PCI::DisableMSI(PCIDev *device) 2113 { 2114 if (!msi_supported()) 2115 return B_UNSUPPORTED; 2116 2117 // try MSI-X 2118 status_t result = _DisableMSIX(device); 2119 if (result != B_UNSUPPORTED && result != B_NO_INIT) 2120 return result; 2121 2122 msi_info *info = &device->msi; 2123 if (!info->msi_capable) 2124 return B_UNSUPPORTED; 2125 2126 if (info->configured_count == 0) 2127 return B_NO_INIT; 2128 2129 // disable HT msi mapping (if applicable) 2130 _HtMSIMap(device, 0); 2131 2132 // disable msi generation 2133 info->control_value &= ~PCI_msi_control_enable; 2134 WriteConfig(device, info->capability_offset + PCI_msi_control, 2, 2135 info->control_value); 2136 2137 return B_OK; 2138 } 2139 2140 2141 uint8 2142 PCI::GetMSIXCount(PCIDev *device) 2143 { 2144 if (!msi_supported()) 2145 return 0; 2146 2147 msix_info *info = &device->msix; 2148 if (!info->msix_capable) 2149 return 0; 2150 2151 return info->message_count; 2152 } 2153 2154 2155 status_t 2156 PCI::ConfigureMSIX(PCIDev *device, uint8 count, uint8 *startVector) 2157 { 2158 if (!msi_supported()) 2159 return B_UNSUPPORTED; 2160 2161 if (count == 0 || startVector == NULL) 2162 return B_BAD_VALUE; 2163 2164 msix_info *info = &device->msix; 2165 if (!info->msix_capable) 2166 return B_UNSUPPORTED; 2167 2168 if (count > 32 || count > info->message_count) { 2169 return B_BAD_VALUE; 2170 } 2171 2172 if (info->configured_count != 0) 2173 return B_BUSY; 2174 2175 // map the table bar 2176 size_t tableSize = info->message_count * 16; 2177 addr_t address; 2178 phys_addr_t barAddr = device->info.u.h0.base_registers[info->table_bar]; 2179 uchar flags = device->info.u.h0.base_register_flags[info->table_bar]; 2180 if ((flags & PCI_address_type) == PCI_address_type_64) { 2181 barAddr |= (uint64)device->info.u.h0.base_registers[ 2182 info->table_bar + 1] << 32; 2183 } 2184 area_id area = map_physical_memory("msi table map", 2185 barAddr, tableSize + info->table_offset, 2186 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 2187 (void**)&address); 2188 if (area < 0) 2189 return area; 2190 info->table_area_id = area; 2191 info->table_address = address + info->table_offset; 2192 2193 // and the pba bar if necessary 2194 if (info->table_bar != info->pba_bar) { 2195 barAddr = device->info.u.h0.base_registers[info->pba_bar]; 2196 flags = device->info.u.h0.base_register_flags[info->pba_bar]; 2197 if ((flags & PCI_address_type) == PCI_address_type_64) { 2198 barAddr |= (uint64)device->info.u.h0.base_registers[ 2199 info->pba_bar + 1] << 32; 2200 } 2201 area = map_physical_memory("msi pba map", 2202 barAddr, tableSize + info->pba_offset, 2203 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 2204 (void**)&address); 2205 if (area < 0) { 2206 delete_area(info->table_area_id); 2207 info->table_area_id = -1; 2208 return area; 2209 } 2210 info->pba_area_id = area; 2211 } else 2212 info->pba_area_id = -1; 2213 info->pba_address = address + info->pba_offset; 2214 2215 status_t result = msi_allocate_vectors(count, &info->start_vector, 2216 &info->address_value, &info->data_value); 2217 if (result != B_OK) { 2218 delete_area(info->pba_area_id); 2219 delete_area(info->table_area_id); 2220 info->pba_area_id = -1; 2221 info->table_area_id = -1; 2222 return result; 2223 } 2224 2225 // ensure the memory i/o is enabled 2226 WriteConfig(device, PCI_command, 2, 2227 ReadConfig(device, PCI_command, 2) | PCI_command_memory); 2228 2229 uint32 data_value = info->data_value; 2230 for (uint32 index = 0; index < count; index++) { 2231 volatile uint32 *entry = (uint32*)(info->table_address + 16 * index); 2232 *(entry + 3) |= PCI_msix_vctrl_mask; 2233 *entry++ = info->address_value & 0xffffffff; 2234 *entry++ = info->address_value >> 32; 2235 *entry++ = data_value++; 2236 *entry &= ~PCI_msix_vctrl_mask; 2237 } 2238 2239 info->configured_count = count; 2240 *startVector = info->start_vector; 2241 dprintf("msix configured for %d vectors\n", count); 2242 return B_OK; 2243 } 2244 2245 2246 status_t 2247 PCI::EnableMSIX(PCIDev *device) 2248 { 2249 if (!msi_supported()) 2250 return B_UNSUPPORTED; 2251 2252 msix_info *info = &device->msix; 2253 if (!info->msix_capable) 2254 return B_UNSUPPORTED; 2255 2256 if (info->configured_count == 0) 2257 return B_NO_INIT; 2258 2259 // ensure the pinned interrupt is disabled 2260 WriteConfig(device, PCI_command, 2, 2261 ReadConfig(device, PCI_command, 2) | PCI_command_int_disable); 2262 2263 // enable msi-x generation 2264 info->control_value |= PCI_msix_control_enable; 2265 WriteConfig(device, info->capability_offset + PCI_msix_control, 2, 2266 info->control_value); 2267 2268 // enable HT msi mapping (if applicable) 2269 _HtMSIMap(device, info->address_value); 2270 2271 dprintf("msi-x enabled: 0x%04" B_PRIx32 "\n", 2272 ReadConfig(device, info->capability_offset + PCI_msix_control, 2)); 2273 return B_OK; 2274 } 2275 2276 2277 void 2278 PCI::_HtMSIMap(PCIDev *device, uint64 address) 2279 { 2280 ht_mapping_info *info = &device->ht_mapping; 2281 if (!info->ht_mapping_capable) 2282 return; 2283 2284 bool enabled = (info->control_value & PCI_ht_command_msi_enable) != 0; 2285 if ((address != 0) != enabled) { 2286 if (enabled) { 2287 info->control_value &= ~PCI_ht_command_msi_enable; 2288 } else { 2289 if ((address >> 20) != (info->address_value >> 20)) 2290 return; 2291 dprintf("ht msi mapping enabled\n"); 2292 info->control_value |= PCI_ht_command_msi_enable; 2293 } 2294 WriteConfig(device, info->capability_offset + PCI_ht_command, 2, 2295 info->control_value); 2296 } 2297 } 2298 2299 2300 void 2301 PCI::_ReadMSIInfo(PCIDev *device) 2302 { 2303 if (!msi_supported()) 2304 return; 2305 2306 msi_info *info = &device->msi; 2307 info->msi_capable = false; 2308 status_t result = FindCapability(device->domain, device->bus, 2309 device->device, device->function, PCI_cap_id_msi, 2310 &info->capability_offset); 2311 if (result != B_OK) 2312 return; 2313 2314 info->msi_capable = true; 2315 info->control_value = ReadConfig(device->domain, device->bus, 2316 device->device, device->function, 2317 info->capability_offset + PCI_msi_control, 2); 2318 info->message_count 2319 = 1 << ((info->control_value & PCI_msi_control_mmc_mask) >> 1); 2320 info->configured_count = 0; 2321 info->data_value = 0; 2322 info->address_value = 0; 2323 } 2324 2325 2326 void 2327 PCI::_ReadMSIXInfo(PCIDev *device) 2328 { 2329 if (!msi_supported()) 2330 return; 2331 2332 msix_info *info = &device->msix; 2333 info->msix_capable = false; 2334 status_t result = FindCapability(device->domain, device->bus, 2335 device->device, device->function, PCI_cap_id_msix, 2336 &info->capability_offset); 2337 if (result != B_OK) 2338 return; 2339 2340 info->msix_capable = true; 2341 info->control_value = ReadConfig(device->domain, device->bus, 2342 device->device, device->function, 2343 info->capability_offset + PCI_msix_control, 2); 2344 info->message_count 2345 = (info->control_value & PCI_msix_control_table_size) + 1; 2346 info->configured_count = 0; 2347 info->data_value = 0; 2348 info->address_value = 0; 2349 info->table_area_id = -1; 2350 info->pba_area_id = -1; 2351 uint32 table_value = ReadConfig(device->domain, device->bus, 2352 device->device, device->function, 2353 info->capability_offset + PCI_msix_table, 4); 2354 uint32 pba_value = ReadConfig(device->domain, device->bus, 2355 device->device, device->function, 2356 info->capability_offset + PCI_msix_pba, 4); 2357 2358 info->table_bar = table_value & PCI_msix_bir_mask; 2359 info->table_offset = table_value & PCI_msix_offset_mask; 2360 info->pba_bar = pba_value & PCI_msix_bir_mask; 2361 info->pba_offset = pba_value & PCI_msix_offset_mask; 2362 } 2363 2364 2365 void 2366 PCI::_ReadHtMappingInfo(PCIDev *device) 2367 { 2368 if (!msi_supported()) 2369 return; 2370 2371 ht_mapping_info *info = &device->ht_mapping; 2372 info->ht_mapping_capable = false; 2373 2374 uint8 offset = 0; 2375 if (FindHTCapability(device, PCI_ht_command_cap_msi_mapping, 2376 &offset) == B_OK) { 2377 info->control_value = ReadConfig(device, offset + PCI_ht_command, 2378 2); 2379 info->capability_offset = offset; 2380 info->ht_mapping_capable = true; 2381 if ((info->control_value & PCI_ht_command_msi_fixed) != 0) { 2382 #if defined(__i386__) || defined(__x86_64__) 2383 info->address_value = MSI_ADDRESS_BASE; 2384 #else 2385 // TODO: investigate what should be set here for non-x86 2386 dprintf("PCI_ht_command_msi_fixed flag unimplemented\n"); 2387 info->address_value = 0; 2388 #endif 2389 } else { 2390 info->address_value = ReadConfig(device, offset 2391 + PCI_ht_msi_address_high, 4); 2392 info->address_value <<= 32; 2393 info->address_value |= ReadConfig(device, offset 2394 + PCI_ht_msi_address_low, 4); 2395 } 2396 dprintf("found an ht msi mapping at %#" B_PRIx64 "\n", 2397 info->address_value); 2398 } 2399 } 2400 2401 2402 status_t 2403 PCI::_UnconfigureMSIX(PCIDev *device) 2404 { 2405 msix_info *info = &device->msix; 2406 if (!info->msix_capable) 2407 return B_UNSUPPORTED; 2408 2409 if (info->configured_count == 0) 2410 return B_NO_INIT; 2411 2412 // disable msi-x generation 2413 info->control_value &= ~PCI_msix_control_enable; 2414 WriteConfig(device, info->capability_offset + PCI_msix_control, 2, 2415 info->control_value); 2416 2417 msi_free_vectors(info->configured_count, info->start_vector); 2418 for (uint8 index = 0; index < info->configured_count; index++) { 2419 volatile uint32 *entry = (uint32*)(info->table_address + 16 * index); 2420 if ((*(entry + 3) & PCI_msix_vctrl_mask) == 0) 2421 *(entry + 3) |= PCI_msix_vctrl_mask; 2422 } 2423 2424 if (info->pba_area_id != -1) 2425 delete_area(info->pba_area_id); 2426 if (info->table_area_id != -1) 2427 delete_area(info->table_area_id); 2428 info->pba_area_id= -1; 2429 info->table_area_id = -1; 2430 2431 info->configured_count = 0; 2432 info->address_value = 0; 2433 info->data_value = 0; 2434 return B_OK; 2435 } 2436 2437 2438 status_t 2439 PCI::_DisableMSIX(PCIDev *device) 2440 { 2441 msix_info *info = &device->msix; 2442 if (!info->msix_capable) 2443 return B_UNSUPPORTED; 2444 2445 if (info->configured_count == 0) 2446 return B_NO_INIT; 2447 2448 // disable HT msi mapping (if applicable) 2449 _HtMSIMap(device, 0); 2450 2451 // disable msi-x generation 2452 info->control_value &= ~PCI_msix_control_enable; 2453 gPCI->WriteConfig(device, info->capability_offset + PCI_msix_control, 2, 2454 info->control_value); 2455 2456 return B_OK; 2457 } 2458