1 /* 2 * Copyright 2022, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ECAMPCIController.h" 8 #include <acpi.h> 9 10 #include <AutoDeleterDrivers.h> 11 12 #include "acpi_irq_routing_table.h" 13 14 #include <string.h> 15 16 17 status_t 18 ECAMPCIControllerACPI::ReadResourceInfo() 19 { 20 DeviceNodePutter<&gDeviceManager> parent(gDeviceManager->get_parent_node(fNode)); 21 22 dprintf("initialize PCI controller from ACPI\n"); 23 24 acpi_module_info* acpiModule; 25 acpi_device_module_info* acpiDeviceModule; 26 acpi_device acpiDevice; 27 28 CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule)); 29 30 acpi_mcfg *mcfg; 31 CHECK_RET(acpiModule->get_table(ACPI_MCFG_SIGNATURE, 0, (void**)&mcfg)); 32 33 CHECK_RET(gDeviceManager->get_driver(parent.Get(), (driver_module_info**)&acpiDeviceModule, 34 (void**)&acpiDevice)); 35 36 acpi_status acpi_res = acpiDeviceModule->walk_resources(acpiDevice, (char *)"_CRS", 37 AcpiCrsScanCallback, this); 38 39 if (acpi_res != 0) 40 return B_ERROR; 41 42 acpi_mcfg_allocation *end = (acpi_mcfg_allocation *) ((char*)mcfg + mcfg->header.length); 43 acpi_mcfg_allocation *alloc = (acpi_mcfg_allocation *) (mcfg + 1); 44 45 if (alloc + 1 != end) 46 dprintf("PCI: multiple host bridges not supported!"); 47 48 for (; alloc < end; alloc++) { 49 dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: %x, end: %x\n", 50 alloc->address, alloc->pci_segment, alloc->start_bus_number, alloc->end_bus_number); 51 52 if (alloc->pci_segment != 0) { 53 dprintf("PCI: multiple segments not supported!"); 54 continue; 55 } 56 57 uint8 startBusNumber = alloc->start_bus_number; 58 uint8 endBusNumber = alloc->end_bus_number; 59 60 fRegsArea.SetTo(map_physical_memory("PCI Config MMIO", 61 alloc->address, (endBusNumber - startBusNumber + 1) << 20, B_ANY_KERNEL_ADDRESS, 62 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&fRegs)); 63 CHECK_RET(fRegsArea.Get()); 64 65 return B_OK; 66 } 67 68 return B_ERROR; 69 } 70 71 72 acpi_status 73 ECAMPCIControllerACPI::AcpiCrsScanCallback(acpi_resource *res, void *context) 74 { 75 return static_cast<ECAMPCIControllerACPI*>(context)->AcpiCrsScanCallbackInt(res); 76 } 77 78 79 acpi_status 80 ECAMPCIControllerACPI::AcpiCrsScanCallbackInt(acpi_resource *res) 81 { 82 uint32 outType; 83 84 switch (res->data.address.resource_type) { 85 case 0: // ACPI_MEMORY_RANGE 86 outType = kPciRangeMmio; 87 if (res->type == ACPI_RESOURCE_TYPE_ADDRESS64) 88 outType += kPciRangeMmio64Bit; 89 if (res->data.address.info.mem.caching == 3 /*ACPI_PREFETCHABLE_MEMORY*/) 90 outType += kPciRangeMmioPrefetch; 91 break; 92 case 1: // ACPI_IO_RANGE 93 outType = kPciRangeIoPort; 94 break; 95 default: 96 return B_OK; 97 } 98 99 pci_resource_range& range = fResourceRanges[outType]; 100 range.type = outType; 101 102 switch (res->type) { 103 case ACPI_RESOURCE_TYPE_ADDRESS16: { 104 const auto &address = res->data.address16.address; 105 range.host_addr = address.minimum + address.translation_offset; 106 range.pci_addr = address.minimum; 107 range.size = address.address_length; 108 break; 109 } 110 case ACPI_RESOURCE_TYPE_ADDRESS32: { 111 const auto &address = res->data.address32.address; 112 range.host_addr = address.minimum + address.translation_offset; 113 range.pci_addr = address.minimum; 114 range.size = address.address_length; 115 break; 116 } 117 case ACPI_RESOURCE_TYPE_ADDRESS64: { 118 const auto &address = res->data.address64.address; 119 range.host_addr = address.minimum + address.translation_offset; 120 range.pci_addr = address.minimum; 121 range.size = address.address_length; 122 break; 123 } 124 } 125 126 return B_OK; 127 } 128 129 130 status_t 131 ECAMPCIControllerACPI::Finalize() 132 { 133 dprintf("finalize PCI controller from ACPI\n"); 134 135 acpi_module_info *acpiModule; 136 CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule)); 137 138 IRQRoutingTable table; 139 CHECK_RET(prepare_irq_routing(acpiModule, table, [](int32 gsi) {return true;})); 140 141 CHECK_RET(enable_irq_routing(acpiModule, table)); 142 143 print_irq_routing_table(table); 144 145 return B_OK; 146 } 147