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