diff options
Diffstat (limited to 'drivers/misc/qfw.c')
-rw-r--r-- | drivers/misc/qfw.c | 243 |
1 files changed, 84 insertions, 159 deletions
diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c index f6eb6583ed..ea00be88a8 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -1,25 +1,22 @@ // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com> + * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee> */ +#define LOG_CATEGORY UCLASS_QFW + #include <common.h> #include <command.h> #include <errno.h> #include <log.h> #include <malloc.h> #include <qfw.h> -#include <asm/io.h> +#include <dm.h> +#include <misc.h> #ifdef CONFIG_GENERATE_ACPI_TABLE #include <asm/tables.h> #endif -#include <linux/list.h> - -static bool fwcfg_present; -static bool fwcfg_dma_present; -static struct fw_cfg_arch_ops *fwcfg_arch_ops; - -static LIST_HEAD(fw_list); #ifdef CONFIG_GENERATE_ACPI_TABLE /* @@ -32,7 +29,8 @@ static LIST_HEAD(fw_list); * be ignored. * @return: 0 on success, or negative value on failure */ -static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) +static int bios_linker_allocate(struct udevice *dev, + struct bios_linker_entry *entry, ulong *addr) { uint32_t size, align; struct fw_file *file; @@ -45,7 +43,7 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) return -EINVAL; } - file = qemu_fwcfg_find_file(entry->alloc.file); + file = qfw_find_file(dev, entry->alloc.file); if (!file) { printf("error: can't find file %s\n", entry->alloc.file); return -ENOENT; @@ -75,8 +73,8 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n", file->cfg.name, size, entry->alloc.zone, align, aligned_addr); - qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), - size, (void *)aligned_addr); + qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, + (void *)aligned_addr); file->addr = aligned_addr; /* adjust address for low memory allocation */ @@ -94,16 +92,17 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) * ACPI tables * @return: 0 on success, or negative value on failure */ -static int bios_linker_add_pointer(struct bios_linker_entry *entry) +static int bios_linker_add_pointer(struct udevice *dev, + struct bios_linker_entry *entry) { struct fw_file *dest, *src; uint32_t offset = le32_to_cpu(entry->pointer.offset); uint64_t pointer = 0; - dest = qemu_fwcfg_find_file(entry->pointer.dest_file); + dest = qfw_find_file(dev, entry->pointer.dest_file); if (!dest || !dest->addr) return -ENOENT; - src = qemu_fwcfg_find_file(entry->pointer.src_file); + src = qfw_find_file(dev, entry->pointer.src_file); if (!src || !src->addr) return -ENOENT; @@ -127,13 +126,14 @@ static int bios_linker_add_pointer(struct bios_linker_entry *entry) * checksums * @return: 0 on success, or negative value on failure */ -static int bios_linker_add_checksum(struct bios_linker_entry *entry) +static int bios_linker_add_checksum(struct udevice *dev, + struct bios_linker_entry *entry) { struct fw_file *file; uint8_t *data, cksum = 0; uint8_t *cksum_start; - file = qemu_fwcfg_find_file(entry->cksum.file); + file = qfw_find_file(dev, entry->cksum.file); if (!file || !file->addr) return -ENOENT; @@ -149,20 +149,27 @@ static int bios_linker_add_checksum(struct bios_linker_entry *entry) /* This function loads and patches ACPI tables provided by QEMU */ ulong write_acpi_tables(ulong addr) { - int i, ret = 0; + int i, ret; struct fw_file *file; struct bios_linker_entry *table_loader; struct bios_linker_entry *entry; uint32_t size; + struct udevice *dev; + + ret = qfw_get_dev(&dev); + if (ret) { + printf("error: no qfw\n"); + return addr; + } /* make sure fw_list is loaded */ - ret = qemu_fwcfg_read_firmware_list(); + ret = qfw_read_firmware_list(dev); if (ret) { printf("error: can't read firmware file list\n"); return addr; } - file = qemu_fwcfg_find_file("etc/table-loader"); + file = qfw_find_file(dev, "etc/table-loader"); if (!file) { printf("error: can't find etc/table-loader\n"); return addr; @@ -180,24 +187,23 @@ ulong write_acpi_tables(ulong addr) return addr; } - qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), - size, table_loader); + qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader); for (i = 0; i < (size / sizeof(*entry)); i++) { entry = table_loader + i; switch (le32_to_cpu(entry->command)) { case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: - ret = bios_linker_allocate(entry, &addr); + ret = bios_linker_allocate(dev, entry, &addr); if (ret) goto out; break; case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: - ret = bios_linker_add_pointer(entry); + ret = bios_linker_add_pointer(dev, entry); if (ret) goto out; break; case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: - ret = bios_linker_add_checksum(entry); + ret = bios_linker_add_checksum(dev, entry); if (ret) goto out; break; @@ -209,9 +215,9 @@ ulong write_acpi_tables(ulong addr) out: if (ret) { struct fw_cfg_file_iter iter; - for (file = qemu_fwcfg_file_iter_init(&iter); - !qemu_fwcfg_file_iter_end(&iter); - file = qemu_fwcfg_file_iter_next(&iter)) { + for (file = qfw_file_iter_init(dev, &iter); + !qfw_file_iter_end(&iter); + file = qfw_file_iter_next(&iter)) { if (file->addr) { free((void *)file->addr); file->addr = 0; @@ -225,170 +231,89 @@ out: ulong acpi_get_rsdp_addr(void) { + int ret; struct fw_file *file; + struct udevice *dev; - file = qemu_fwcfg_find_file("etc/acpi/rsdp"); + ret = qfw_get_dev(&dev); + if (ret) { + printf("error: no qfw\n"); + return 0; + } + + file = qfw_find_file(dev, "etc/acpi/rsdp"); return file->addr; } #endif -/* Read configuration item using fw_cfg PIO interface */ -static void qemu_fwcfg_read_entry_pio(uint16_t entry, - uint32_t size, void *address) +static void qfw_read_entry_io(struct qfw_dev *qdev, u16 entry, u32 size, + void *address) { - debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n", - entry, size, address); + struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev); + + debug("%s: entry 0x%x, size %u address %p\n", __func__, entry, size, + address); - return fwcfg_arch_ops->arch_read_pio(entry, size, address); + ops->read_entry_io(qdev->dev, entry, size, address); } -/* Read configuration item using fw_cfg DMA interface */ -static void qemu_fwcfg_read_entry_dma(uint16_t entry, - uint32_t size, void *address) +static void qfw_read_entry_dma(struct qfw_dev *qdev, u16 entry, u32 size, + void *address) { - struct fw_cfg_dma_access dma; + struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev); - dma.length = cpu_to_be32(size); - dma.address = cpu_to_be64((uintptr_t)address); - dma.control = cpu_to_be32(FW_CFG_DMA_READ); + struct qfw_dma dma = { + .length = cpu_to_be32(size), + .address = cpu_to_be64((uintptr_t)address), + .control = cpu_to_be32(FW_CFG_DMA_READ), + }; /* - * writting FW_CFG_INVALID will cause read operation to resume at - * last offset, otherwise read will start at offset 0 + * writing FW_CFG_INVALID will cause read operation to resume at last + * offset, otherwise read will start at offset 0 */ if (entry != FW_CFG_INVALID) dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16)); - barrier(); - - debug("qemu_fwcfg_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n", + debug("%s: entry 0x%x, size %u address %p, control 0x%x\n", __func__, entry, size, address, be32_to_cpu(dma.control)); - fwcfg_arch_ops->arch_read_dma(&dma); -} + barrier(); -bool qemu_fwcfg_present(void) -{ - return fwcfg_present; + ops->read_entry_dma(qdev->dev, &dma); } -bool qemu_fwcfg_dma_present(void) +void qfw_read_entry(struct udevice *dev, u16 entry, u32 size, void *address) { - return fwcfg_dma_present; -} + struct qfw_dev *qdev = dev_get_uclass_priv(dev); -void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address) -{ - if (fwcfg_dma_present) - qemu_fwcfg_read_entry_dma(entry, length, address); + if (qdev->dma_present) + qfw_read_entry_dma(qdev, entry, size, address); else - qemu_fwcfg_read_entry_pio(entry, length, address); + qfw_read_entry_io(qdev, entry, size, address); } -int qemu_fwcfg_online_cpus(void) +int qfw_register(struct udevice *dev) { - uint16_t nb_cpus; + struct qfw_dev *qdev = dev_get_uclass_priv(dev); + u32 qemu, dma_enabled; - if (!fwcfg_present) - return -ENODEV; - - qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus); - - return le16_to_cpu(nb_cpus); -} + qdev->dev = dev; + INIT_LIST_HEAD(&qdev->fw_list); -int qemu_fwcfg_read_firmware_list(void) -{ - int i; - uint32_t count; - struct fw_file *file; - struct list_head *entry; - - /* don't read it twice */ - if (!list_empty(&fw_list)) - return 0; + qfw_read_entry_io(qdev, FW_CFG_SIGNATURE, 4, &qemu); + if (be32_to_cpu(qemu) != QEMU_FW_CFG_SIGNATURE) + return -ENODEV; - qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count); - if (!count) - return 0; - - count = be32_to_cpu(count); - for (i = 0; i < count; i++) { - file = malloc(sizeof(*file)); - if (!file) { - printf("error: allocating resource\n"); - goto err; - } - qemu_fwcfg_read_entry(FW_CFG_INVALID, - sizeof(struct fw_cfg_file), &file->cfg); - file->addr = 0; - list_add_tail(&file->list, &fw_list); - } + qfw_read_entry_io(qdev, FW_CFG_ID, 1, &dma_enabled); + if (dma_enabled & FW_CFG_DMA_ENABLED) + qdev->dma_present = true; return 0; - -err: - list_for_each(entry, &fw_list) { - file = list_entry(entry, struct fw_file, list); - free(file); - } - - return -ENOMEM; } -struct fw_file *qemu_fwcfg_find_file(const char *name) -{ - struct list_head *entry; - struct fw_file *file; - - list_for_each(entry, &fw_list) { - file = list_entry(entry, struct fw_file, list); - if (!strcmp(file->cfg.name, name)) - return file; - } - - return NULL; -} - -struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) -{ - iter->entry = fw_list.next; - return list_entry((struct list_head *)iter->entry, - struct fw_file, list); -} - -struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) -{ - iter->entry = ((struct list_head *)iter->entry)->next; - return list_entry((struct list_head *)iter->entry, - struct fw_file, list); -} - -bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) -{ - return iter->entry == &fw_list; -} - -void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops) -{ - uint32_t qemu; - uint32_t dma_enabled; - - fwcfg_present = false; - fwcfg_dma_present = false; - fwcfg_arch_ops = NULL; - - if (!ops || !ops->arch_read_pio || !ops->arch_read_dma) - return; - fwcfg_arch_ops = ops; - - qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); - if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) - fwcfg_present = true; - - if (fwcfg_present) { - qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); - if (dma_enabled & FW_CFG_DMA_ENABLED) - fwcfg_dma_present = true; - } -} +UCLASS_DRIVER(qfw) = { + .id = UCLASS_QFW, + .name = "qfw", + .per_device_auto = sizeof(struct qfw_dev), +}; |