1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <acpica/acpi.h>
6 #include <ddk/debug.h>
7 #include <ddk/protocol/auxdata.h>
8 #include <ddk/protocol/pciroot.h>
9 #include <pci/pio.h>
10 #include <zircon/hw/i2c.h>
11 #include <zircon/types.h>
12
13 #include "acpi-private.h"
14 #include "dev.h"
15 #include "errors.h"
16 #include "iommu.h"
17 #include "pci.h"
18 #include "pciroot.h"
19
find_pci_child_callback(ACPI_HANDLE object,uint32_t nesting_level,void * context,void ** out_value)20 static ACPI_STATUS find_pci_child_callback(ACPI_HANDLE object, uint32_t nesting_level,
21 void* context, void** out_value) {
22 ACPI_DEVICE_INFO* info;
23 ACPI_STATUS acpi_status = AcpiGetObjectInfo(object, &info);
24 if (acpi_status != AE_OK) {
25 zxlogf(TRACE, "bus-acpi: AcpiGetObjectInfo failed %d\n", acpi_status);
26 return acpi_status;
27 }
28 ACPI_FREE(info);
29 ACPI_OBJECT obj = {
30 .Type = ACPI_TYPE_INTEGER,
31 };
32 ACPI_BUFFER buffer = {
33 .Length = sizeof(obj),
34 .Pointer = &obj,
35 };
36 acpi_status = AcpiEvaluateObject(object, (char*)"_ADR", NULL, &buffer);
37 if (acpi_status != AE_OK) {
38 return AE_OK;
39 }
40 uint32_t addr = *(uint32_t*)context;
41 ACPI_HANDLE* out_handle = (ACPI_HANDLE*)out_value;
42 if (addr == obj.Integer.Value) {
43 *out_handle = object;
44 return AE_CTRL_TERMINATE;
45 } else {
46 return AE_OK;
47 }
48 }
49
pci_child_data_resources_callback(ACPI_RESOURCE * res,void * context)50 static ACPI_STATUS pci_child_data_resources_callback(ACPI_RESOURCE* res, void* context) {
51 pci_child_auxdata_ctx_t* ctx = (pci_child_auxdata_ctx_t*)context;
52 auxdata_i2c_device_t* child = ctx->data + ctx->i;
53
54 if (res->Type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
55 return AE_NOT_FOUND;
56 }
57 if (res->Data.I2cSerialBus.Type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
58 return AE_NOT_FOUND;
59 }
60
61 ACPI_RESOURCE_I2C_SERIALBUS* i2c = &res->Data.I2cSerialBus;
62 child->bus_master = i2c->SlaveMode;
63 child->ten_bit = i2c->AccessMode;
64 child->address = i2c->SlaveAddress;
65 child->bus_speed = i2c->ConnectionSpeed;
66
67 return AE_CTRL_TERMINATE;
68 }
69
pci_child_data_callback(ACPI_HANDLE object,uint32_t nesting_level,void * context,void ** out_value)70 static ACPI_STATUS pci_child_data_callback(ACPI_HANDLE object,
71 uint32_t nesting_level,
72 void* context, void** out_value) {
73 pci_child_auxdata_ctx_t* ctx = (pci_child_auxdata_ctx_t*)context;
74 if ((ctx->i + 1) > ctx->max) {
75 return AE_CTRL_TERMINATE;
76 }
77
78 auxdata_i2c_device_t* data = ctx->data + ctx->i;
79 data->protocol_id = ZX_PROTOCOL_I2C;
80
81 ACPI_DEVICE_INFO* info = NULL;
82 ACPI_STATUS acpi_status = AcpiGetObjectInfo(object, &info);
83 if (acpi_status == AE_OK) {
84 // These length fields count the trailing NUL.
85 // Publish HID
86 if ((info->Valid & ACPI_VALID_HID) && info->HardwareId.Length <= HID_LENGTH + 1) {
87 const char* hid = info->HardwareId.String;
88 data->props[data->propcount].id = BIND_ACPI_HID_0_3;
89 data->props[data->propcount++].value = htobe32(*((uint32_t*)(hid)));
90 data->props[data->propcount].id = BIND_ACPI_HID_4_7;
91 data->props[data->propcount++].value = htobe32(*((uint32_t*)(hid + 4)));
92 }
93 // Check for I2C HID devices via CID
94 if ((info->Valid & ACPI_VALID_CID) && info->CompatibleIdList.Count > 0) {
95 ACPI_PNP_DEVICE_ID* cid = &info->CompatibleIdList.Ids[0];
96 if (cid->Length <= CID_LENGTH + 1) {
97 if (!strncmp(cid->String, I2C_HID_CID_STRING, CID_LENGTH)) {
98 data->props[data->propcount].id = BIND_I2C_CLASS;
99 data->props[data->propcount++].value = I2C_CLASS_HID;
100 }
101 data->props[data->propcount].id = BIND_ACPI_CID_0_3;
102 data->props[data->propcount++].value = htobe32(*((uint32_t*)(cid->String)));
103 data->props[data->propcount].id = BIND_ACPI_CID_4_7;
104 data->props[data->propcount++].value = htobe32(*((uint32_t*)(cid->String + 4)));
105 }
106 }
107 ACPI_FREE(info);
108 }
109 ZX_ASSERT(data->propcount <= AUXDATA_MAX_DEVPROPS);
110
111 // call _CRS to get i2c info
112 acpi_status = AcpiWalkResources(object, (char*)"_CRS",
113 pci_child_data_resources_callback, ctx);
114 if ((acpi_status == AE_OK) || (acpi_status == AE_CTRL_TERMINATE)) {
115 ctx->i++;
116 }
117 return AE_OK;
118 }
119
pciroot_op_get_auxdata(void * context,const char * args,void * data,size_t bytes,size_t * actual)120 static zx_status_t pciroot_op_get_auxdata(void* context, const char* args,
121 void* data, size_t bytes,
122 size_t* actual) {
123 acpi_device_t* dev = (acpi_device_t*)context;
124
125 char type[16];
126 uint32_t bus_id, dev_id, func_id;
127 int n;
128 if ((n = sscanf(args, "%[^,],%02x:%02x:%02x", type, &bus_id, &dev_id, &func_id)) != 4) {
129 return ZX_ERR_INVALID_ARGS;
130 }
131
132 zxlogf(SPEW, "bus-acpi: get_auxdata type '%s' device %02x:%02x:%02x\n", type,
133 bus_id, dev_id, func_id);
134
135 if (strcmp(type, "i2c-child")) {
136 return ZX_ERR_NOT_SUPPORTED;
137 }
138
139 if (bytes < (2 * sizeof(uint32_t))) {
140 return ZX_ERR_BUFFER_TOO_SMALL;
141 }
142
143 ACPI_HANDLE pci_node = NULL;
144 uint32_t addr = (dev_id << 16) | func_id;
145
146 // Look for the child node with this device and function id
147 ACPI_STATUS acpi_status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, dev->ns_node, 1,
148 find_pci_child_callback, NULL,
149 &addr, &pci_node);
150 if ((acpi_status != AE_OK) && (acpi_status != AE_CTRL_TERMINATE)) {
151 return acpi_to_zx_status(acpi_status);
152 }
153 if (pci_node == NULL) {
154 return ZX_ERR_NOT_FOUND;
155 }
156
157 memset(data, 0, bytes);
158
159 // Look for as many children as can fit in the provided buffer
160 pci_child_auxdata_ctx_t ctx = {
161 .max = static_cast<uint8_t>(bytes / sizeof(auxdata_i2c_device_t)),
162 .i = 0,
163 .data = static_cast<auxdata_i2c_device_t*>(data),
164 };
165
166 acpi_status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, pci_node, 1,
167 pci_child_data_callback, NULL, &ctx, NULL);
168 if ((acpi_status != AE_OK) && (acpi_status != AE_CTRL_TERMINATE)) {
169 *actual = 0;
170 return acpi_to_zx_status(acpi_status);
171 }
172
173 *actual = ctx.i * sizeof(auxdata_i2c_device_t);
174
175 zxlogf(SPEW, "bus-acpi: get_auxdata '%s' %u devs actual %zu\n",
176 args, ctx.i, *actual);
177
178 return ZX_OK;
179 }
180
pciroot_op_get_bti(void * context,uint32_t bdf,uint32_t index,zx_handle_t * bti)181 static zx_status_t pciroot_op_get_bti(void* context, uint32_t bdf, uint32_t index,
182 zx_handle_t* bti) {
183 // The x86 IOMMU world uses PCI BDFs as the hardware identifiers, so there
184 // will only be one BTI per device.
185 if (index != 0) {
186 return ZX_ERR_OUT_OF_RANGE;
187 }
188 // For dummy IOMMUs, the bti_id just needs to be unique. For Intel IOMMUs,
189 // the bti_ids correspond to PCI BDFs.
190 zx_handle_t iommu_handle;
191 zx_status_t status = iommu_manager_iommu_for_bdf(bdf, &iommu_handle);
192 if (status != ZX_OK) {
193 return status;
194 }
195 return zx_bti_create(iommu_handle, 0, bdf, bti);
196 }
197
198 #ifdef ENABLE_USER_PCI
pciroot_op_get_pci_platform_info(void * ctx,pci_platform_info_t * info)199 static zx_status_t pciroot_op_get_pci_platform_info(void* ctx, pci_platform_info_t* info) {
200 pciroot_ctx_t* pciroot = static_cast<pciroot_ctx_t*>(ctx);
201 *info = pciroot->info;
202 return ZX_OK;
203 }
204
pciroot_op_get_pci_irq_info(void * ctx,pci_irq_info_t * info)205 static zx_status_t pciroot_op_get_pci_irq_info(void* ctx, pci_irq_info_t* info) {
206 return ZX_ERR_NOT_SUPPORTED;
207 }
208
pciroot_op_driver_should_proxy_config(void * ctx)209 static bool pciroot_op_driver_should_proxy_config(void* ctx) {
210 // If we have no mcfg then all config access will need to be through IOports which
211 // are proxied over pciroot.
212 return !pci_platform_has_mcfg();
213 }
214
215 // For ACPI systems we only intend to use PIO access if MMIO config is unavailable. In the event we
216 // do use them though, we're restricted to the base 256 byte PCI config header.
pciroot_op_config_read8(void * ctx,const pci_bdf_t * address,uint16_t offset,uint8_t * value)217 static zx_status_t pciroot_op_config_read8(void* ctx, const pci_bdf_t* address, uint16_t offset, uint8_t* value) {
218 return pci_pio_read8(*address, static_cast<uint8_t>(offset), value);
219 }
220
pciroot_op_config_read16(void * ctx,const pci_bdf_t * address,uint16_t offset,uint16_t * value)221 static zx_status_t pciroot_op_config_read16(void* ctx,
222 const pci_bdf_t* address,
223 uint16_t offset,
224 uint16_t* value) {
225 return pci_pio_read16(*address, static_cast<uint8_t>(offset), value);
226 }
227
pciroot_op_config_read32(void * ctx,const pci_bdf_t * address,uint16_t offset,uint32_t * value)228 static zx_status_t pciroot_op_config_read32(void* ctx,
229 const pci_bdf_t* address,
230 uint16_t offset,
231 uint32_t* value) {
232 return pci_pio_read32(*address, static_cast<uint8_t>(offset), value);
233 }
234
pciroot_op_config_write8(void * ctx,const pci_bdf_t * address,uint16_t offset,uint8_t value)235 static zx_status_t pciroot_op_config_write8(void* ctx,
236 const pci_bdf_t* address,
237 uint16_t offset,
238 uint8_t value) {
239 return pci_pio_write8(*address, static_cast<uint8_t>(offset), value);
240 }
241
pciroot_op_config_write16(void * ctx,const pci_bdf_t * address,uint16_t offset,uint16_t value)242 static zx_status_t pciroot_op_config_write16(void* ctx,
243 const pci_bdf_t* address,
244 uint16_t offset,
245 uint16_t value) {
246 return pci_pio_write16(*address, static_cast<uint8_t>(offset), value);
247 }
248
pciroot_op_config_write32(void * ctx,const pci_bdf_t * address,uint16_t offset,uint32_t value)249 static zx_status_t pciroot_op_config_write32(void* ctx,
250 const pci_bdf_t* address,
251 uint16_t offset,
252 uint32_t value) {
253 return pci_pio_write32(*address, static_cast<uint8_t>(offset), value);
254 }
255
256 // These methods may not exist in usable implementations and are a prototyping side effect. It
257 // likely will not make sense for MSI blocks to be dealt with in the PCI driver itself if we can
258 // help it.
pciroot_op_msi_alloc_block(void * ctx,uint64_t requested_irqs,bool can_target_64bit,msi_block_t * out_block)259 static zx_status_t pciroot_op_msi_alloc_block(void* ctx,
260 uint64_t requested_irqs,
261 bool can_target_64bit,
262 msi_block_t* out_block) {
263 return ZX_ERR_NOT_SUPPORTED;
264 }
265
pciroot_op_msi_free_block(void * ctx,const msi_block_t * block)266 static zx_status_t pciroot_op_msi_free_block(void* ctx,
267 const msi_block_t* block) {
268 return ZX_ERR_NOT_SUPPORTED;
269 }
270
pciroot_op_msi_mask_unmask(void * ctx,uint64_t msi_id,bool mask)271 static zx_status_t pciroot_op_msi_mask_unmask(void* ctx,
272 uint64_t msi_id,
273 bool mask) {
274 return ZX_ERR_NOT_SUPPORTED;
275 }
276
pciroot_op_get_address_space(void * ctx,size_t len,pci_address_space_t type,bool low,uint64_t * out_base)277 static zx_status_t pciroot_op_get_address_space(void* ctx,
278 size_t len,
279 pci_address_space_t type,
280 bool low,
281 uint64_t* out_base) {
282 return ZX_ERR_NOT_SUPPORTED;
283 }
284
pciroot_op_free_address_space(void * ctx,uint64_t base,size_t len,pci_address_space_t type)285 static zx_status_t pciroot_op_free_address_space(void* ctx,
286 uint64_t base,
287 size_t len,
288 pci_address_space_t type) {
289 return ZX_ERR_NOT_SUPPORTED;
290 }
291
292 #else // TODO(cja): remove after the switch to userspace pci
pciroot_op_get_pci_platform_info(void *,pci_platform_info_t *)293 static zx_status_t pciroot_op_get_pci_platform_info(void*, pci_platform_info_t*) {
294 return ZX_ERR_NOT_SUPPORTED;
295 }
296
pciroot_op_get_pci_irq_info(void *,pci_irq_info_t *)297 static zx_status_t pciroot_op_get_pci_irq_info(void*, pci_irq_info_t*) {
298 return ZX_ERR_NOT_SUPPORTED;
299 }
300
pciroot_op_driver_should_proxy_config(void * ctx)301 static bool pciroot_op_driver_should_proxy_config(void* ctx) {
302 return false;
303 }
304
pciroot_op_config_read8(void *,const pci_bdf_t *,uint16_t,uint8_t *)305 static zx_status_t pciroot_op_config_read8(void*, const pci_bdf_t*, uint16_t, uint8_t*) {
306 return ZX_ERR_NOT_SUPPORTED;
307 }
308
pciroot_op_config_read16(void *,const pci_bdf_t *,uint16_t,uint16_t *)309 static zx_status_t pciroot_op_config_read16(void*, const pci_bdf_t*, uint16_t, uint16_t*) {
310 return ZX_ERR_NOT_SUPPORTED;
311 }
312
pciroot_op_config_read32(void *,const pci_bdf_t *,uint16_t,uint32_t *)313 static zx_status_t pciroot_op_config_read32(void*, const pci_bdf_t*, uint16_t, uint32_t*) {
314 return ZX_ERR_NOT_SUPPORTED;
315 }
316
pciroot_op_config_write8(void *,const pci_bdf_t *,uint16_t,uint8_t)317 static zx_status_t pciroot_op_config_write8(void*, const pci_bdf_t*, uint16_t, uint8_t) {
318 return ZX_ERR_NOT_SUPPORTED;
319 }
320
pciroot_op_config_write16(void *,const pci_bdf_t *,uint16_t,uint16_t)321 static zx_status_t pciroot_op_config_write16(void*, const pci_bdf_t*, uint16_t, uint16_t) {
322 return ZX_ERR_NOT_SUPPORTED;
323 }
324
pciroot_op_config_write32(void *,const pci_bdf_t *,uint16_t,uint32_t)325 static zx_status_t pciroot_op_config_write32(void*, const pci_bdf_t*, uint16_t, uint32_t) {
326 return ZX_ERR_NOT_SUPPORTED;
327 }
328
pciroot_op_msi_alloc_block(void *,uint64_t,bool,msi_block_t *)329 static zx_status_t pciroot_op_msi_alloc_block(void*, uint64_t, bool, msi_block_t*) {
330 return ZX_ERR_NOT_SUPPORTED;
331 }
332
pciroot_op_msi_free_block(void *,const msi_block_t *)333 static zx_status_t pciroot_op_msi_free_block(void*, const msi_block_t*) {
334 return ZX_ERR_NOT_SUPPORTED;
335 }
336
pciroot_op_msi_mask_unmask(void *,uint64_t,bool)337 static zx_status_t pciroot_op_msi_mask_unmask(void*, uint64_t, bool) {
338 return ZX_ERR_NOT_SUPPORTED;
339 }
340
pciroot_op_get_address_space(void *,size_t,pci_address_space_t,bool,uint64_t *)341 static zx_status_t pciroot_op_get_address_space(void*, size_t, pci_address_space_t, bool, uint64_t*) {
342 return ZX_ERR_NOT_SUPPORTED;
343 }
344
pciroot_op_free_address_space(void *,uint64_t,size_t,pci_address_space_t)345 static zx_status_t pciroot_op_free_address_space(void*, uint64_t, size_t, pci_address_space_t) {
346 return ZX_ERR_NOT_SUPPORTED;
347 }
348 #endif // ENABLE_USER_PCI
349
350 static pciroot_protocol_ops_t pciroot_proto = {
351 .get_auxdata = pciroot_op_get_auxdata,
352 .get_bti = pciroot_op_get_bti,
353 .get_pci_platform_info = pciroot_op_get_pci_platform_info,
354 .get_pci_irq_info = pciroot_op_get_pci_irq_info,
355 .driver_should_proxy_config = pciroot_op_driver_should_proxy_config,
356 .config_read8 = pciroot_op_config_read8,
357 .config_read16 = pciroot_op_config_read16,
358 .config_read32 = pciroot_op_config_read32,
359 .config_write8 = pciroot_op_config_write8,
360 .config_write16 = pciroot_op_config_write16,
361 .config_write32 = pciroot_op_config_write32,
362 .msi_alloc_block = pciroot_op_msi_alloc_block,
363 .msi_free_block = pciroot_op_msi_free_block,
364 .msi_mask_unmask = pciroot_op_msi_mask_unmask,
365 .get_address_space = pciroot_op_get_address_space,
366 .free_address_space = pciroot_op_free_address_space,
367 };
368
get_pciroot_ops(void)369 pciroot_protocol_ops_t* get_pciroot_ops(void) {
370 return &pciroot_proto;
371 }
372