| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * Handles writing the declared ACPI tables | |
| * | |
| * Copyright 2021 Google LLC | |
| */ | |
| #define LOG_CATEGORY LOGC_ACPI | |
| #include <log.h> | |
| #include <malloc.h> | |
| #include <mapmem.h> | |
| #include <acpi/acpi_table.h> | |
| #include <asm/global_data.h> | |
| #include <dm/acpi.h> | |
| #include <linux/errno.h> | |
| DECLARE_GLOBAL_DATA_PTR; | |
| int acpi_write_one(struct acpi_ctx *ctx, const struct acpi_writer *entry) | |
| { | |
| int ret; | |
| log_debug("%s: writing table '%s'\n", entry->name, | |
| entry->table); | |
| ctx->tab_start = ctx->current; | |
| ret = entry->h_write(ctx, entry); | |
| if (ret == -ENOENT) { | |
| log_debug("%s: Omitted due to being empty\n", | |
| entry->name); | |
| ret = 0; | |
| ctx->current = ctx->tab_start; /* drop the table */ | |
| return ret; | |
| } | |
| if (ret) | |
| return log_msg_ret("write", ret); | |
| if (entry->flags & ACPIWF_ALIGN64) | |
| acpi_align64(ctx); | |
| else | |
| acpi_align(ctx); | |
| /* Add the item to the internal list */ | |
| ret = acpi_add_other_item(ctx, entry, ctx->tab_start); | |
| if (ret) | |
| return log_msg_ret("add", ret); | |
| return 0; | |
| } | |
| #ifndef CONFIG_QFW_ACPI | |
| static int acpi_write_all(struct acpi_ctx *ctx) | |
| { | |
| const struct acpi_writer *writer = | |
| ll_entry_start(struct acpi_writer, acpi_writer); | |
| const int n_ents = ll_entry_count(struct acpi_writer, acpi_writer); | |
| const struct acpi_writer *entry; | |
| int ret; | |
| for (entry = writer; entry != writer + n_ents; entry++) { | |
| ret = acpi_write_one(ctx, entry); | |
| if (ret && ret != -ENOENT) | |
| return log_msg_ret("one", ret); | |
| } | |
| return 0; | |
| } | |
| /* | |
| * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c | |
| */ | |
| ulong write_acpi_tables(ulong start_addr) | |
| { | |
| struct acpi_ctx *ctx; | |
| ulong addr; | |
| int ret; | |
| ctx = malloc(sizeof(*ctx)); | |
| if (!ctx) | |
| return log_msg_ret("mem", -ENOMEM); | |
| log_debug("ACPI: Writing ACPI tables at %lx\n", start_addr); | |
| acpi_reset_items(); | |
| acpi_setup_ctx(ctx, start_addr); | |
| ret = acpi_write_all(ctx); | |
| if (ret) { | |
| log_err("Failed to write ACPI tables (err=%d)\n", ret); | |
| return log_msg_ret("write", -ENOMEM); | |
| } | |
| addr = map_to_sysmem(ctx->current); | |
| log_debug("ACPI current = %lx\n", addr); | |
| return addr; | |
| } | |
| int write_dev_tables(struct acpi_ctx *ctx, const struct acpi_writer *entry) | |
| { | |
| int ret; | |
| ret = acpi_write_dev_tables(ctx); | |
| if (ret) | |
| return log_msg_ret("write", ret); | |
| return 0; | |
| } | |
| ACPI_WRITER(8dev, NULL, write_dev_tables, 0); | |
| ulong acpi_get_rsdp_addr(void) | |
| { | |
| if (!gd->acpi_ctx) | |
| return 0; | |
| return map_to_sysmem(gd->acpi_ctx->rsdp); | |
| } | |
| #endif /* QFW_ACPI */ | |
| void acpi_setup_ctx(struct acpi_ctx *ctx, ulong start) | |
| { | |
| gd->acpi_ctx = ctx; | |
| memset(ctx, '\0', sizeof(*ctx)); | |
| /* Align ACPI tables to 16-byte boundary */ | |
| start = ALIGN(start, 16); | |
| ctx->base = map_sysmem(start, 0); | |
| ctx->current = ctx->base; | |
| gd_set_acpi_start(start); | |
| } |