From 0f7b111f70087f60e84f936fbe0c2a0a243a4fec Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:06 -0600 Subject: acpi: Support ordering SSDT data by device Add a /chosen property to control the order in which the data appears in the SSDT. This allows matching up U-Boot's output from a dump of the known-good data obtained from within Linux. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- drivers/core/acpi.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'drivers') diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index df3d7ba..a9b7fc1 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -108,6 +108,85 @@ static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev, return 0; } +static struct acpi_item *find_acpi_item(const char *devname) +{ + int i; + + for (i = 0; i < item_count; i++) { + struct acpi_item *item = &acpi_item[i]; + + if (!strcmp(devname, item->dev->name)) + return item; + } + + return NULL; +} + +/** + * sort_acpi_item_type - Sort the ACPI items into the desired order + * + * This looks up the ordering in the device tree and then adds each item one by + * one into the supplied buffer + * + * @ctx: ACPI context + * @start: Start position to put the sorted items. The items will follow each + * other in sorted order + * @type: Type of items to sort + * @return 0 if OK, -ve on error + */ +static int sort_acpi_item_type(struct acpi_ctx *ctx, void *start, + enum gen_type_t type) +{ + const u32 *order; + int size; + int count; + void *ptr; + void *end = ctx->current; + + ptr = start; + order = ofnode_read_chosen_prop("u-boot,acpi-ssdt-order", &size); + if (!order) { + log_warning("Failed to find ordering, leaving as is\n"); + return 0; + } + + /* + * This algorithm rewrites the context buffer without changing its + * length. So there is no need to update ctx-current + */ + count = size / sizeof(u32); + while (count--) { + struct acpi_item *item; + const char *name; + ofnode node; + + node = ofnode_get_by_phandle(fdt32_to_cpu(*order++)); + name = ofnode_get_name(node); + item = find_acpi_item(name); + if (!item) { + log_err("Failed to find item '%s'\n", name); + return log_msg_ret("find", -ENOENT); + } + if (item->type == type) { + log_debug(" - add %s\n", item->dev->name); + memcpy(ptr, item->buf, item->size); + ptr += item->size; + } + } + + /* + * If the sort order is missing an item then the output will be too + * small. Report this error since the item needs to be added to the + * ordering for the ACPI tables to be complete. + */ + if (ptr != end) { + log_warning("*** Missing bytes: ptr=%p, end=%p\n", ptr, end); + return -ENXIO; + } + + return 0; +} + acpi_method acpi_get_method(struct udevice *dev, enum method_t method) { struct acpi_ops *aops; @@ -163,11 +242,16 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, int acpi_fill_ssdt(struct acpi_ctx *ctx) { + void *start = ctx->current; int ret; log_debug("Writing SSDT tables\n"); + item_count = 0; ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT, TYPE_SSDT); log_debug("Writing SSDT finished, err=%d\n", ret); + ret = sort_acpi_item_type(ctx, start, TYPE_SSDT); + if (ret) + return log_msg_ret("build", ret); return ret; } -- cgit v1.1