1 /* 2 * Copyright 2007, Hugo Santos. All Rights Reserved. 3 * Copyright 2004, Marcus Overhagen. All Rights Reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 extern "C" { 9 #include "device.h" 10 } 11 12 #include <stdlib.h> 13 14 #include <algorithm> 15 16 #include <arch/cpu.h> 17 18 extern "C" { 19 #include <compat/dev/pci/pcireg.h> 20 #include <compat/dev/pci/pcivar.h> 21 #include <compat/machine/resource.h> 22 #include <compat/sys/mutex.h> 23 #include <compat/machine/bus.h> 24 #include <compat/sys/rman.h> 25 #include <compat/sys/bus.h> 26 } 27 28 // private kernel header to get B_NO_HANDLED_INFO 29 #include <int.h> 30 31 #include <PCI_x86.h> 32 33 34 //#define DEBUG_BUS_SPACE_RW 35 #ifdef DEBUG_BUS_SPACE_RW 36 # define TRACE_BUS_SPACE_RW(x) driver_printf x 37 #else 38 # define TRACE_BUS_SPACE_RW(x) 39 #endif 40 41 //#define DEBUG_PCI 42 #ifdef DEBUG_PCI 43 # define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args) 44 #else 45 # define TRACE_PCI(dev, format, args...) do { } while (0) 46 #endif 47 48 49 struct internal_intr { 50 device_t dev; 51 driver_filter_t* filter; 52 driver_intr_t *handler; 53 void *arg; 54 int irq; 55 uint32 flags; 56 57 thread_id thread; 58 sem_id sem; 59 int32 handling; 60 }; 61 62 static int32 intr_wrapper(void *data); 63 64 65 static area_id 66 map_mem(void **virtualAddr, phys_addr_t _phy, size_t size, uint32 protection, 67 const char *name) 68 { 69 uint32 offset = _phy & (B_PAGE_SIZE - 1); 70 phys_addr_t physicalAddr = _phy - offset; 71 area_id area; 72 73 size = roundup(size + offset, B_PAGE_SIZE); 74 area = map_physical_memory(name, physicalAddr, size, B_ANY_KERNEL_ADDRESS, 75 protection, virtualAddr); 76 if (area < B_OK) 77 return area; 78 79 *virtualAddr = (uint8 *)(*virtualAddr) + offset; 80 81 return area; 82 } 83 84 85 static int 86 bus_alloc_irq_resource(device_t dev, struct resource *res) 87 { 88 uint8 irq = pci_read_config(dev, PCI_interrupt_line, 1); 89 if (irq == 0 || irq == 0xff) 90 return -1; 91 92 /* TODO: IRQ resources! */ 93 res->r_bustag = 0; 94 res->r_bushandle = irq; 95 96 return 0; 97 } 98 99 100 static int 101 bus_alloc_mem_resource(device_t dev, struct resource *res, pci_info *info, 102 int bar_index) 103 { 104 phys_addr_t addr = info->u.h0.base_registers[bar_index]; 105 uint64 size = info->u.h0.base_register_sizes[bar_index]; 106 uchar flags = info->u.h0.base_register_flags[bar_index]; 107 108 // reject empty regions 109 if (size == 0) 110 return -1; 111 112 // reject I/O space 113 if ((flags & PCI_address_space) != 0) 114 return -1; 115 116 // TODO: check flags & PCI_address_prefetchable ? 117 118 if ((flags & PCI_address_type) == PCI_address_type_64) { 119 addr |= (uint64)info->u.h0.base_registers[bar_index + 1] << 32; 120 size |= (uint64)info->u.h0.base_register_sizes[bar_index + 1] << 32; 121 } 122 123 // enable this I/O resource 124 if (pci_enable_io(dev, SYS_RES_MEMORY) != 0) 125 return -1; 126 127 void *virtualAddr; 128 129 res->r_mapped_area = map_mem(&virtualAddr, addr, size, 0, 130 "bus_alloc_resource(MEMORY)"); 131 if (res->r_mapped_area < B_OK) 132 return -1; 133 134 res->r_bustag = X86_BUS_SPACE_MEM; 135 res->r_bushandle = (bus_space_handle_t)virtualAddr; 136 return 0; 137 } 138 139 140 static int 141 bus_alloc_ioport_resource(device_t dev, struct resource *res, pci_info *info, 142 int bar_index) 143 { 144 uint32 size = info->u.h0.base_register_sizes[bar_index]; 145 uchar flags = info->u.h0.base_register_flags[bar_index]; 146 147 // reject empty regions 148 if (size == 0) 149 return -1; 150 151 // reject memory space 152 if ((flags & PCI_address_space) == 0) 153 return -1; 154 155 // enable this I/O resource 156 if (pci_enable_io(dev, SYS_RES_IOPORT) != 0) 157 return -1; 158 159 res->r_bustag = X86_BUS_SPACE_IO; 160 res->r_bushandle = info->u.h0.base_registers[bar_index]; 161 return 0; 162 } 163 164 165 static int 166 bus_register_to_bar_index(pci_info *info, int regid) 167 { 168 // check the offset really is of a BAR 169 if (regid < PCI_base_registers || (regid % sizeof(uint32) != 0) 170 || (regid >= PCI_base_registers + 6 * (int)sizeof(uint32))) { 171 return -1; 172 } 173 174 // turn offset into array index 175 regid -= PCI_base_registers; 176 regid /= sizeof(uint32); 177 return regid; 178 } 179 180 181 struct resource * 182 bus_alloc_resource(device_t dev, int type, int *rid, unsigned long start, 183 unsigned long end, unsigned long count, uint32 flags) 184 { 185 struct resource *res; 186 int result = -1; 187 188 if (type != SYS_RES_IRQ && type != SYS_RES_MEMORY 189 && type != SYS_RES_IOPORT) 190 return NULL; 191 192 device_printf(dev, "bus_alloc_resource(%i, [%i], 0x%lx, 0x%lx, 0x%lx," 193 "0x%" B_PRIx32 ")\n", type, *rid, start, end, count, flags); 194 195 // maybe a local array of resources is enough 196 res = (struct resource *)malloc(sizeof(struct resource)); 197 if (res == NULL) 198 return NULL; 199 200 if (type == SYS_RES_IRQ) { 201 if (*rid == 0) { 202 // pinned interrupt 203 result = bus_alloc_irq_resource(dev, res); 204 } else { 205 // msi or msi-x interrupt at index *rid - 1 206 pci_info *info; 207 info = &((struct root_device_softc *)dev->root->softc)->pci_info; 208 res->r_bustag = 1; 209 res->r_bushandle = info->u.h0.interrupt_line + *rid - 1; 210 result = 0; 211 } 212 } else if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 213 pci_info *info 214 = &((struct root_device_softc *)dev->root->softc)->pci_info; 215 int bar_index = bus_register_to_bar_index(info, *rid); 216 if (bar_index >= 0) { 217 if (type == SYS_RES_MEMORY) 218 result = bus_alloc_mem_resource(dev, res, info, bar_index); 219 else 220 result = bus_alloc_ioport_resource(dev, res, info, bar_index); 221 } 222 } 223 224 if (result < 0) { 225 free(res); 226 return NULL; 227 } 228 229 res->r_type = type; 230 return res; 231 } 232 233 234 int 235 bus_release_resource(device_t dev, int type, int rid, struct resource *res) 236 { 237 if (res->r_type != type) 238 panic("bus_release_resource: mismatch"); 239 240 if (type == SYS_RES_MEMORY) 241 delete_area(res->r_mapped_area); 242 243 free(res); 244 return 0; 245 } 246 247 248 int 249 bus_alloc_resources(device_t dev, struct resource_spec *resourceSpec, 250 struct resource **resources) 251 { 252 int i; 253 254 for (i = 0; resourceSpec[i].type != -1; i++) { 255 resources[i] = bus_alloc_resource_any(dev, 256 resourceSpec[i].type, &resourceSpec[i].rid, resourceSpec[i].flags); 257 if (resources[i] == NULL 258 && (resourceSpec[i].flags & RF_OPTIONAL) == 0) { 259 for (++i; resourceSpec[i].type != -1; i++) { 260 resources[i] = NULL; 261 } 262 263 bus_release_resources(dev, resourceSpec, resources); 264 return ENXIO; 265 } 266 } 267 return 0; 268 } 269 270 271 void 272 bus_release_resources(device_t dev, const struct resource_spec *resourceSpec, 273 struct resource **resources) 274 { 275 int i; 276 277 for (i = 0; resourceSpec[i].type != -1; i++) { 278 if (resources[i] == NULL) 279 continue; 280 281 bus_release_resource(dev, resourceSpec[i].type, resourceSpec[i].rid, 282 resources[i]); 283 resources[i] = NULL; 284 } 285 } 286 287 288 bus_space_handle_t 289 rman_get_bushandle(struct resource *res) 290 { 291 return res->r_bushandle; 292 } 293 294 295 bus_space_tag_t 296 rman_get_bustag(struct resource *res) 297 { 298 return res->r_bustag; 299 } 300 301 302 int 303 rman_get_rid(struct resource *res) 304 { 305 return 0; 306 } 307 308 309 void* 310 rman_get_virtual(struct resource *res) 311 { 312 return NULL; 313 } 314 315 316 // #pragma mark - Interrupt handling 317 318 319 static int32 320 intr_wrapper(void *data) 321 { 322 struct internal_intr *intr = (struct internal_intr *)data; 323 324 //device_printf(intr->dev, "in interrupt handler.\n"); 325 326 if (!HAIKU_CHECK_DISABLE_INTERRUPTS(intr->dev)) 327 return B_UNHANDLED_INTERRUPT; 328 329 release_sem_etc(intr->sem, 1, B_DO_NOT_RESCHEDULE); 330 return intr->handling ? B_HANDLED_INTERRUPT : B_INVOKE_SCHEDULER; 331 } 332 333 334 static int32 335 intr_handler(void *data) 336 { 337 struct internal_intr *intr = (struct internal_intr *)data; 338 status_t status; 339 340 while (1) { 341 status = acquire_sem(intr->sem); 342 if (status < B_OK) 343 break; 344 345 //device_printf(intr->dev, "in soft interrupt handler.\n"); 346 347 atomic_or(&intr->handling, 1); 348 intr->handler(intr->arg); 349 atomic_and(&intr->handling, 0); 350 HAIKU_REENABLE_INTERRUPTS(intr->dev); 351 } 352 353 return 0; 354 } 355 356 357 static void 358 free_internal_intr(struct internal_intr *intr) 359 { 360 if (intr->sem >= B_OK) { 361 status_t status; 362 delete_sem(intr->sem); 363 wait_for_thread(intr->thread, &status); 364 } 365 366 free(intr); 367 } 368 369 370 int 371 bus_setup_intr(device_t dev, struct resource *res, int flags, 372 driver_filter_t* filter, driver_intr_t handler, void *arg, void **_cookie) 373 { 374 /* TODO check MPSAFE etc */ 375 376 struct internal_intr *intr = (struct internal_intr *)malloc( 377 sizeof(struct internal_intr)); 378 char semName[64]; 379 status_t status; 380 381 if (intr == NULL) 382 return B_NO_MEMORY; 383 384 intr->dev = dev; 385 intr->filter = filter; 386 intr->handler = handler; 387 intr->arg = arg; 388 intr->irq = res->r_bushandle; 389 intr->flags = flags; 390 intr->sem = -1; 391 intr->thread = -1; 392 393 if (filter != NULL) { 394 status = install_io_interrupt_handler(intr->irq, 395 (interrupt_handler)intr->filter, intr->arg, 0); 396 } else { 397 snprintf(semName, sizeof(semName), "%s intr", dev->device_name); 398 399 intr->sem = create_sem(0, semName); 400 if (intr->sem < B_OK) { 401 free(intr); 402 return B_NO_MEMORY; 403 } 404 405 snprintf(semName, sizeof(semName), "%s intr handler", dev->device_name); 406 407 intr->thread = spawn_kernel_thread(intr_handler, semName, 408 B_REAL_TIME_DISPLAY_PRIORITY, intr); 409 if (intr->thread < B_OK) { 410 delete_sem(intr->sem); 411 free(intr); 412 return B_NO_MEMORY; 413 } 414 415 status = install_io_interrupt_handler(intr->irq, 416 intr_wrapper, intr, 0); 417 } 418 419 if (status == B_OK && res->r_bustag == 1 && gPCIx86 != NULL) { 420 // this is an msi, enable it 421 pci_info *info 422 = &((struct root_device_softc *)dev->root->softc)->pci_info; 423 if (((struct root_device_softc *)dev->root->softc)->is_msi) { 424 if (gPCIx86->enable_msi(info->bus, info->device, 425 info->function) != B_OK) { 426 device_printf(dev, "enabling msi failed\n"); 427 bus_teardown_intr(dev, res, intr); 428 return ENODEV; 429 } 430 } else if (((struct root_device_softc *)dev->root->softc)->is_msix) { 431 if (gPCIx86->enable_msix(info->bus, info->device, 432 info->function) != B_OK) { 433 device_printf(dev, "enabling msix failed\n"); 434 bus_teardown_intr(dev, res, intr); 435 return ENODEV; 436 } 437 } 438 } 439 440 if (status < B_OK) { 441 free_internal_intr(intr); 442 return status; 443 } 444 445 resume_thread(intr->thread); 446 447 *_cookie = intr; 448 return 0; 449 } 450 451 452 int 453 bus_teardown_intr(device_t dev, struct resource *res, void *arg) 454 { 455 struct internal_intr *intr = (struct internal_intr *)arg; 456 if (intr == NULL) 457 return -1; 458 459 struct root_device_softc *root = (struct root_device_softc *)dev->root->softc; 460 461 if ((root->is_msi || root->is_msix) && gPCIx86 != NULL) { 462 // disable msi generation 463 pci_info *info = &root->pci_info; 464 gPCIx86->disable_msi(info->bus, info->device, info->function); 465 } 466 467 if (intr->filter != NULL) { 468 remove_io_interrupt_handler(intr->irq, (interrupt_handler)intr->filter, 469 intr->arg); 470 } else { 471 remove_io_interrupt_handler(intr->irq, intr_wrapper, intr); 472 } 473 474 free_internal_intr(intr); 475 return 0; 476 } 477 478 479 int 480 bus_bind_intr(device_t dev, struct resource *res, int cpu) 481 { 482 if (dev->parent == NULL) 483 return EINVAL; 484 485 // TODO 486 return 0; 487 } 488 489 490 int bus_describe_intr(device_t dev, struct resource *irq, void *cookie, 491 const char* fmt, ...) 492 { 493 if (dev->parent == NULL) 494 return EINVAL; 495 496 // we don't really support names for interrupts 497 return 0; 498 } 499 500 501 // #pragma mark - bus functions 502 503 504 bus_dma_tag_t 505 bus_get_dma_tag(device_t dev) 506 { 507 return NULL; 508 } 509 510 511 int 512 bus_generic_suspend(device_t dev) 513 { 514 UNIMPLEMENTED(); 515 return B_ERROR; 516 } 517 518 519 int 520 bus_generic_resume(device_t dev) 521 { 522 UNIMPLEMENTED(); 523 return B_ERROR; 524 } 525 526 527 void 528 bus_generic_shutdown(device_t dev) 529 { 530 UNIMPLEMENTED(); 531 } 532 533 534 int 535 bus_print_child_header(device_t dev, device_t child) 536 { 537 UNIMPLEMENTED(); 538 return B_ERROR; 539 } 540 541 542 int 543 bus_print_child_footer(device_t dev, device_t child) 544 { 545 UNIMPLEMENTED(); 546 return B_ERROR; 547 } 548 549 550 int 551 bus_generic_print_child(device_t dev, device_t child) 552 { 553 UNIMPLEMENTED(); 554 return B_ERROR; 555 } 556 557 558 void 559 bus_generic_driver_added(device_t dev, driver_t *driver) 560 { 561 UNIMPLEMENTED(); 562 } 563 564 565 int 566 bus_child_present(device_t child) 567 { 568 device_t parent = device_get_parent(child); 569 if (parent == NULL) 570 return 0; 571 572 return bus_child_present(parent); 573 } 574 575 576 void 577 bus_enumerate_hinted_children(device_t bus) 578 { 579 #if 0 580 UNIMPLEMENTED(); 581 #endif 582 } 583 584 585 586 // #pragma mark - PCI functions 587 588 589 uint32_t 590 pci_read_config(device_t dev, int offset, int size) 591 { 592 pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info; 593 594 uint32_t value = gPci->read_pci_config(info->bus, info->device, 595 info->function, offset, size); 596 TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value); 597 return value; 598 } 599 600 601 void 602 pci_write_config(device_t dev, int offset, uint32_t value, int size) 603 { 604 pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info; 605 606 TRACE_PCI(dev, "pci_write_config(%i, 0x%x, %i)\n", offset, value, size); 607 608 gPci->write_pci_config(info->bus, info->device, info->function, offset, 609 size, value); 610 } 611 612 613 uint16_t 614 pci_get_vendor(device_t dev) 615 { 616 return pci_read_config(dev, PCI_vendor_id, 2); 617 } 618 619 620 uint16_t 621 pci_get_device(device_t dev) 622 { 623 return pci_read_config(dev, PCI_device_id, 2); 624 } 625 626 627 uint16_t 628 pci_get_subvendor(device_t dev) 629 { 630 return pci_read_config(dev, PCI_subsystem_vendor_id, 2); 631 } 632 633 634 uint16_t 635 pci_get_subdevice(device_t dev) 636 { 637 return pci_read_config(dev, PCI_subsystem_id, 2); 638 } 639 640 641 uint8_t 642 pci_get_revid(device_t dev) 643 { 644 return pci_read_config(dev, PCI_revision, 1); 645 } 646 647 648 uint32_t 649 pci_get_domain(device_t dev) 650 { 651 return 0; 652 } 653 654 uint32_t 655 pci_get_devid(device_t dev) 656 { 657 return pci_read_config(dev, PCI_device_id, 2) << 16 | 658 pci_read_config(dev, PCI_vendor_id, 2); 659 } 660 661 uint8_t 662 pci_get_cachelnsz(device_t dev) 663 { 664 return pci_read_config(dev, PCI_line_size, 1); 665 } 666 667 uint8_t * 668 pci_get_ether(device_t dev) 669 { 670 /* used in if_dc to get the MAC from CardBus CIS for Xircom card */ 671 return NULL; /* NULL is handled in the caller correctly */ 672 } 673 674 uint8_t 675 pci_get_bus(device_t dev) 676 { 677 pci_info *info 678 = &((struct root_device_softc *)dev->root->softc)->pci_info; 679 return info->bus; 680 } 681 682 683 uint8_t 684 pci_get_slot(device_t dev) 685 { 686 pci_info *info 687 = &((struct root_device_softc *)dev->root->softc)->pci_info; 688 return info->device; 689 } 690 691 692 uint8_t 693 pci_get_function(device_t dev) 694 { 695 pci_info *info 696 = &((struct root_device_softc *)dev->root->softc)->pci_info; 697 return info->function; 698 } 699 700 701 device_t 702 pci_find_dbsf(uint32_t domain, uint8_t bus, uint8_t slot, uint8_t func) 703 { 704 // We don't support that yet - if we want to support the multi port 705 // feature of the Broadcom BCM 570x driver, we would have to change 706 // that. 707 return NULL; 708 } 709 710 711 static void 712 pci_set_command_bit(device_t dev, uint16_t bit) 713 { 714 uint16_t command = pci_read_config(dev, PCI_command, 2); 715 pci_write_config(dev, PCI_command, command | bit, 2); 716 } 717 718 719 int 720 pci_enable_busmaster(device_t dev) 721 { 722 pci_set_command_bit(dev, PCI_command_master); 723 return 0; 724 } 725 726 727 int 728 pci_enable_io(device_t dev, int space) 729 { 730 /* adapted from FreeBSD's pci_enable_io_method */ 731 int bit = 0; 732 733 switch (space) { 734 case SYS_RES_IOPORT: 735 bit = PCI_command_io; 736 break; 737 case SYS_RES_MEMORY: 738 bit = PCI_command_memory; 739 break; 740 default: 741 return EINVAL; 742 } 743 744 pci_set_command_bit(dev, bit); 745 if (pci_read_config(dev, PCI_command, 2) & bit) 746 return 0; 747 748 device_printf(dev, "pci_enable_io(%d) failed.\n", space); 749 750 return ENXIO; 751 } 752 753 754 int 755 pci_find_cap(device_t dev, int capability, int *capreg) 756 { 757 return pci_find_extcap(dev, capability, capreg); 758 } 759 760 761 int 762 pci_find_extcap(device_t child, int capability, int *_capabilityRegister) 763 { 764 uint8 capabilityPointer; 765 uint8 headerType; 766 uint16 status; 767 768 status = pci_read_config(child, PCIR_STATUS, 2); 769 if ((status & PCIM_STATUS_CAPPRESENT) == 0) 770 return ENXIO; 771 772 headerType = pci_read_config(child, PCI_header_type, 1); 773 switch (headerType & PCIM_HDRTYPE) { 774 case 0: 775 case 1: 776 capabilityPointer = PCIR_CAP_PTR; 777 break; 778 case 2: 779 capabilityPointer = PCIR_CAP_PTR_2; 780 break; 781 default: 782 return ENXIO; 783 } 784 capabilityPointer = pci_read_config(child, capabilityPointer, 1); 785 786 while (capabilityPointer != 0) { 787 if (pci_read_config(child, capabilityPointer + PCICAP_ID, 1) 788 == capability) { 789 if (_capabilityRegister != NULL) 790 *_capabilityRegister = capabilityPointer; 791 return 0; 792 } 793 capabilityPointer = pci_read_config(child, 794 capabilityPointer + PCICAP_NEXTPTR, 1); 795 } 796 797 return ENOENT; 798 } 799 800 801 int 802 pci_msi_count(device_t dev) 803 { 804 pci_info *info; 805 if (gPCIx86 == NULL) 806 return 0; 807 808 info = &((struct root_device_softc *)dev->root->softc)->pci_info; 809 return gPCIx86->get_msi_count(info->bus, info->device, info->function); 810 } 811 812 813 int 814 pci_alloc_msi(device_t dev, int *count) 815 { 816 pci_info *info; 817 uint8 startVector = 0; 818 if (gPCIx86 == NULL) 819 return ENODEV; 820 821 info = &((struct root_device_softc *)dev->root->softc)->pci_info; 822 823 if (gPCIx86->configure_msi(info->bus, info->device, info->function, *count, 824 &startVector) != B_OK) { 825 return ENODEV; 826 } 827 828 ((struct root_device_softc *)dev->root->softc)->is_msi = true; 829 info->u.h0.interrupt_line = startVector; 830 return EOK; 831 } 832 833 834 int 835 pci_release_msi(device_t dev) 836 { 837 pci_info *info; 838 if (gPCIx86 == NULL) 839 return ENODEV; 840 841 info = &((struct root_device_softc *)dev->root->softc)->pci_info; 842 gPCIx86->unconfigure_msi(info->bus, info->device, info->function); 843 ((struct root_device_softc *)dev->root->softc)->is_msi = false; 844 ((struct root_device_softc *)dev->root->softc)->is_msix = false; 845 return EOK; 846 } 847 848 849 int 850 pci_msix_table_bar(device_t dev) 851 { 852 pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info; 853 854 uint8 capability_offset; 855 if (gPci->find_pci_capability(info->bus, info->device, info->function, 856 PCI_cap_id_msix, &capability_offset) != B_OK) 857 return -1; 858 859 uint32 table_value = gPci->read_pci_config(info->bus, info->device, info->function, 860 capability_offset + PCI_msix_table, 4); 861 862 uint32 bar = table_value & PCI_msix_bir_mask; 863 return PCIR_BAR(bar); 864 } 865 866 867 int 868 pci_msix_count(device_t dev) 869 { 870 pci_info *info; 871 if (gPCIx86 == NULL) 872 return 0; 873 874 info = &((struct root_device_softc *)dev->root->softc)->pci_info; 875 return gPCIx86->get_msix_count(info->bus, info->device, info->function); 876 } 877 878 879 int 880 pci_alloc_msix(device_t dev, int *count) 881 { 882 pci_info *info; 883 uint8 startVector = 0; 884 if (gPCIx86 == NULL) 885 return ENODEV; 886 887 info = &((struct root_device_softc *)dev->root->softc)->pci_info; 888 889 if (gPCIx86->configure_msix(info->bus, info->device, info->function, *count, 890 &startVector) != B_OK) { 891 return ENODEV; 892 } 893 894 ((struct root_device_softc *)dev->root->softc)->is_msix = true; 895 info->u.h0.interrupt_line = startVector; 896 return EOK; 897 } 898 899 900 int 901 pci_get_max_read_req(device_t dev) 902 { 903 int cap; 904 uint16_t val; 905 906 if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0) 907 return (0); 908 val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2); 909 val &= PCIM_EXP_CTL_MAX_READ_REQUEST; 910 val >>= 12; 911 return (1 << (val + 7)); 912 } 913 914 915 int 916 pci_set_max_read_req(device_t dev, int size) 917 { 918 int cap; 919 uint16_t val; 920 921 if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0) 922 return (0); 923 if (size < 128) 924 size = 128; 925 if (size > 4096) 926 size = 4096; 927 size = (1 << (fls(size) - 1)); 928 val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2); 929 val &= ~PCIM_EXP_CTL_MAX_READ_REQUEST; 930 val |= (fls(size) - 8) << 12; 931 pci_write_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, val, 2); 932 return (size); 933 } 934 935 936 int 937 pci_get_powerstate(device_t dev) 938 { 939 int capabilityRegister; 940 uint16 status; 941 int powerState = PCI_POWERSTATE_D0; 942 943 if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK) 944 return powerState; 945 946 status = pci_read_config(dev, capabilityRegister + PCIR_POWER_STATUS, 2); 947 switch (status & PCI_pm_mask) { 948 case PCI_pm_state_d0: 949 break; 950 case PCI_pm_state_d1: 951 powerState = PCI_POWERSTATE_D1; 952 break; 953 case PCI_pm_state_d2: 954 powerState = PCI_POWERSTATE_D2; 955 break; 956 case PCI_pm_state_d3: 957 powerState = PCI_POWERSTATE_D3; 958 break; 959 default: 960 powerState = PCI_POWERSTATE_UNKNOWN; 961 break; 962 } 963 964 TRACE_PCI(dev, "%s: D%i\n", __func__, powerState); 965 return powerState; 966 } 967 968 969 int 970 pci_set_powerstate(device_t dev, int newPowerState) 971 { 972 int capabilityRegister; 973 int oldPowerState; 974 uint8 currentPowerManagementStatus; 975 uint8 newPowerManagementStatus; 976 uint16 powerManagementCapabilities; 977 bigtime_t stateTransitionDelayInUs = 0; 978 979 if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK) 980 return EOPNOTSUPP; 981 982 oldPowerState = pci_get_powerstate(dev); 983 if (oldPowerState == newPowerState) 984 return EOK; 985 986 switch (std::max(oldPowerState, newPowerState)) { 987 case PCI_POWERSTATE_D2: 988 stateTransitionDelayInUs = 200; 989 break; 990 case PCI_POWERSTATE_D3: 991 stateTransitionDelayInUs = 10000; 992 break; 993 } 994 995 currentPowerManagementStatus = pci_read_config(dev, capabilityRegister 996 + PCIR_POWER_STATUS, 2); 997 newPowerManagementStatus = currentPowerManagementStatus & ~PCI_pm_mask; 998 powerManagementCapabilities = pci_read_config(dev, capabilityRegister 999 + PCIR_POWER_CAP, 2); 1000 1001 switch (newPowerState) { 1002 case PCI_POWERSTATE_D0: 1003 newPowerManagementStatus |= PCIM_PSTAT_D0; 1004 break; 1005 case PCI_POWERSTATE_D1: 1006 if ((powerManagementCapabilities & PCI_pm_d1supp) == 0) 1007 return EOPNOTSUPP; 1008 newPowerManagementStatus |= PCIM_PSTAT_D1; 1009 break; 1010 case PCI_POWERSTATE_D2: 1011 if ((powerManagementCapabilities & PCI_pm_d2supp) == 0) 1012 return EOPNOTSUPP; 1013 newPowerManagementStatus |= PCIM_PSTAT_D2; 1014 break; 1015 case PCI_POWERSTATE_D3: 1016 newPowerManagementStatus |= PCIM_PSTAT_D3; 1017 break; 1018 default: 1019 return EINVAL; 1020 } 1021 1022 TRACE_PCI(dev, "%s: D%i -> D%i\n", __func__, oldPowerState, newPowerState); 1023 pci_write_config(dev, capabilityRegister + PCIR_POWER_STATUS, 1024 newPowerManagementStatus, 2); 1025 if (stateTransitionDelayInUs != 0) 1026 snooze(stateTransitionDelayInUs); 1027 1028 return EOK; 1029 } 1030