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 acpi_status 87 ECAMPCIControllerACPI::AcpiCrsScanCallbackInt(acpi_resource *res) 88 { 89 uint32 outType; 90 91 switch (res->data.address.resource_type) { 92 case 0: // ACPI_MEMORY_RANGE 93 outType = kPciRangeMmio; 94 if (res->type == ACPI_RESOURCE_TYPE_ADDRESS64) 95 outType += kPciRangeMmio64Bit; 96 if (res->data.address.info.mem.caching == 3 /*ACPI_PREFETCHABLE_MEMORY*/) 97 outType += kPciRangeMmioPrefetch; 98 break; 99 case 1: // ACPI_IO_RANGE 100 outType = kPciRangeIoPort; 101 break; 102 default: 103 return B_OK; 104 } 105 106 pci_resource_range& range = fResourceRanges[outType]; 107 range.type = outType; 108 109 switch (res->type) { 110 case ACPI_RESOURCE_TYPE_ADDRESS16: { 111 const auto &address = res->data.address16.address; 112 // If address_length isn't set, compute it from minimum and maximum 113 auto address_length = address.address_length; 114 if (address_length == 0) 115 address_length = address.maximum - address.minimum + 1; 116 ASSERT(address.minimum + address_length - 1 == address.maximum); 117 range.host_addr = address.minimum + address.translation_offset; 118 range.pci_addr = address.minimum; 119 range.size = address_length; 120 break; 121 } 122 case ACPI_RESOURCE_TYPE_ADDRESS32: { 123 const auto &address = res->data.address32.address; 124 // If address_length isn't set, compute it from minimum and maximum 125 auto address_length = address.address_length; 126 if (address_length == 0) 127 address_length = address.maximum - address.minimum + 1; 128 ASSERT(address.minimum + address_length - 1 == address.maximum); 129 range.host_addr = address.minimum + address.translation_offset; 130 range.pci_addr = address.minimum; 131 range.size = address_length; 132 break; 133 } 134 case ACPI_RESOURCE_TYPE_ADDRESS64: { 135 const auto &address = res->data.address64.address; 136 // If address_length isn't set, compute it from minimum and maximum 137 auto address_length = address.address_length; 138 if (address_length == 0) 139 address_length = address.maximum - address.minimum + 1; 140 ASSERT(address.minimum + address_length - 1 == address.maximum); 141 range.host_addr = address.minimum + address.translation_offset; 142 range.pci_addr = address.minimum; 143 range.size = address_length; 144 break; 145 } 146 } 147 148 return B_OK; 149 } 150 151 152 status_t 153 ECAMPCIControllerACPI::Finalize() 154 { 155 dprintf("finalize PCI controller from ACPI\n"); 156 157 acpi_module_info *acpiModule; 158 CHECK_RET(get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule)); 159 160 IRQRoutingTable table; 161 CHECK_RET(prepare_irq_routing(acpiModule, table, [](int32 gsi) {return true;})); 162 163 CHECK_RET(enable_irq_routing(acpiModule, table)); 164 165 print_irq_routing_table(table); 166 167 return B_OK; 168 } 169