1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Handles writing the declared ACPI tables 4 * 5 * Copyright 2021 Google LLC 6 */ 7 8#define LOG_CATEGORY LOGC_ACPI 9 10#include <log.h> 11#include <malloc.h> 12#include <mapmem.h> 13#include <acpi/acpi_table.h> 14#include <asm/global_data.h> 15#include <dm/acpi.h> 16#include <linux/errno.h> 17 18DECLARE_GLOBAL_DATA_PTR; 19 20int acpi_write_one(struct acpi_ctx *ctx, const struct acpi_writer *entry) 21{ 22 int ret; 23 24 log_debug("%s: writing table '%s'\n", entry->name, 25 entry->table); 26 ctx->tab_start = ctx->current; 27 ret = entry->h_write(ctx, entry); 28 if (ret == -ENOENT) { 29 log_debug("%s: Omitted due to being empty\n", 30 entry->name); 31 ret = 0; 32 ctx->current = ctx->tab_start; /* drop the table */ 33 return ret; 34 } 35 if (ret) 36 return log_msg_ret("write", ret); 37 38 if (entry->flags & ACPIWF_ALIGN64) 39 acpi_align64(ctx); 40 else 41 acpi_align(ctx); 42 43 /* Add the item to the internal list */ 44 ret = acpi_add_other_item(ctx, entry, ctx->tab_start); 45 if (ret) 46 return log_msg_ret("add", ret); 47 48 return 0; 49} 50 51#ifndef CONFIG_QFW_ACPI 52static int acpi_write_all(struct acpi_ctx *ctx) 53{ 54 const struct acpi_writer *writer = 55 ll_entry_start(struct acpi_writer, acpi_writer); 56 const int n_ents = ll_entry_count(struct acpi_writer, acpi_writer); 57 const struct acpi_writer *entry; 58 int ret; 59 60 for (entry = writer; entry != writer + n_ents; entry++) { 61 ret = acpi_write_one(ctx, entry); 62 if (ret && ret != -ENOENT) 63 return log_msg_ret("one", ret); 64 } 65 66 return 0; 67} 68 69/* 70 * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c 71 */ 72ulong write_acpi_tables(ulong start_addr) 73{ 74 struct acpi_ctx *ctx; 75 ulong addr; 76 int ret; 77 78 ctx = malloc(sizeof(*ctx)); 79 if (!ctx) 80 return log_msg_ret("mem", -ENOMEM); 81 82 log_debug("ACPI: Writing ACPI tables at %lx\n", start_addr); 83 84 acpi_reset_items(); 85 acpi_setup_ctx(ctx, start_addr); 86 87 ret = acpi_write_all(ctx); 88 if (ret) { 89 log_err("Failed to write ACPI tables (err=%d)\n", ret); 90 return log_msg_ret("write", -ENOMEM); 91 } 92 93 addr = map_to_sysmem(ctx->current); 94 log_debug("ACPI current = %lx\n", addr); 95 96 return addr; 97} 98 99int write_dev_tables(struct acpi_ctx *ctx, const struct acpi_writer *entry) 100{ 101 int ret; 102 103 ret = acpi_write_dev_tables(ctx); 104 if (ret) 105 return log_msg_ret("write", ret); 106 107 return 0; 108} 109ACPI_WRITER(8dev, NULL, write_dev_tables, 0); 110 111ulong acpi_get_rsdp_addr(void) 112{ 113 if (!gd->acpi_ctx) 114 return 0; 115 116 return map_to_sysmem(gd->acpi_ctx->rsdp); 117} 118#endif /* QFW_ACPI */ 119 120void acpi_setup_ctx(struct acpi_ctx *ctx, ulong start) 121{ 122 gd->acpi_ctx = ctx; 123 memset(ctx, '\0', sizeof(*ctx)); 124 125 /* Align ACPI tables to 16-byte boundary */ 126 start = ALIGN(start, 16); 127 ctx->base = map_sysmem(start, 0); 128 ctx->current = ctx->base; 129 130 gd_set_acpi_start(start); 131} 132