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