1// Copyright 2017 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 <ddk/binding.h>
6#include <ddk/device.h>
7#include <ddk/driver.h>
8#include <ddk/debug.h>
9#include <ddk/metadata.h>
10#include <ddk/protocol/acpi.h>
11#include <ddk/protocol/pciroot.h>
12
13#include <inttypes.h>
14#include <limits.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <stdint.h>
18#include <string.h>
19#include <sys/stat.h>
20#include <threads.h>
21
22#include <acpica/acpi.h>
23#include <zircon/compiler.h>
24#include <zircon/process.h>
25#include <zircon/syscalls/iommu.h>
26
27#include "acpi-private.h"
28#include "cpu-trace.h"
29#include "dev.h"
30#include "errors.h"
31#include "init.h"
32#include "iommu.h"
33#include "methods.h"
34#include "nhlt.h"
35#include "pci.h"
36#include "pciroot.h"
37#include "power.h"
38#include "resources.h"
39
40
41zx_handle_t root_resource_handle;
42
43static zx_device_t* publish_device(zx_device_t* parent, ACPI_HANDLE handle,
44                                   ACPI_DEVICE_INFO* info, const char* name,
45                                   uint32_t protocol_id, void* protocol_ops);
46
47static void acpi_device_release(void* ctx) {
48    acpi_device_t* dev = (acpi_device_t*)ctx;
49    free(dev);
50}
51
52static zx_protocol_device_t acpi_device_proto = {
53    .version = DEVICE_OPS_VERSION,
54    .release = acpi_device_release,
55};
56
57typedef struct {
58    acpi_device_resource_t* resources;
59    size_t resource_count;
60    size_t resource_i;
61
62    acpi_device_irq_t* irqs;
63    size_t irq_count;
64    size_t irq_i;
65} acpi_crs_ctx_t;
66
67static ACPI_STATUS report_current_resources_resource_cb(ACPI_RESOURCE* res, void* _ctx) {
68    acpi_crs_ctx_t* ctx = (acpi_crs_ctx_t*)_ctx;
69
70    if (resource_is_memory(res)) {
71        resource_memory_t mem;
72        zx_status_t st = resource_parse_memory(res, &mem);
73        // only expect fixed memory resource. resource_parse_memory sets minimum == maximum
74        // for this memory resource type.
75        if ((st != ZX_OK) || (mem.minimum != mem.maximum)) {
76            return AE_ERROR;
77        }
78
79        ctx->resources[ctx->resource_i].writeable = mem.writeable;
80        ctx->resources[ctx->resource_i].base_address = mem.minimum;
81        ctx->resources[ctx->resource_i].alignment = mem.alignment;
82        ctx->resources[ctx->resource_i].address_length = mem.address_length;
83
84        ctx->resource_i += 1;
85
86    } else if (resource_is_address(res)) {
87        resource_address_t addr;
88        zx_status_t st = resource_parse_address(res, &addr);
89        if (st != ZX_OK) {
90            return AE_ERROR;
91        }
92        if ((addr.resource_type == RESOURCE_ADDRESS_MEMORY) && addr.min_address_fixed &&
93            addr.max_address_fixed && (addr.maximum < addr.minimum)) {
94
95            ctx->resources[ctx->resource_i].writeable = true;
96            ctx->resources[ctx->resource_i].base_address = addr.min_address_fixed;
97            ctx->resources[ctx->resource_i].alignment = 0;
98            ctx->resources[ctx->resource_i].address_length = addr.address_length;
99
100            ctx->resource_i += 1;
101        }
102
103    } else if (resource_is_irq(res)) {
104        resource_irq_t irq;
105        zx_status_t st = resource_parse_irq(res, &irq);
106        if (st != ZX_OK) {
107            return AE_ERROR;
108        }
109        for (size_t i = 0; i < irq.pin_count; i++) {
110            ctx->irqs[ctx->irq_i].trigger = irq.trigger;
111            ctx->irqs[ctx->irq_i].polarity = irq.polarity;
112            ctx->irqs[ctx->irq_i].sharable = irq.sharable;
113            ctx->irqs[ctx->irq_i].wake_capable = irq.wake_capable;
114            ctx->irqs[ctx->irq_i].pin = irq.pins[i];
115
116            ctx->irq_i += 1;
117        }
118    }
119
120    return AE_OK;
121}
122
123static ACPI_STATUS report_current_resources_count_cb(ACPI_RESOURCE* res, void* _ctx) {
124    acpi_crs_ctx_t* ctx = (acpi_crs_ctx_t*)_ctx;
125
126    if (resource_is_memory(res)) {
127        resource_memory_t mem;
128        zx_status_t st = resource_parse_memory(res, &mem);
129        if ((st != ZX_OK) || (mem.minimum != mem.maximum)) {
130            return AE_ERROR;
131        }
132        ctx->resource_count += 1;
133
134    } else if (resource_is_address(res)) {
135        resource_address_t addr;
136        zx_status_t st = resource_parse_address(res, &addr);
137        if (st != ZX_OK) {
138            return AE_ERROR;
139        }
140        if ((addr.resource_type == RESOURCE_ADDRESS_MEMORY) && addr.min_address_fixed &&
141            addr.max_address_fixed && (addr.maximum < addr.minimum)) {
142            ctx->resource_count += 1;
143        }
144
145    } else if (resource_is_irq(res)) {
146        ctx->irq_count += res->Data.Irq.InterruptCount;
147    }
148
149    return AE_OK;
150}
151
152static zx_status_t report_current_resources(acpi_device_t* dev) {
153    acpi_crs_ctx_t ctx;
154    memset(&ctx, 0, sizeof(ctx));
155
156    if (dev->got_resources) {
157        return ZX_OK;
158    }
159
160    // call _CRS to count number of resources
161    ACPI_STATUS acpi_status = AcpiWalkResources(dev->ns_node, (char*)"_CRS",
162            report_current_resources_count_cb, &ctx);
163    if ((acpi_status != AE_NOT_FOUND) && (acpi_status != AE_OK)) {
164        return acpi_to_zx_status(acpi_status);
165    }
166
167    if (ctx.resource_count == 0) {
168        return ZX_OK;
169    }
170
171    // allocate resources
172    ctx.resources = calloc(ctx.resource_count, sizeof(acpi_device_resource_t));
173    if (!ctx.resources) {
174        return ZX_ERR_NO_MEMORY;
175    }
176    ctx.irqs = calloc(ctx.irq_count, sizeof(acpi_device_irq_t));
177    if (!ctx.irqs) {
178        free(ctx.resources);
179        return ZX_ERR_NO_MEMORY;
180    }
181
182    // call _CRS again and fill in resources
183    acpi_status = AcpiWalkResources(dev->ns_node, (char*)"_CRS",
184            report_current_resources_resource_cb, &ctx);
185    if ((acpi_status != AE_NOT_FOUND) && (acpi_status != AE_OK)) {
186        free(ctx.resources);
187        free(ctx.irqs);
188        return acpi_to_zx_status(acpi_status);
189    }
190
191    dev->resources = ctx.resources;
192    dev->resource_count = ctx.resource_count;
193    dev->irqs = ctx.irqs;
194    dev->irq_count = ctx.irq_count;
195
196    zxlogf(TRACE, "acpi-bus[%s]: found %zd resources %zx irqs\n", device_get_name(dev->zxdev),
197            dev->resource_count, dev->irq_count);
198    if (driver_get_log_flags() & DDK_LOG_SPEW) {
199        zxlogf(SPEW, "resources:\n");
200        for (size_t i = 0; i < dev->resource_count; i++) {
201            zxlogf(SPEW, "  %02zd: addr=0x%x length=0x%x align=0x%x writeable=%d\n", i,
202                    dev->resources[i].base_address,
203                    dev->resources[i].address_length,
204                    dev->resources[i].alignment,
205                    dev->resources[i].writeable);
206        }
207        zxlogf(SPEW, "irqs:\n");
208        for (size_t i = 0; i < dev->irq_count; i++) {
209            zxlogf(SPEW, "  %02zd: pin=%u %s %s %s %s\n", i,
210                    dev->irqs[i].pin,
211                    dev->irqs[i].trigger ? "edge" : "level",
212                    (dev->irqs[i].polarity == 2) ? "both" :
213                        (dev->irqs[i].polarity ? "low" : "high"),
214                    dev->irqs[i].sharable ? "shared" : "exclusive",
215                    dev->irqs[i].wake_capable ? "wake" : "nowake");
216        }
217    }
218
219    dev->got_resources = true;
220
221    return ZX_OK;
222}
223
224static zx_status_t acpi_op_map_resource(void* ctx, uint32_t res_id, uint32_t cache_policy,
225        void** out_vaddr, size_t* out_size, zx_handle_t* out_handle) {
226    acpi_device_t* dev = (acpi_device_t*)ctx;
227    mtx_lock(&dev->lock);
228
229    zx_status_t st = report_current_resources(dev);
230    if (st != ZX_OK) {
231        goto unlock;
232    }
233
234    if (res_id >= dev->resource_count) {
235        st = ZX_ERR_NOT_FOUND;
236        goto unlock;
237    }
238
239    acpi_device_resource_t* res = dev->resources + res_id;
240    if (((res->base_address & (PAGE_SIZE - 1)) != 0) ||
241        ((res->address_length & (PAGE_SIZE - 1)) != 0)) {
242        zxlogf(ERROR, "acpi-bus[%s]: resource id=%d addr=0x%08x len=0x%x is not page aligned\n",
243                device_get_name(dev->zxdev), res_id, res->base_address, res->address_length);
244        st = ZX_ERR_NOT_FOUND;
245        goto unlock;
246    }
247
248    zx_handle_t vmo;
249    zx_vaddr_t vaddr;
250    size_t size = res->address_length;
251    st = zx_vmo_create_physical(get_root_resource(), res->base_address, size, &vmo);
252    if (st != ZX_OK) {
253        goto unlock;
254    }
255
256    st = zx_vmo_set_cache_policy(vmo, cache_policy);
257    if (st != ZX_OK) {
258        zx_handle_close(vmo);
259        goto unlock;
260    }
261
262    st = zx_vmar_map(zx_vmar_root_self(),
263                     ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_MAP_RANGE,
264                     0, vmo, 0, size, &vaddr);
265    if (st != ZX_OK) {
266        zx_handle_close(vmo);
267    } else {
268        *out_handle = vmo;
269        *out_vaddr = (void*)vaddr;
270        *out_size = size;
271    }
272unlock:
273    mtx_unlock(&dev->lock);
274    return st;
275}
276
277static zx_status_t acpi_op_map_interrupt(void* ctx, int which_irq, zx_handle_t* out_handle) {
278    acpi_device_t* dev = (acpi_device_t*)ctx;
279    mtx_lock(&dev->lock);
280
281    zx_status_t st = report_current_resources(dev);
282    if (st != ZX_OK) {
283        goto unlock;
284    }
285
286    if ((uint)which_irq >= dev->irq_count) {
287        st = ZX_ERR_NOT_FOUND;
288        goto unlock;
289    }
290
291    acpi_device_irq_t* irq = dev->irqs + which_irq;
292    zx_handle_t handle;
293    st = zx_interrupt_create(get_root_resource(), irq->pin, ZX_INTERRUPT_REMAP_IRQ, &handle);
294    if (st != ZX_OK) {
295        goto unlock;
296    }
297    *out_handle = handle;
298
299unlock:
300    mtx_unlock(&dev->lock);
301    return st;
302}
303
304// TODO marking unused until we publish some devices
305static __attribute__ ((unused)) acpi_protocol_ops_t acpi_proto = {
306    .map_resource = acpi_op_map_resource,
307    .map_interrupt = acpi_op_map_interrupt,
308};
309
310static zx_protocol_device_t acpi_root_device_proto = {
311    .version = DEVICE_OPS_VERSION,
312};
313
314static zx_status_t sys_device_suspend(void* ctx, uint32_t flags) {
315    switch (flags & DEVICE_SUSPEND_REASON_MASK) {
316    case DEVICE_SUSPEND_FLAG_MEXEC: {
317        AcpiTerminate();
318        return ZX_OK;
319    }
320    case DEVICE_SUSPEND_FLAG_REBOOT:
321        reboot();
322        // Kill this driver so that the IPC channel gets closed; devmgr will
323        // perform a fallback that should shutdown or reboot the machine.
324        exit(0);
325    case DEVICE_SUSPEND_FLAG_POWEROFF:
326        poweroff();
327        exit(0);
328    case DEVICE_SUSPEND_FLAG_SUSPEND_RAM:
329        return suspend_to_ram();
330    default:
331        return ZX_ERR_NOT_SUPPORTED;
332    };
333}
334
335static zx_protocol_device_t sys_device_proto = {
336    .version = DEVICE_OPS_VERSION,
337    .suspend = sys_device_suspend,
338};
339
340static const char* hid_from_acpi_devinfo(ACPI_DEVICE_INFO* info) {
341    const char* hid = NULL;
342    if ((info->Valid & ACPI_VALID_HID) &&
343            (info->HardwareId.Length > 0) &&
344            ((info->HardwareId.Length - 1) <= sizeof(uint64_t))) {
345        hid = (const char*)info->HardwareId.String;
346    }
347    return hid;
348}
349
350static zx_device_t* publish_device(zx_device_t* parent,
351                                   ACPI_HANDLE handle,
352                                   ACPI_DEVICE_INFO* info,
353                                   const char* name,
354                                   uint32_t protocol_id,
355                                   void* protocol_ops) {
356    zx_device_prop_t props[4];
357    int propcount = 0;
358
359    char acpi_name[5] = { 0 };
360    if (!name) {
361        memcpy(acpi_name, &info->Name, sizeof(acpi_name) - 1);
362        name = (const char*)acpi_name;
363    }
364
365    // Publish HID in device props
366    const char* hid = hid_from_acpi_devinfo(info);
367    if (hid) {
368        props[propcount].id = BIND_ACPI_HID_0_3;
369        props[propcount++].value = htobe32(*((uint32_t*)(hid)));
370        props[propcount].id = BIND_ACPI_HID_4_7;
371        props[propcount++].value = htobe32(*((uint32_t*)(hid + 4)));
372    }
373
374    // Publish the first CID in device props
375    const char* cid = (const char*)info->CompatibleIdList.Ids[0].String;
376    if ((info->Valid & ACPI_VALID_CID) &&
377            (info->CompatibleIdList.Count > 0) &&
378            ((info->CompatibleIdList.Ids[0].Length - 1) <= sizeof(uint64_t))) {
379        props[propcount].id = BIND_ACPI_CID_0_3;
380        props[propcount++].value = htobe32(*((uint32_t*)(cid)));
381        props[propcount].id = BIND_ACPI_CID_4_7;
382        props[propcount++].value = htobe32(*((uint32_t*)(cid + 4)));
383    }
384
385    if (driver_get_log_flags() & DDK_LOG_SPEW) {
386        // ACPI names are always 4 characters in a uint32
387        zxlogf(SPEW, "acpi: got device %s\n", acpi_name);
388        if (info->Valid & ACPI_VALID_HID) {
389            zxlogf(SPEW, "     HID=%s\n", info->HardwareId.String);
390        } else {
391            zxlogf(SPEW, "     HID=invalid\n");
392        }
393        if (info->Valid & ACPI_VALID_ADR) {
394            zxlogf(SPEW, "     ADR=0x%" PRIx64 "\n", (uint64_t)info->Address);
395        } else {
396            zxlogf(SPEW, "     ADR=invalid\n");
397        }
398        if (info->Valid & ACPI_VALID_CID) {
399            zxlogf(SPEW, "    CIDS=%d\n", info->CompatibleIdList.Count);
400            for (uint i = 0; i < info->CompatibleIdList.Count; i++) {
401                zxlogf(SPEW, "     [%u] %s\n", i, info->CompatibleIdList.Ids[i].String);
402            }
403        } else {
404            zxlogf(SPEW, "     CID=invalid\n");
405        }
406        zxlogf(SPEW, "    devprops:\n");
407        for (int i = 0; i < propcount; i++) {
408            zxlogf(SPEW, "     [%d] id=0x%08x value=0x%08x\n", i, props[i].id, props[i].value);
409        }
410    }
411
412    acpi_device_t* dev = calloc(1, sizeof(acpi_device_t));
413    if (!dev) {
414        return NULL;
415    }
416
417    dev->ns_node = handle;
418
419    device_add_args_t args = {
420        .version = DEVICE_ADD_ARGS_VERSION,
421        .name = name,
422        .ctx = dev,
423        .ops = &acpi_device_proto,
424        .proto_id = protocol_id,
425        .proto_ops = protocol_ops,
426        .props = (propcount > 0) ? props : NULL,
427        .prop_count = propcount,
428    };
429
430    zx_status_t status;
431    if ((status = device_add(parent, &args, &dev->zxdev)) != ZX_OK) {
432        zxlogf(ERROR, "acpi: error %d in device_add, parent=%s(%p)\n",
433                status, device_get_name(parent), parent);
434        free(dev);
435        return NULL;
436    } else {
437        zxlogf(ERROR, "acpi: published device %s(%p), parent=%s(%p), handle=%p\n",
438                name, dev, device_get_name(parent), parent, (void*)dev->ns_node);
439        return dev->zxdev;
440    }
441}
442
443static ACPI_STATUS acpi_ns_walk_callback(ACPI_HANDLE object, uint32_t nesting_level,
444                                         void* context, void** status) {
445    ACPI_DEVICE_INFO* info = NULL;
446    ACPI_STATUS acpi_status = AcpiGetObjectInfo(object, &info);
447    if (acpi_status != AE_OK) {
448        return acpi_status;
449    }
450
451    publish_acpi_device_ctx_t* ctx = (publish_acpi_device_ctx_t*)context;
452    zx_device_t* parent = ctx->parent;
453
454    // TODO: This is a temporary workaround until we have full ACPI device
455    // enumeration. If this is the I2C1 bus, we run _PS0 so the controller
456    // is active.
457    if (!memcmp(&info->Name, "I2C1", 4)) {
458        acpi_status = AcpiEvaluateObject(object, (char*)"_PS0", NULL, NULL);
459        if (acpi_status != AE_OK) {
460            zxlogf(ERROR, "acpi: acpi error 0x%x in I2C1._PS0\n", acpi_status);
461        }
462
463    // Attach the NHLT table as metadata on the HDA device.
464    // The ACPI node representing the HDA controller is named "HDAS" on Pixelbook.
465    // TODO: This is a temporary workaround for ACPI device enumeration.
466    } else if (!memcmp(&info->Name, "HDAS", 4)) {
467        // We must have already seen at least one PCI root due to traversal order.
468        if (ctx->last_pci == 0xFF) {
469            zxlogf(ERROR, "acpi: Found HDAS node, but no prior PCI root was discovered!\n");
470        } else if (!(info->Valid & ACPI_VALID_ADR)) {
471            zxlogf(ERROR, "acpi: no valid ADR found for HDA device\n");
472        } else {
473            zx_status_t status = nhlt_publish_metadata(parent,
474                                                       ctx->last_pci,
475                                                       (uint64_t)info->Address,
476                                                       object);
477            if ((status != ZX_OK) && (status != ZX_ERR_NOT_FOUND)) {
478                zxlogf(ERROR, "acpi: failed to publish NHLT metadata\n");
479            }
480        }
481    }
482
483    const char* hid = hid_from_acpi_devinfo(info);
484    if (hid == 0) {
485        goto out;
486    }
487    const char* cid = NULL;
488    if ((info->Valid & ACPI_VALID_CID) &&
489            (info->CompatibleIdList.Count > 0) &&
490            // IDs may be 7 or 8 bytes, and Length includes the null byte
491            (info->CompatibleIdList.Ids[0].Length == HID_LENGTH ||
492             info->CompatibleIdList.Ids[0].Length == HID_LENGTH + 1)) {
493        cid = (const char*)info->CompatibleIdList.Ids[0].String;
494    }
495
496    if ((!memcmp(hid, PCI_EXPRESS_ROOT_HID_STRING, HID_LENGTH) ||
497         !memcmp(hid, PCI_ROOT_HID_STRING, HID_LENGTH))) {
498        if (!ctx->found_pci) {
499            // Publish PCI root as top level
500            // Only publish one PCI root device for all PCI roots
501            // TODO: store context for PCI root protocol
502            parent = device_get_parent(parent);
503            zx_device_t* pcidev = publish_device(parent, object, info, "pci",
504                    ZX_PROTOCOL_PCIROOT, get_pciroot_ops());
505            ctx->found_pci = (pcidev != NULL);
506        }
507        // Get the PCI base bus number
508        zx_status_t status = acpi_bbn_call(object, &ctx->last_pci);
509        if (status != ZX_OK) {
510            zxlogf(ERROR, "acpi: failed to get PCI base bus number for device '%s' "
511                          "(status %u)\n", (const char*)&info->Name, status);
512        }
513        zxlogf(TRACE, "acpi: found pci root #%u\n", ctx->last_pci);
514    } else if (!memcmp(hid, BATTERY_HID_STRING, HID_LENGTH)) {
515        battery_init(parent, object);
516    } else if (!memcmp(hid, PWRSRC_HID_STRING, HID_LENGTH)) {
517        pwrsrc_init(parent, object);
518    } else if (!memcmp(hid, EC_HID_STRING, HID_LENGTH)) {
519        ec_init(parent, object);
520    } else if (!memcmp(hid, GOOGLE_TBMC_HID_STRING, HID_LENGTH)) {
521        tbmc_init(parent, object);
522    } else if (!memcmp(hid, GOOGLE_CROS_EC_HID_STRING, HID_LENGTH)) {
523        cros_ec_lpc_init(parent, object);
524    } else if (!memcmp(hid, DPTF_THERMAL_HID_STRING, HID_LENGTH)) {
525        thermal_init(parent, info, object);
526    } else if (!memcmp(hid, I8042_HID_STRING, HID_LENGTH) ||
527               (cid && !memcmp(cid, I8042_HID_STRING, HID_LENGTH))) {
528        publish_device(parent, object, info, "i8042", ZX_PROTOCOL_ACPI, &acpi_proto);
529    } else if (!memcmp(hid, RTC_HID_STRING, HID_LENGTH) ||
530               (cid && !memcmp(cid, RTC_HID_STRING, HID_LENGTH))) {
531        publish_device(parent, object, info, "rtc", ZX_PROTOCOL_ACPI, &acpi_proto);
532    }
533
534out:
535    ACPI_FREE(info);
536
537    return AE_OK;
538}
539
540static zx_status_t publish_acpi_devices(zx_device_t* parent) {
541    zx_status_t status = pwrbtn_init(parent);
542    if (status != ZX_OK) {
543        zxlogf(ERROR, "acpi: failed to initialize pwrbtn device: %d\n", status);
544    }
545
546    // Walk the ACPI namespace for devices and publish them
547    // Only publish a single PCI device
548    publish_acpi_device_ctx_t ctx = {
549        .parent = parent,
550        .found_pci = false,
551        .last_pci = 0xFF,
552    };
553    ACPI_STATUS acpi_status = AcpiWalkNamespace(ACPI_TYPE_DEVICE,
554                                                ACPI_ROOT_OBJECT,
555                                                MAX_NAMESPACE_DEPTH,
556                                                acpi_ns_walk_callback,
557                                                NULL, &ctx, NULL);
558    if (acpi_status != AE_OK) {
559        return ZX_ERR_BAD_STATE;
560    } else {
561        return ZX_OK;
562    }
563}
564
565static zx_status_t acpi_drv_create(void* ctx, zx_device_t* parent, const char* name,
566                                   const char* _args, zx_handle_t zbi_vmo) {
567    // ACPI is the root driver for its devhost so run init in the bind thread.
568    zxlogf(TRACE, "acpi: bind to %s %p\n", device_get_name(parent), parent);
569    root_resource_handle = get_root_resource();
570
571    // We don't need ZBI VMO handle.
572    zx_handle_close(zbi_vmo);
573
574    zx_status_t status = init();
575    if (status != ZX_OK) {
576        zxlogf(ERROR, "acpi: failed to initialize ACPI %d \n", status);
577        return ZX_ERR_INTERNAL;
578    }
579
580    zxlogf(TRACE, "acpi: initialized\n");
581
582    // Report current resources to kernel PCI driver
583    status = pci_report_current_resources(get_root_resource());
584    if (status != ZX_OK) {
585        zxlogf(ERROR, "acpi: WARNING: ACPI failed to report all current resources!\n");
586    }
587
588    // Initialize kernel PCI driver
589    zx_pci_init_arg_t* arg;
590    uint32_t arg_size;
591    status = get_pci_init_arg(&arg, &arg_size);
592    if (status != ZX_OK) {
593        zxlogf(ERROR, "acpi: erorr %d in get_pci_init_arg\n", status);
594        return status;
595    }
596
597    status = zx_pci_init(get_root_resource(), arg, arg_size);
598    if (status != ZX_OK) {
599        zxlogf(ERROR, "acpi: error %d in zx_pci_init\n", status);
600        return status;
601    }
602
603    free(arg);
604
605    // publish sys root
606    device_add_args_t args = {
607        .version = DEVICE_ADD_ARGS_VERSION,
608        .name = name,
609        .ops = &sys_device_proto,
610        .flags = DEVICE_ADD_NON_BINDABLE,
611    };
612
613    zx_device_t* sys_root = NULL;
614    status = device_add(parent, &args, &sys_root);
615    if (status != ZX_OK) {
616        zxlogf(ERROR, "acpi: error %d in device_add(sys)\n", status);
617        return status;
618    }
619
620    zx_handle_t dummy_iommu_handle;
621    status = iommu_manager_get_dummy_iommu(&dummy_iommu_handle);
622    if (status != ZX_OK) {
623        zxlogf(ERROR, "acpi-bus: error %d in iommu_manager_get_dummy_iommu()\n", status);
624        return status;
625    }
626    zx_handle_t cpu_trace_bti;
627    status = zx_bti_create(dummy_iommu_handle, 0, CPU_TRACE_BTI_ID, &cpu_trace_bti);
628    if (status != ZX_OK) {
629        zxlogf(ERROR, "acpi: error %d in bti_create(cpu_trace_bti)\n", status);
630        return status;
631    }
632
633    status = publish_cpu_trace(cpu_trace_bti, sys_root);
634    if (status != ZX_OK) {
635        return status;
636    }
637
638    // publish acpi root
639    device_add_args_t args2 = {
640        .version = DEVICE_ADD_ARGS_VERSION,
641        .name = "acpi",
642        .ops = &acpi_root_device_proto,
643        .flags = DEVICE_ADD_NON_BINDABLE,
644    };
645
646    zx_device_t* acpi_root = NULL;
647    status = device_add(sys_root, &args2, &acpi_root);
648    if (status != ZX_OK) {
649        zxlogf(ERROR, "acpi: error %d in device_add(sys/acpi)\n", status);
650        device_remove(sys_root);
651        return status;
652    }
653
654    // TODO - retrieve more useful board name from ACPI data
655    const char board_name[] = { "pc" };
656
657    // Publish board name to sysinfo driver
658    status = device_publish_metadata(acpi_root, "/dev/misc/sysinfo", DEVICE_METADATA_BOARD_NAME,
659                                     board_name, sizeof(board_name));
660    if (status != ZX_OK) {
661        zxlogf(ERROR, "device_publish_metadata(board_name) failed: %d\n", status);
662    }
663
664    publish_acpi_devices(acpi_root);
665
666    return ZX_OK;
667}
668
669static zx_driver_ops_t acpi_driver_ops = {
670    .version = DRIVER_OPS_VERSION,
671    .create = acpi_drv_create,
672};
673
674ZIRCON_DRIVER_BEGIN(acpi, acpi_driver_ops, "zircon", "0.1", 1)
675    BI_ABORT_IF_AUTOBIND, // loaded by devcoordinator
676ZIRCON_DRIVER_END(acpi)
677