u-boot/cmd/acpi.c
Heinrich Schuchardt c95ade8dcd cmd: acpi: check HW reduced flag in acpi list
On non x86 platforms the hardware reduce flag must be set in the FADT
table. Write an error message if the flag is missing.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Rebased on -next to use nomap, add hyphens:
Signed-off-by: Simon Glass <sjg@chromium.org>
2024-01-07 13:49:02 -07:00

200 lines
4.8 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2019 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <command.h>
#include <display_options.h>
#include <log.h>
#include <mapmem.h>
#include <acpi/acpi_table.h>
#include <asm/acpi_table.h>
#include <asm/global_data.h>
#include <dm/acpi.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* dump_hdr() - Dump an ACPI header
*
* Except for the Firmware ACPI Control Structure (FACS)
* additionally show the revision information.
*
* @hdr: ACPI header to dump
*/
static void dump_hdr(struct acpi_table_header *hdr)
{
bool has_hdr = memcmp(hdr->signature, "FACS", ACPI_NAME_LEN);
printf("%.*s %16lx %5x", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr), hdr->length);
if (has_hdr) {
printf(" v%02d %.6s %.8s %x %.4s %x\n", hdr->revision,
hdr->oem_id, hdr->oem_table_id, hdr->oem_revision,
hdr->aslc_id, hdr->aslc_revision);
} else {
printf("\n");
}
}
static int dump_table_name(const char *sig)
{
struct acpi_table_header *hdr;
hdr = acpi_find_table(sig);
if (!hdr)
return -ENOENT;
printf("%.*s @ %16lx\n", ACPI_NAME_LEN, hdr->signature,
(ulong)nomap_to_sysmem(hdr));
print_buffer(0, hdr, 1, hdr->length, 0);
return 0;
}
static void list_fadt(struct acpi_fadt *fadt)
{
if (fadt->header.revision >= 3 && fadt->x_dsdt)
dump_hdr(nomap_sysmem(fadt->x_dsdt, 0));
else if (fadt->dsdt)
dump_hdr(nomap_sysmem(fadt->dsdt, 0));
if (!IS_ENABLED(CONFIG_X86) &&
!(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI))
log_err("FADT not ACPI-hardware-reduced-compliant\n");
if (fadt->header.revision >= 3 && fadt->x_firmware_ctrl)
dump_hdr(nomap_sysmem(fadt->x_firmware_ctrl, 0));
else if (fadt->firmware_ctrl)
dump_hdr(nomap_sysmem(fadt->firmware_ctrl, 0));
}
static void list_rsdt(struct acpi_rsdp *rsdp)
{
int len, i, count;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
if (rsdp->rsdt_address) {
rsdt = nomap_sysmem(rsdp->rsdt_address, 0);
dump_hdr(&rsdt->header);
}
if (rsdp->xsdt_address) {
xsdt = nomap_sysmem(rsdp->xsdt_address, 0);
dump_hdr(&xsdt->header);
len = xsdt->header.length - sizeof(xsdt->header);
count = len / sizeof(u64);
} else if (rsdp->rsdt_address) {
len = rsdt->header.length - sizeof(rsdt->header);
count = len / sizeof(u32);
} else {
return;
}
for (i = 0; i < count; i++) {
struct acpi_table_header *hdr;
u64 entry;
if (rsdp->xsdt_address)
entry = xsdt->entry[i];
else
entry = rsdt->entry[i];
if (!entry)
break;
hdr = nomap_sysmem(entry, 0);
dump_hdr(hdr);
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN))
list_fadt((struct acpi_fadt *)hdr);
}
}
static void list_rsdp(struct acpi_rsdp *rsdp)
{
printf("RSDP %16lx %5x v%02d %.6s\n", (ulong)map_to_sysmem(rsdp),
rsdp->length, rsdp->revision, rsdp->oem_id);
list_rsdt(rsdp);
}
static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct acpi_rsdp *rsdp;
rsdp = map_sysmem(gd_acpi_start(), 0);
if (!rsdp) {
printf("No ACPI tables present\n");
return 0;
}
printf("Name Base Size Detail\n"
"---- ---------------- ----- ----------------------------\n");
list_rsdp(rsdp);
return 0;
}
static int do_acpi_set(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
ulong val;
if (argc < 2) {
printf("ACPI pointer: %lx\n", gd_acpi_start());
} else {
val = hextoul(argv[1], NULL);
printf("Setting ACPI pointer to %lx\n", val);
gd_set_acpi_start(val);
}
return 0;
}
static int do_acpi_items(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
bool dump_contents;
dump_contents = argc >= 2 && !strcmp("-d", argv[1]);
if (!IS_ENABLED(CONFIG_ACPIGEN)) {
printf("Not supported (enable ACPIGEN)\n");
return CMD_RET_FAILURE;
}
acpi_dump_items(dump_contents ? ACPI_DUMP_CONTENTS : ACPI_DUMP_LIST);
return 0;
}
static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
const char *name;
char sig[ACPI_NAME_LEN];
int ret;
if (argc < 2)
return CMD_RET_USAGE;
name = argv[1];
if (strlen(name) != ACPI_NAME_LEN) {
printf("Table name '%s' must be four characters\n", name);
return CMD_RET_FAILURE;
}
str_to_upper(name, sig, ACPI_NAME_LEN);
ret = dump_table_name(sig);
if (ret) {
printf("Table '%.*s' not found\n", ACPI_NAME_LEN, sig);
return CMD_RET_FAILURE;
}
return 0;
}
U_BOOT_LONGHELP(acpi,
"list - list ACPI tables\n"
"acpi items [-d] - List/dump each piece of ACPI data from devices\n"
"acpi set [<addr>] - Set or show address of ACPI tables\n"
"acpi dump <name> - Dump ACPI table");
U_BOOT_CMD_WITH_SUBCMDS(acpi, "ACPI tables", acpi_help_text,
U_BOOT_SUBCMD_MKENT(list, 1, 1, do_acpi_list),
U_BOOT_SUBCMD_MKENT(items, 2, 1, do_acpi_items),
U_BOOT_SUBCMD_MKENT(set, 2, 1, do_acpi_set),
U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump));