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> bool 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 104 if (addressLength == 0 && addressMaximum <= acpiRange.minimum) { 105 // There's nothing we can do with that... 106 dprintf("PCI: Ignore empty ACPI range\n"); 107 return false; 108 } else if (!resource.maxAddress_fixed) { 109 if (addressLength == 0) { 110 dprintf("PCI: maxAddress and addressLength are not set, ignore range\n"); 111 return false; 112 } 113 114 dprintf("PCI: maxAddress is not set, compute it\n"); 115 addressMaximum = acpiRange.minimum + addressLength - 1; 116 } else if (addressLength != addressMaximum - acpiRange.minimum + 1) { 117 dprintf("PCI: Fixup invalid length from ACPI!\n"); 118 addressLength = addressMaximum - acpiRange.minimum + 1; 119 } 120 121 range.host_address = acpiRange.minimum + acpiRange.translation_offset; 122 range.pci_address = acpiRange.minimum; 123 range.size = addressLength; 124 125 return true; 126 } 127 128 129 acpi_status 130 ECAMPCIControllerACPI::AcpiCrsScanCallbackInt(acpi_resource *res) 131 { 132 pci_resource_range range = {}; 133 134 switch (res->type) { 135 case ACPI_RESOURCE_TYPE_ADDRESS16: { 136 const auto& address = res->data.address16; 137 if (!DecodeAddress(address, range)) 138 return B_OK; 139 break; 140 } 141 case ACPI_RESOURCE_TYPE_ADDRESS32: { 142 const auto& address = res->data.address32; 143 if (!DecodeAddress(address, range)) 144 return B_OK; 145 range.address_type |= PCI_address_type_32; 146 break; 147 } 148 case ACPI_RESOURCE_TYPE_ADDRESS64: { 149 const auto& address = res->data.address64; 150 if (!DecodeAddress(address, range)) 151 return B_OK; 152 range.address_type |= PCI_address_type_64; 153 break; 154 } 155 156 default: 157 return B_OK; 158 } 159 160 switch (res->data.address.resource_type) { 161 case 0: // ACPI_MEMORY_RANGE 162 range.type = B_IO_MEMORY; 163 if (res->data.address.info.mem.caching == 3 /*ACPI_PREFETCHABLE_MEMORY*/) 164 range.address_type |= PCI_address_prefetchable; 165 break; 166 case 1: // ACPI_IO_RANGE 167 range.type = B_IO_PORT; 168 break; 169 170 default: 171 return B_OK; 172 } 173 174 fResourceRanges.Add(range); 175 return B_OK; 176 } 177 178 179 status_t 180 ECAMPCIControllerACPI::Finalize() 181 { 182 dprintf("finalize PCI controller from ACPI\n"); 183 184 acpi_module_info *acpiModule; 185 CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule)); 186 187 IRQRoutingTable table; 188 CHECK_RET(prepare_irq_routing(acpiModule, table, [](int32 gsi) {return true;})); 189 190 CHECK_RET(enable_irq_routing(acpiModule, table)); 191 192 print_irq_routing_table(table); 193 194 return B_OK; 195 } 196