blob: e2ac682305952db11820900412cc773c7b9363fa [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuchsia/hardware/pciroot/c/banjo.h>
#include <inttypes.h>
#include <lib/ddk/debug.h>
#include <limits.h>
#include <sys/types.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/iommu.h>
#include <zircon/syscalls/resource.h>
#include <zircon/threads.h>
#include <variant>
#include <vector>
#include <acpica/acpi.h>
#include <fbl/auto_lock.h>
#include "acpi-dev/dev-ec.h"
#include "acpi-private.h"
#include "acpi.h"
#include "dev.h"
#include "errors.h"
#include "methods.h"
#include "power.h"
#include "src/devices/board/lib/acpi/device.h"
#include "src/devices/board/lib/acpi/manager.h"
#include "src/devices/board/lib/acpi/resources.h"
#include "src/devices/board/lib/acpi/status.h"
#include "src/devices/lib/iommu/iommu.h"
#include "sysmem.h"
namespace {
const std::string_view hid_from_acpi_devinfo(const ACPI_DEVICE_INFO& info) {
if ((info.Valid & ACPI_VALID_HID) && (info.HardwareId.Length > 0) &&
((info.HardwareId.Length - 1) <= sizeof(uint64_t))) {
// ACPICA string lengths include the NULL terminator.
return std::string_view{info.HardwareId.String, info.HardwareId.Length - 1};
}
return std::string_view{};
}
} // namespace
namespace acpi {
acpi::status<UniquePtr<ACPI_DEVICE_INFO>> GetObjectInfo(ACPI_HANDLE obj) {
ACPI_DEVICE_INFO* raw = nullptr;
ACPI_STATUS acpi_status = AcpiGetObjectInfo(obj, &raw);
UniquePtr<ACPI_DEVICE_INFO> ret{raw};
if (ACPI_SUCCESS(acpi_status)) {
return acpi::ok(std::move(ret));
}
return acpi::error(acpi_status);
}
} // namespace acpi
zx_status_t acpi_suspend(zx_device_t* device, uint8_t requested_state, bool enable_wake,
uint8_t suspend_reason, uint8_t* out_state) {
switch (suspend_reason & DEVICE_MASK_SUSPEND_REASON) {
case DEVICE_SUSPEND_REASON_MEXEC: {
AcpiTerminate();
return ZX_OK;
}
case DEVICE_SUSPEND_REASON_REBOOT:
// Don't do anything, we expect the higher layers to execute the reboot.
return ZX_OK;
case DEVICE_SUSPEND_REASON_POWEROFF:
poweroff(device);
exit(0);
case DEVICE_SUSPEND_REASON_SUSPEND_RAM:
return suspend_to_ram(device);
default:
return ZX_ERR_NOT_SUPPORTED;
};
}
zx_status_t publish_acpi_devices(acpi::Manager* manager, zx_device_t* platform_bus,
zx_device_t* acpi_root) {
acpi::Acpi* acpi = manager->acpi();
auto result = manager->DiscoverDevices();
if (result.is_error()) {
zxlogf(INFO, "discover devices failed");
}
result = manager->ConfigureDiscoveredDevices();
if (result.is_error()) {
zxlogf(INFO, "configure failed");
}
result = manager->PublishDevices(platform_bus, fdf::Dispatcher::GetCurrent()->async_dispatcher());
// Now walk the ACPI namespace looking for devices we understand, and publish
// them. For now, publish only the first PCI bus we encounter.
// TODO(https://fxbug.dev/42158465): remove this when all drivers are removed from the x86 board
// driver.
acpi::status<> acpi_status =
acpi->WalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, MAX_NAMESPACE_DEPTH,
[acpi_root, acpi](ACPI_HANDLE object, uint32_t level,
acpi::WalkDirection dir) -> acpi::status<> {
// We don't have anything useful to do during the ascent
// phase. Just skip it.
if (dir == acpi::WalkDirection::Ascending) {
return acpi::ok();
}
// We are descending. Grab our object info.
acpi::UniquePtr<ACPI_DEVICE_INFO> info;
if (auto res = acpi::GetObjectInfo(object); res.is_error()) {
return res.take_error();
} else {
info = std::move(res.value());
}
// Extract pointers to the hardware ID and the compatible ID
// if present. If there is no hardware ID, just skip the
// device.
const std::string_view hid = hid_from_acpi_devinfo(*info);
if (hid.empty()) {
return acpi::ok();
}
// Now, if we recognize the HID, go ahead and deal with
// publishing the device.
if (hid == EC_HID_STRING) {
acpi_ec::EcDevice::Create(acpi_root, acpi, object);
}
return acpi::ok();
});
if (acpi_status.is_error()) {
return ZX_ERR_BAD_STATE;
}
return ZX_OK;
}