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
ReadResourceInfo()18 ECAMPCIControllerACPI::ReadResourceInfo()
19 {
20 DeviceNodePutter<&gDeviceManager> parent(gDeviceManager->get_parent_node(fNode));
21 return ReadResourceInfo(parent.Get());
22 }
23
24
25 status_t
ReadResourceInfo(device_node * parent)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 = (uint64(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
AcpiCrsScanCallback(acpi_resource * res,void * context)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
DecodeAddress(const T & resource,pci_resource_range & range)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
AcpiCrsScanCallbackInt(acpi_resource * res)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
Finalize()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