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