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 return ReadResourceInfo(parent.Get()); 22 } 23 24 25 status_t 26 ECAMPCIControllerACPI::ReadResourceInfo(device_node* parent) 27 { 28 dprintf("initialize PCI controller from ACPI\n"); 29 30 acpi_module_info* acpiModule; 31 acpi_device_module_info* acpiDeviceModule; 32 acpi_device acpiDevice; 33 34 CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule)); 35 36 acpi_mcfg *mcfg; 37 CHECK_RET(acpiModule->get_table(ACPI_MCFG_SIGNATURE, 0, (void**)&mcfg)); 38 39 CHECK_RET(gDeviceManager->get_driver(parent, (driver_module_info**)&acpiDeviceModule, 40 (void**)&acpiDevice)); 41 42 acpi_status acpi_res = acpiDeviceModule->walk_resources(acpiDevice, (char *)"_CRS", 43 AcpiCrsScanCallback, this); 44 45 if (acpi_res != 0) 46 return B_ERROR; 47 48 acpi_mcfg_allocation *end = (acpi_mcfg_allocation *) ((char*)mcfg + mcfg->header.length); 49 acpi_mcfg_allocation *alloc = (acpi_mcfg_allocation *) (mcfg + 1); 50 51 if (alloc + 1 != end) 52 dprintf("PCI: multiple host bridges not supported!"); 53 54 for (; alloc < end; alloc++) { 55 dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: %x, end: %x\n", 56 alloc->address, alloc->pci_segment, alloc->start_bus_number, alloc->end_bus_number); 57 58 if (alloc->pci_segment != 0) { 59 dprintf("PCI: multiple segments not supported!"); 60 continue; 61 } 62 63 fStartBusNumber = alloc->start_bus_number; 64 fEndBusNumber = alloc->end_bus_number; 65 66 fRegsLen = (fEndBusNumber - fStartBusNumber + 1) << 20; 67 fRegsArea.SetTo(map_physical_memory("PCI Config MMIO", 68 alloc->address, fRegsLen, B_ANY_KERNEL_ADDRESS, 69 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&fRegs)); 70 CHECK_RET(fRegsArea.Get()); 71 72 return B_OK; 73 } 74 75 return B_ERROR; 76 } 77 78 79 acpi_status 80 ECAMPCIControllerACPI::AcpiCrsScanCallback(acpi_resource *res, void *context) 81 { 82 return static_cast<ECAMPCIControllerACPI*>(context)->AcpiCrsScanCallbackInt(res); 83 } 84 85 86 /** Convert an ACPI address resource descriptor into a pci_resource_range. 87 * 88 * This is a template because ACPI resources can be encoded using 8, 16, 32 or 64 bit values. 89 */ 90 template<typename T> void 91 DecodeAddress(const T& resource, pci_resource_range& range) 92 { 93 const auto& acpiRange = resource.address; 94 dprintf("PCI: range from ACPI [%lx(%d),%lx(%d)] with length %lx\n", 95 (unsigned long)acpiRange.minimum, resource.minAddress_fixed, 96 (unsigned long)acpiRange.maximum, resource.maxAddress_fixed, 97 (unsigned long)acpiRange.address_length); 98 99 // If address_length isn't set, compute it from minimum and maximum 100 // If maximum isn't set, compute it from minimum and length 101 auto addressLength = acpiRange.address_length; 102 phys_addr_t addressMaximum = acpiRange.maximum; 103 if (addressLength == 0) 104 addressLength = acpiRange.maximum - acpiRange.minimum + 1; 105 else if (!resource.maxAddress_fixed) 106 addressMaximum = acpiRange.minimum + addressLength - 1; 107 ASSERT((phys_addr_t)(acpiRange.minimum + addressLength - 1) == addressMaximum); 108 109 range.host_address = acpiRange.minimum + acpiRange.translation_offset; 110 range.pci_address = acpiRange.minimum; 111 range.size = addressLength; 112 } 113 114 115 acpi_status 116 ECAMPCIControllerACPI::AcpiCrsScanCallbackInt(acpi_resource *res) 117 { 118 pci_resource_range range = {}; 119 120 switch (res->type) { 121 case ACPI_RESOURCE_TYPE_ADDRESS16: { 122 const auto& address = res->data.address16; 123 DecodeAddress(address, range); 124 break; 125 } 126 case ACPI_RESOURCE_TYPE_ADDRESS32: { 127 const auto& address = res->data.address32; 128 DecodeAddress(address, range); 129 range.address_type |= PCI_address_type_32; 130 break; 131 } 132 case ACPI_RESOURCE_TYPE_ADDRESS64: { 133 const auto& address = res->data.address64; 134 DecodeAddress(address, range); 135 range.address_type |= PCI_address_type_64; 136 break; 137 } 138 139 default: 140 return B_OK; 141 } 142 143 switch (res->data.address.resource_type) { 144 case 0: // ACPI_MEMORY_RANGE 145 range.type = B_IO_MEMORY; 146 if (res->data.address.info.mem.caching == 3 /*ACPI_PREFETCHABLE_MEMORY*/) 147 range.address_type |= PCI_address_prefetchable; 148 break; 149 case 1: // ACPI_IO_RANGE 150 range.type = B_IO_PORT; 151 break; 152 153 default: 154 return B_OK; 155 } 156 157 fResourceRanges.Add(range); 158 return B_OK; 159 } 160 161 162 status_t 163 ECAMPCIControllerACPI::Finalize() 164 { 165 dprintf("finalize PCI controller from ACPI\n"); 166 167 acpi_module_info *acpiModule; 168 CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule)); 169 170 IRQRoutingTable table; 171 CHECK_RET(prepare_irq_routing(acpiModule, table, [](int32 gsi) {return true;})); 172 173 CHECK_RET(enable_irq_routing(acpiModule, table)); 174 175 print_irq_routing_table(table); 176 177 return B_OK; 178 } 179