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