diff options
author | Olof Johansson <olof@lixom.net> | 2019-12-05 13:16:58 -0800 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2019-12-05 13:18:54 -0800 |
commit | 942e6f8a8314e5550e254519dfba4ccd5170421d (patch) | |
tree | 75ec655b440fbc1c454247af38b5596dd8c78de9 /drivers/firmware | |
parent | 336bab731be76a90291697e51d2aed0ad67d7cb5 (diff) | |
parent | b08baef02b26cf7c2123e4a24a2fa1fb7a593ffb (diff) |
Merge mainline/master into arm/fixes
This brings in the mainline tree right after armsoc contents was merged
this release cycle, so that we can re-run savedefconfig, etc.
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/firmware')
36 files changed, 866 insertions, 190 deletions
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c index 9cd70d1a5622..a479023fa036 100644 --- a/drivers/firmware/arm_sdei.c +++ b/drivers/firmware/arm_sdei.c @@ -967,29 +967,29 @@ static int sdei_get_conduit(struct platform_device *pdev) if (np) { if (of_property_read_string(np, "method", &method)) { pr_warn("missing \"method\" property\n"); - return CONDUIT_INVALID; + return SMCCC_CONDUIT_NONE; } if (!strcmp("hvc", method)) { sdei_firmware_call = &sdei_smccc_hvc; - return CONDUIT_HVC; + return SMCCC_CONDUIT_HVC; } else if (!strcmp("smc", method)) { sdei_firmware_call = &sdei_smccc_smc; - return CONDUIT_SMC; + return SMCCC_CONDUIT_SMC; } pr_warn("invalid \"method\" property: %s\n", method); } else if (IS_ENABLED(CONFIG_ACPI) && !acpi_disabled) { if (acpi_psci_use_hvc()) { sdei_firmware_call = &sdei_smccc_hvc; - return CONDUIT_HVC; + return SMCCC_CONDUIT_HVC; } else { sdei_firmware_call = &sdei_smccc_smc; - return CONDUIT_SMC; + return SMCCC_CONDUIT_SMC; } } - return CONDUIT_INVALID; + return SMCCC_CONDUIT_NONE; } static int sdei_probe(struct platform_device *pdev) diff --git a/drivers/firmware/broadcom/Kconfig b/drivers/firmware/broadcom/Kconfig index d03ed8e43ad7..8e3d355a637a 100644 --- a/drivers/firmware/broadcom/Kconfig +++ b/drivers/firmware/broadcom/Kconfig @@ -22,3 +22,11 @@ config BCM47XX_SPROM In case of SoC devices SPROM content is stored on a flash used by bootloader firmware CFE. This driver provides method to ssb and bcma drivers to read SPROM on SoC. + +config TEE_BNXT_FW + tristate "Broadcom BNXT firmware manager" + depends on (ARCH_BCM_IPROC && OPTEE) || (COMPILE_TEST && TEE) + default ARCH_BCM_IPROC + help + This module help to manage firmware on Broadcom BNXT device. The module + registers on tee bus and invoke calls to manage firmware on BNXT device. diff --git a/drivers/firmware/broadcom/Makefile b/drivers/firmware/broadcom/Makefile index 72c7fdc20c77..17c5061c47a7 100644 --- a/drivers/firmware/broadcom/Makefile +++ b/drivers/firmware/broadcom/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_BCM47XX_NVRAM) += bcm47xx_nvram.o obj-$(CONFIG_BCM47XX_SPROM) += bcm47xx_sprom.o +obj-$(CONFIG_TEE_BNXT_FW) += tee_bnxt_fw.o diff --git a/drivers/firmware/broadcom/tee_bnxt_fw.c b/drivers/firmware/broadcom/tee_bnxt_fw.c new file mode 100644 index 000000000000..5b7ef89eb701 --- /dev/null +++ b/drivers/firmware/broadcom/tee_bnxt_fw.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Broadcom. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sizes.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include <linux/uuid.h> + +#include <linux/firmware/broadcom/tee_bnxt_fw.h> + +#define MAX_SHM_MEM_SZ SZ_4M + +#define MAX_TEE_PARAM_ARRY_MEMB 4 + +enum ta_cmd { + /* + * TA_CMD_BNXT_FASTBOOT - boot bnxt device by copying f/w into sram + * + * param[0] unused + * param[1] unused + * param[2] unused + * param[3] unused + * + * Result: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_ITEM_NOT_FOUND - Corrupt f/w image found on memory + */ + TA_CMD_BNXT_FASTBOOT = 0, + + /* + * TA_CMD_BNXT_COPY_COREDUMP - copy the core dump into shm + * + * param[0] (inout memref) - Coredump buffer memory reference + * param[1] (in value) - value.a: offset, data to be copied from + * value.b: size of data to be copied + * param[2] unused + * param[3] unused + * + * Result: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + * TEE_ERROR_ITEM_NOT_FOUND - Corrupt core dump + */ + TA_CMD_BNXT_COPY_COREDUMP = 3, +}; + +/** + * struct tee_bnxt_fw_private - OP-TEE bnxt private data + * @dev: OP-TEE based bnxt device. + * @ctx: OP-TEE context handler. + * @session_id: TA session identifier. + */ +struct tee_bnxt_fw_private { + struct device *dev; + struct tee_context *ctx; + u32 session_id; + struct tee_shm *fw_shm_pool; +}; + +static struct tee_bnxt_fw_private pvt_data; + +static void prepare_args(int cmd, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param) +{ + memset(arg, 0, sizeof(*arg)); + memset(param, 0, MAX_TEE_PARAM_ARRY_MEMB * sizeof(*param)); + + arg->func = cmd; + arg->session = pvt_data.session_id; + arg->num_params = MAX_TEE_PARAM_ARRY_MEMB; + + /* Fill invoke cmd params */ + switch (cmd) { + case TA_CMD_BNXT_COPY_COREDUMP: + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; + param[0].u.memref.shm = pvt_data.fw_shm_pool; + param[0].u.memref.size = MAX_SHM_MEM_SZ; + param[0].u.memref.shm_offs = 0; + param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + break; + case TA_CMD_BNXT_FASTBOOT: + default: + /* Nothing to do */ + break; + } +} + +/** + * tee_bnxt_fw_load() - Load the bnxt firmware + * Uses an OP-TEE call to start a secure + * boot process. + * Returns 0 on success, negative errno otherwise. + */ +int tee_bnxt_fw_load(void) +{ + int ret = 0; + struct tee_ioctl_invoke_arg arg; + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB]; + + if (!pvt_data.ctx) + return -ENODEV; + + prepare_args(TA_CMD_BNXT_FASTBOOT, &arg, param); + + ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); + if (ret < 0 || arg.ret != 0) { + dev_err(pvt_data.dev, + "TA_CMD_BNXT_FASTBOOT invoke failed TEE err: %x, ret:%x\n", + arg.ret, ret); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(tee_bnxt_fw_load); + +/** + * tee_bnxt_copy_coredump() - Copy coredump from the allocated memory + * Uses an OP-TEE call to copy coredump + * @buf: destination buffer where core dump is copied into + * @offset: offset from the base address of core dump area + * @size: size of the dump + * + * Returns 0 on success, negative errno otherwise. + */ +int tee_bnxt_copy_coredump(void *buf, u32 offset, u32 size) +{ + struct tee_ioctl_invoke_arg arg; + struct tee_param param[MAX_TEE_PARAM_ARRY_MEMB]; + void *core_data; + u32 rbytes = size; + u32 nbytes = 0; + int ret = 0; + + if (!pvt_data.ctx) + return -ENODEV; + + prepare_args(TA_CMD_BNXT_COPY_COREDUMP, &arg, param); + + while (rbytes) { + nbytes = rbytes; + + nbytes = min_t(u32, rbytes, param[0].u.memref.size); + + /* Fill additional invoke cmd params */ + param[1].u.value.a = offset; + param[1].u.value.b = nbytes; + + ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); + if (ret < 0 || arg.ret != 0) { + dev_err(pvt_data.dev, + "TA_CMD_BNXT_COPY_COREDUMP invoke failed TEE err: %x, ret:%x\n", + arg.ret, ret); + return -EINVAL; + } + + core_data = tee_shm_get_va(pvt_data.fw_shm_pool, 0); + if (IS_ERR(core_data)) { + dev_err(pvt_data.dev, "tee_shm_get_va failed\n"); + return PTR_ERR(core_data); + } + + memcpy(buf, core_data, nbytes); + + rbytes -= nbytes; + buf += nbytes; + offset += nbytes; + } + + return 0; +} +EXPORT_SYMBOL(tee_bnxt_copy_coredump); + +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) +{ + return (ver->impl_id == TEE_IMPL_ID_OPTEE); +} + +static int tee_bnxt_fw_probe(struct device *dev) +{ + struct tee_client_device *bnxt_device = to_tee_client_device(dev); + int ret, err = -ENODEV; + struct tee_ioctl_open_session_arg sess_arg; + struct tee_shm *fw_shm_pool; + + memset(&sess_arg, 0, sizeof(sess_arg)); + + /* Open context with TEE driver */ + pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, + NULL); + if (IS_ERR(pvt_data.ctx)) + return -ENODEV; + + /* Open session with Bnxt load Trusted App */ + memcpy(sess_arg.uuid, bnxt_device->id.uuid.b, TEE_IOCTL_UUID_LEN); + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; + sess_arg.num_params = 0; + + ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL); + if (ret < 0 || sess_arg.ret != 0) { + dev_err(dev, "tee_client_open_session failed, err: %x\n", + sess_arg.ret); + err = -EINVAL; + goto out_ctx; + } + pvt_data.session_id = sess_arg.session; + + pvt_data.dev = dev; + + fw_shm_pool = tee_shm_alloc(pvt_data.ctx, MAX_SHM_MEM_SZ, + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(fw_shm_pool)) { + tee_client_close_context(pvt_data.ctx); + dev_err(pvt_data.dev, "tee_shm_alloc failed\n"); + err = PTR_ERR(fw_shm_pool); + goto out_sess; + } + + pvt_data.fw_shm_pool = fw_shm_pool; + + return 0; + +out_sess: + tee_client_close_session(pvt_data.ctx, pvt_data.session_id); +out_ctx: + tee_client_close_context(pvt_data.ctx); + + return err; +} + +static int tee_bnxt_fw_remove(struct device *dev) +{ + tee_shm_free(pvt_data.fw_shm_pool); + tee_client_close_session(pvt_data.ctx, pvt_data.session_id); + tee_client_close_context(pvt_data.ctx); + pvt_data.ctx = NULL; + + return 0; +} + +static const struct tee_client_device_id tee_bnxt_fw_id_table[] = { + {UUID_INIT(0x6272636D, 0x2019, 0x0716, + 0x42, 0x43, 0x4D, 0x5F, 0x53, 0x43, 0x48, 0x49)}, + {} +}; + +MODULE_DEVICE_TABLE(tee, tee_bnxt_fw_id_table); + +static struct tee_client_driver tee_bnxt_fw_driver = { + .id_table = tee_bnxt_fw_id_table, + .driver = { + .name = KBUILD_MODNAME, + .bus = &tee_bus_type, + .probe = tee_bnxt_fw_probe, + .remove = tee_bnxt_fw_remove, + }, +}; + +static int __init tee_bnxt_fw_mod_init(void) +{ + return driver_register(&tee_bnxt_fw_driver.driver); +} + +static void __exit tee_bnxt_fw_mod_exit(void) +{ + driver_unregister(&tee_bnxt_fw_driver.driver); +} + +module_init(tee_bnxt_fw_mod_init); +module_exit(tee_bnxt_fw_mod_exit); + +MODULE_AUTHOR("Vikas Gupta <vikas.gupta@broadcom.com>"); +MODULE_DESCRIPTION("Broadcom bnxt firmware manager"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 35ed56b9c34f..2045566d622f 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -35,6 +35,7 @@ static struct dmi_memdev_info { const char *bank; u64 size; /* bytes */ u16 handle; + u8 type; /* DDR2, DDR3, DDR4 etc */ } *dmi_memdev; static int dmi_memdev_nr; @@ -391,7 +392,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v) u64 bytes; u16 size; - if (dm->type != DMI_ENTRY_MEM_DEVICE || dm->length < 0x12) + if (dm->type != DMI_ENTRY_MEM_DEVICE || dm->length < 0x13) return; if (nr >= dmi_memdev_nr) { pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n"); @@ -400,6 +401,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v) dmi_memdev[nr].handle = get_unaligned(&dm->handle); dmi_memdev[nr].device = dmi_string(dm, d[0x10]); dmi_memdev[nr].bank = dmi_string(dm, d[0x11]); + dmi_memdev[nr].type = d[0x12]; size = get_unaligned((u16 *)&d[0xC]); if (size == 0) @@ -408,7 +410,7 @@ static void __init save_mem_devices(const struct dmi_header *dm, void *v) bytes = ~0ull; else if (size & 0x8000) bytes = (u64)(size & 0x7fff) << 10; - else if (size != 0x7fff) + else if (size != 0x7fff || dm->length < 0x20) bytes = (u64)size << 20; else bytes = (u64)get_unaligned((u32 *)&d[0x1C]) << 20; @@ -1128,3 +1130,40 @@ u64 dmi_memdev_size(u16 handle) return ~0ull; } EXPORT_SYMBOL_GPL(dmi_memdev_size); + +/** + * dmi_memdev_type - get the memory type + * @handle: DMI structure handle + * + * Return the DMI memory type of the module in the slot associated with the + * given DMI handle, or 0x0 if no such DMI handle exists. + */ +u8 dmi_memdev_type(u16 handle) +{ + int n; + + if (dmi_memdev) { + for (n = 0; n < dmi_memdev_nr; n++) { + if (handle == dmi_memdev[n].handle) + return dmi_memdev[n].type; + } + } + return 0x0; /* Not a valid value */ +} +EXPORT_SYMBOL_GPL(dmi_memdev_type); + +/** + * dmi_memdev_handle - get the DMI handle of a memory slot + * @slot: slot number + * + * Return the DMI handle associated with a given memory slot, or %0xFFFF + * if there is no such slot. + */ +u16 dmi_memdev_handle(int slot) +{ + if (dmi_memdev && slot >= 0 && slot < dmi_memdev_nr) + return dmi_memdev[slot].handle; + + return 0xffff; /* Not a valid value */ +} +EXPORT_SYMBOL_GPL(dmi_memdev_handle); diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 178ee8106828..bcc378c19ebe 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -75,6 +75,27 @@ config EFI_MAX_FAKE_MEM Ranges can be set up to this value using comma-separated list. The default value is 8. +config EFI_SOFT_RESERVE + bool "Reserve EFI Specific Purpose Memory" + depends on EFI && EFI_STUB && ACPI_HMAT + default ACPI_HMAT + help + On systems that have mixed performance classes of memory EFI + may indicate specific purpose memory with an attribute (See + EFI_MEMORY_SP in UEFI 2.8). A memory range tagged with this + attribute may have unique performance characteristics compared + to the system's general purpose "System RAM" pool. On the + expectation that such memory has application specific usage, + and its base EFI memory type is "conventional" answer Y to + arrange for the kernel to reserve it as a "Soft Reserved" + resource, and set aside for direct-access (device-dax) by + default. The memory range can later be optionally assigned to + the page allocator by system administrator policy via the + device-dax kmem facility. Say N to have the kernel treat this + memory as "System RAM" by default. + + If unsure, say Y. + config EFI_PARAMS_FROM_FDT bool help @@ -182,6 +203,7 @@ config RESET_ATTACK_MITIGATION config EFI_RCI2_TABLE bool "EFI Runtime Configuration Interface Table Version 2 Support" + depends on X86 || COMPILE_TEST help Displays the content of the Runtime Configuration Interface Table version 2 on Dell EMC PowerEdge systems as a binary diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 4ac2de4dfa72..554d795270d9 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -20,13 +20,16 @@ obj-$(CONFIG_UEFI_CPER) += cper.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o obj-$(CONFIG_EFI_STUB) += libstub/ -obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o +obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_map.o obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o obj-$(CONFIG_EFI_TEST) += test/ obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o +fake_map-y += fake_mem.o +fake_map-$(CONFIG_X86) += x86_fake_mem.o + arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o obj-$(CONFIG_ARM) += $(arm-obj-y) obj-$(CONFIG_ARM64) += $(arm-obj-y) diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index 0e206c9e0d7a..5ccf39986a14 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c @@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, for (i = 0; i < dev_header->prop_count; i++) { int remaining = dev_header->len - (ptr - (void *)dev_header); - u32 key_len, val_len; + u32 key_len, val_len, entry_len; + const u8 *entry_data; char *key; if (sizeof(key_len) > remaining) @@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, ucs2_as_utf8(key, ptr + sizeof(key_len), key_len - sizeof(key_len)); - entry[i].name = key; - entry[i].length = val_len - sizeof(val_len); - entry[i].is_array = !!entry[i].length; - entry[i].type = DEV_PROP_U8; - entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len); - + entry_data = ptr + key_len + sizeof(val_len); + entry_len = val_len - sizeof(val_len); + entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data, + entry_len); if (dump_properties) { - dev_info(dev, "property: %s\n", entry[i].name); + dev_info(dev, "property: %s\n", key); print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, - 16, 1, entry[i].pointer.u8_data, - entry[i].length, true); + 16, 1, entry_data, entry_len, true); } ptr += key_len + val_len; diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 311cd349a862..904fa09e6a6b 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -164,6 +164,15 @@ static __init int is_usable_memory(efi_memory_desc_t *md) case EFI_CONVENTIONAL_MEMORY: case EFI_PERSISTENT_MEMORY: /* + * Special purpose memory is 'soft reserved', which means it + * is set aside initially, but can be hotplugged back in or + * be assigned to the dax driver after boot. + */ + if (efi_soft_reserve_enabled() && + (md->attribute & EFI_MEMORY_SP)) + return false; + + /* * According to the spec, these regions are no longer reserved * after calling ExitBootServices(). However, we can only use * them as System RAM if they can be mapped writeback cacheable. diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index e2ac5fa5531b..899b803842bb 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -121,6 +121,30 @@ static int __init arm_enable_runtime_services(void) return 0; } + if (efi_soft_reserve_enabled()) { + efi_memory_desc_t *md; + + for_each_efi_memory_desc(md) { + int md_size = md->num_pages << EFI_PAGE_SHIFT; + struct resource *res; + + if (!(md->attribute & EFI_MEMORY_SP)) + continue; + + res = kzalloc(sizeof(*res), GFP_KERNEL); + if (WARN_ON(!res)) + break; + + res->start = md->phys_addr; + res->end = md->phys_addr + md_size - 1; + res->name = "Soft Reserved"; + res->flags = IORESOURCE_MEM; + res->desc = IORES_DESC_SOFT_RESERVED; + + insert_resource(&iomem_resource, res); + } + } + if (efi_runtime_disabled()) { pr_info("EFI runtime services will be disabled.\n"); return 0; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 69f00f7453a3..d101f072c8f8 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -81,6 +81,11 @@ bool efi_runtime_disabled(void) return disable_runtime; } +bool __pure __efi_soft_reserve_enabled(void) +{ + return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE); +} + static int __init parse_efi_cmdline(char *str) { if (!str) { @@ -94,6 +99,9 @@ static int __init parse_efi_cmdline(char *str) if (parse_option_str(str, "noruntime")) disable_runtime = true; + if (parse_option_str(str, "nosoftreserve")) + set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags); + return 0; } early_param("efi", parse_efi_cmdline); @@ -296,7 +304,7 @@ static __init int efivar_ssdt_load(void) goto free_data; } - ret = acpi_load_table(data); + ret = acpi_load_table(data, NULL); if (ret) { pr_err("failed to load table: %d\n", ret); goto free_data; @@ -554,7 +562,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, sizeof(*seed) + size); if (seed != NULL) { pr_notice("seeding entropy pool\n"); - add_device_randomness(seed->bits, seed->size); + add_bootloader_randomness(seed->bits, seed->size); early_memunmap(seed, sizeof(*seed) + size); } else { pr_err("Could not map UEFI random seed!\n"); @@ -842,15 +850,16 @@ char * __init efi_md_typeattr_format(char *buf, size_t size, if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO | EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP | - EFI_MEMORY_NV | + EFI_MEMORY_NV | EFI_MEMORY_SP | EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE)) snprintf(pos, size, "|attr=0x%016llx]", (unsigned long long)attr); else snprintf(pos, size, - "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", + "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", attr & EFI_MEMORY_RUNTIME ? "RUN" : "", attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "", + attr & EFI_MEMORY_SP ? "SP" : "", attr & EFI_MEMORY_NV ? "NV" : "", attr & EFI_MEMORY_XP ? "XP" : "", attr & EFI_MEMORY_RP ? "RP" : "", diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index d6dd5f503fa2..2762e0662bf4 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -246,6 +246,9 @@ void __init efi_esrt_init(void) int rc; phys_addr_t end; + if (!efi_enabled(EFI_MEMMAP)) + return; + pr_debug("esrt-init: loading.\n"); if (!esrt_table_exists()) return; diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c index 9501edc0fcfb..bb9fc70d0cfa 100644 --- a/drivers/firmware/efi/fake_mem.c +++ b/drivers/firmware/efi/fake_mem.c @@ -17,12 +17,10 @@ #include <linux/memblock.h> #include <linux/types.h> #include <linux/sort.h> -#include <asm/efi.h> +#include "fake_mem.h" -#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM - -static struct efi_mem_range fake_mems[EFI_MAX_FAKEMEM]; -static int nr_fake_mem; +struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; +int nr_fake_mem; static int __init cmp_fake_mem(const void *x1, const void *x2) { @@ -44,13 +42,13 @@ void __init efi_fake_memmap(void) void *new_memmap; int i; - if (!nr_fake_mem) + if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem) return; /* count up the number of EFI memory descriptor */ for (i = 0; i < nr_fake_mem; i++) { for_each_efi_memory_desc(md) { - struct range *r = &fake_mems[i].range; + struct range *r = &efi_fake_mems[i].range; new_nr_map += efi_memmap_split_count(md, r); } @@ -70,7 +68,7 @@ void __init efi_fake_memmap(void) } for (i = 0; i < nr_fake_mem; i++) - efi_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]); + efi_memmap_insert(&efi.memmap, new_memmap, &efi_fake_mems[i]); /* swap into new EFI memmap */ early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map); @@ -104,22 +102,22 @@ static int __init setup_fake_mem(char *p) if (nr_fake_mem >= EFI_MAX_FAKEMEM) break; - fake_mems[nr_fake_mem].range.start = start; - fake_mems[nr_fake_mem].range.end = start + mem_size - 1; - fake_mems[nr_fake_mem].attribute = attribute; + efi_fake_mems[nr_fake_mem].range.start = start; + efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1; + efi_fake_mems[nr_fake_mem].attribute = attribute; nr_fake_mem++; if (*p == ',') p++; } - sort(fake_mems, nr_fake_mem, sizeof(struct efi_mem_range), + sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range), cmp_fake_mem, NULL); for (i = 0; i < nr_fake_mem; i++) pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]", - fake_mems[i].attribute, fake_mems[i].range.start, - fake_mems[i].range.end); + efi_fake_mems[i].attribute, efi_fake_mems[i].range.start, + efi_fake_mems[i].range.end); return *p == '\0' ? 0 : -EINVAL; } diff --git a/drivers/firmware/efi/fake_mem.h b/drivers/firmware/efi/fake_mem.h new file mode 100644 index 000000000000..d52791af4b18 --- /dev/null +++ b/drivers/firmware/efi/fake_mem.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __EFI_FAKE_MEM_H__ +#define __EFI_FAKE_MEM_H__ +#include <asm/efi.h> + +#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM + +extern struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; +extern int nr_fake_mem; +#endif /* __EFI_FAKE_MEM_H__ */ diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 0460c7581220..c35f893897e1 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -38,7 +38,8 @@ OBJECT_FILES_NON_STANDARD := y # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. KCOV_INSTRUMENT := n -lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o +lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ + random.o # include the stub's generic dependencies from lib/ when building for ARM/arm64 arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c @@ -47,11 +48,12 @@ arm-deps-$(CONFIG_ARM64) += sort.c $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(call if_changed_rule,cc_o_c) -lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o random.o \ +lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ $(patsubst %.c,lib-%.o,$(arm-deps-y)) lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o +CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index c382a48c6678..817237ce2420 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -189,6 +189,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail_free_cmdline; } + efi_retrieve_tpm2_eventlog(sys_table); + /* Ask the firmware to clear memory on unclean shutdown */ efi_enable_reset_attack_mitigation(sys_table); diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index e8f7aefb6813..4566640de650 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -146,6 +146,11 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg, continue; case EFI_CONVENTIONAL_MEMORY: + /* Skip soft reserved conventional memory */ + if (efi_soft_reserve_enabled() && + (desc->attribute & EFI_MEMORY_SP)) + continue; + /* * Reserve the intersection between this entry and the * region. @@ -195,6 +200,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, unsigned long dram_base, efi_loaded_image_t *image) { + unsigned long kernel_base; efi_status_t status; /* @@ -204,9 +210,18 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, * loaded. These assumptions are made by the decompressor, * before any memory map is available. */ - dram_base = round_up(dram_base, SZ_128M); + kernel_base = round_up(dram_base, SZ_128M); + + /* + * Note that some platforms (notably, the Raspberry Pi 2) put + * spin-tables and other pieces of firmware at the base of RAM, + * abusing the fact that the window of TEXT_OFFSET bytes at the + * base of the kernel image is only partially used at the moment. + * (Up to 5 pages are used for the swapper page tables) + */ + kernel_base += TEXT_OFFSET - 5 * PAGE_SIZE; - status = reserve_kernel_base(sys_table, dram_base, reserve_addr, + status = reserve_kernel_base(sys_table, kernel_base, reserve_addr, reserve_size); if (status != EFI_SUCCESS) { pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n"); @@ -220,7 +235,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, *image_size = image->image_size; status = efi_relocate_kernel(sys_table, image_addr, *image_size, *image_size, - dram_base + MAX_UNCOMP_KERNEL_SIZE, 0); + kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0); if (status != EFI_SUCCESS) { pr_efi_err(sys_table, "Failed to relocate kernel.\n"); efi_free(sys_table, *reserve_size, *reserve_addr); diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 3caae7f2cf56..e02579907f2e 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,6 +32,7 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; static int __section(.data) __nokaslr; static int __section(.data) __quiet; static int __section(.data) __novamap; +static bool __section(.data) efi_nosoftreserve; int __pure nokaslr(void) { @@ -45,6 +46,10 @@ int __pure novamap(void) { return __novamap; } +bool __pure __efi_soft_reserve_enabled(void) +{ + return !efi_nosoftreserve; +} #define EFI_MMAP_NR_SLACK_SLOTS 8 @@ -211,6 +216,10 @@ again: if (desc->type != EFI_CONVENTIONAL_MEMORY) continue; + if (efi_soft_reserve_enabled() && + (desc->attribute & EFI_MEMORY_SP)) + continue; + if (desc->num_pages < nr_pages) continue; @@ -260,11 +269,11 @@ fail: } /* - * Allocate at the lowest possible address. + * Allocate at the lowest possible address that is not below 'min'. */ -efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, unsigned long align, - unsigned long *addr) +efi_status_t efi_low_alloc_above(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr, unsigned long min) { unsigned long map_size, desc_size, buff_size; efi_memory_desc_t *map; @@ -305,19 +314,18 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, if (desc->type != EFI_CONVENTIONAL_MEMORY) continue; + if (efi_soft_reserve_enabled() && + (desc->attribute & EFI_MEMORY_SP)) + continue; + if (desc->num_pages < nr_pages) continue; start = desc->phys_addr; end = start + desc->num_pages * EFI_PAGE_SIZE; - /* - * Don't allocate at 0x0. It will confuse code that - * checks pointers against NULL. Skip the first 8 - * bytes so we start at a nice even number. - */ - if (start == 0x0) - start += 8; + if (start < min) + start = min; start = round_up(start, align); if ((start + size) > end) @@ -489,6 +497,12 @@ efi_status_t efi_parse_options(char const *cmdline) __novamap = 1; } + if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) && + !strncmp(str, "nosoftreserve", 7)) { + str += strlen("nosoftreserve"); + efi_nosoftreserve = 1; + } + /* Group words together, delimited by "," */ while (*str && *str != ' ' && *str != ',') str++; @@ -698,7 +712,8 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, unsigned long image_size, unsigned long alloc_size, unsigned long preferred_addr, - unsigned long alignment) + unsigned long alignment, + unsigned long min_addr) { unsigned long cur_image_addr; unsigned long new_addr = 0; @@ -731,8 +746,8 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, * possible. */ if (status != EFI_SUCCESS) { - status = efi_low_alloc(sys_table_arg, alloc_size, alignment, - &new_addr); + status = efi_low_alloc_above(sys_table_arg, alloc_size, + alignment, &new_addr, min_addr); } if (status != EFI_SUCCESS) { pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n"); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 7f1556fd867d..05739ae013c8 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -63,8 +63,6 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); -efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); - void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid); /* Helper macros for the usual case of using simple C variables: */ diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index b4b1d1dcb5fd..35edd7cfb6a1 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c @@ -9,6 +9,18 @@ #include "efistub.h" +typedef struct efi_rng_protocol efi_rng_protocol_t; + +typedef struct { + u32 get_info; + u32 get_rng; +} efi_rng_protocol_32_t; + +typedef struct { + u64 get_info; + u64 get_rng; +} efi_rng_protocol_64_t; + struct efi_rng_protocol { efi_status_t (*get_info)(struct efi_rng_protocol *, unsigned long *, efi_guid_t *); @@ -28,7 +40,7 @@ efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg, if (status != EFI_SUCCESS) return status; - return rng->get_rng(rng, NULL, size, out); + return efi_call_proto(efi_rng_protocol, get_rng, rng, NULL, size, out); } /* @@ -46,6 +58,10 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md, if (md->type != EFI_CONVENTIONAL_MEMORY) return 0; + if (efi_soft_reserve_enabled() && + (md->attribute & EFI_MEMORY_SP)) + return 0; + region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1); first_slot = round_up(md->phys_addr, align); @@ -161,15 +177,16 @@ efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg) if (status != EFI_SUCCESS) return status; - status = rng->get_rng(rng, &rng_algo_raw, EFI_RANDOM_SEED_SIZE, - seed->bits); + status = efi_call_proto(efi_rng_protocol, get_rng, rng, &rng_algo_raw, + EFI_RANDOM_SEED_SIZE, seed->bits); + if (status == EFI_UNSUPPORTED) /* * Use whatever algorithm we have available if the raw algorithm * is not implemented. */ - status = rng->get_rng(rng, NULL, EFI_RANDOM_SEED_SIZE, - seed->bits); + status = efi_call_proto(efi_rng_protocol, get_rng, rng, NULL, + EFI_RANDOM_SEED_SIZE, seed->bits); if (status != EFI_SUCCESS) goto err_freepool; diff --git a/drivers/firmware/efi/test/efi_test.c b/drivers/firmware/efi/test/efi_test.c index 877745c3aaf2..7baf48c01e72 100644 --- a/drivers/firmware/efi/test/efi_test.c +++ b/drivers/firmware/efi/test/efi_test.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/efi.h> +#include <linux/security.h> #include <linux/slab.h> #include <linux/uaccess.h> @@ -717,6 +718,13 @@ static long efi_test_ioctl(struct file *file, unsigned int cmd, static int efi_test_open(struct inode *inode, struct file *file) { + int ret = security_locked_down(LOCKDOWN_EFI_TEST); + + if (ret) + return ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; /* * nothing special to do here * We do accept multiple open files at the same time as we diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c index ebd7977653a8..31f9f0e369b9 100644 --- a/drivers/firmware/efi/tpm.c +++ b/drivers/firmware/efi/tpm.c @@ -88,6 +88,7 @@ int __init efi_tpm_eventlog_init(void) if (tbl_size < 0) { pr_err(FW_BUG "Failed to parse event in TPM Final Events Log\n"); + ret = -EINVAL; goto out_calc; } diff --git a/drivers/firmware/efi/x86_fake_mem.c b/drivers/firmware/efi/x86_fake_mem.c new file mode 100644 index 000000000000..e5d6d5a1b240 --- /dev/null +++ b/drivers/firmware/efi/x86_fake_mem.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2019 Intel Corporation. All rights reserved. */ +#include <linux/efi.h> +#include <asm/e820/api.h> +#include "fake_mem.h" + +void __init efi_fake_memmap_early(void) +{ + int i; + + /* + * The late efi_fake_mem() call can handle all requests if + * EFI_MEMORY_SP support is disabled. + */ + if (!efi_soft_reserve_enabled()) + return; + + if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem) + return; + + /* + * Given that efi_fake_memmap() needs to perform memblock + * allocations it needs to run after e820__memblock_setup(). + * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given + * address range that potentially needs to mark the memory as + * reserved prior to e820__memblock_setup(). Update e820 + * directly if EFI_MEMORY_SP is specified for an + * EFI_CONVENTIONAL_MEMORY descriptor. + */ + for (i = 0; i < nr_fake_mem; i++) { + struct efi_mem_range *mem = &efi_fake_mems[i]; + efi_memory_desc_t *md; + u64 m_start, m_end; + + if ((mem->attribute & EFI_MEMORY_SP) == 0) + continue; + + m_start = mem->range.start; + m_end = mem->range.end; + for_each_efi_memory_desc(md) { + u64 start, end; + + if (md->type != EFI_CONVENTIONAL_MEMORY) + continue; + + start = md->phys_addr; + end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; + + if (m_start <= end && m_end >= start) + /* fake range overlaps descriptor */; + else + continue; + + /* + * Trim the boundary of the e820 update to the + * descriptor in case the fake range overlaps + * !EFI_CONVENTIONAL_MEMORY + */ + start = max(start, m_start); + end = min(end, m_end); + + if (end <= start) + continue; + e820__range_update(start, end - start + 1, E820_TYPE_RAM, + E820_TYPE_SOFT_RESERVED); + e820__update_table(e820_table); + } + } +} diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c index a43d2db5cbdb..4265e9dbed84 100644 --- a/drivers/firmware/imx/imx-dsp.c +++ b/drivers/firmware/imx/imx-dsp.c @@ -114,7 +114,7 @@ static int imx_dsp_probe(struct platform_device *pdev) dev_info(dev, "NXP i.MX DSP IPC initialized\n"); - return devm_of_platform_populate(dev); + return 0; out: kfree(chan_name); for (j = 0; j < i; j++) { diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 687121f8c4d5..db655e87cdc8 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -8,6 +8,7 @@ #include <dt-bindings/firmware/imx/rsrc.h> #include <linux/firmware/imx/ipc.h> +#include <linux/firmware/imx/sci.h> #include <linux/mailbox_client.h> #define IMX_SC_IRQ_FUNC_ENABLE 1 diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 04a24a863d6e..03b43b7a6d1d 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -107,6 +107,12 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg) struct imx_sc_rpc_msg *hdr; u32 *data = msg; + if (!sc_ipc->msg) { + dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n", + sc_chan->idx, *data); + return; + } + if (sc_chan->idx == 0) { hdr = msg; sc_ipc->rx_size = hdr->size; @@ -156,6 +162,7 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg) */ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) { + uint8_t saved_svc, saved_func; struct imx_sc_rpc_msg *hdr; int ret; @@ -165,7 +172,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) mutex_lock(&sc_ipc->lock); reinit_completion(&sc_ipc->done); - sc_ipc->msg = msg; + if (have_resp) { + sc_ipc->msg = msg; + saved_svc = ((struct imx_sc_rpc_msg *)msg)->svc; + saved_func = ((struct imx_sc_rpc_msg *)msg)->func; + } sc_ipc->count = 0; ret = imx_scu_ipc_write(sc_ipc, msg); if (ret < 0) { @@ -184,9 +195,20 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) /* response status is stored in hdr->func field */ hdr = msg; ret = hdr->func; + /* + * Some special SCU firmware APIs do NOT have return value + * in hdr->func, but they do have response data, those special + * APIs are defined as void function in SCU firmware, so they + * should be treated as return success always. + */ + if ((saved_svc == IMX_SC_RPC_SVC_MISC) && + (saved_func == IMX_SC_MISC_FUNC_UNIQUE_ID || + saved_func == IMX_SC_MISC_FUNC_GET_BUTTON_STATUS)) + ret = 0; } out: + sc_ipc->msg = NULL; mutex_unlock(&sc_ipc->lock); dev_dbg(sc_ipc->dev, "RPC SVC done\n"); diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index 8d908a8e0d20..1d5b4d74f96d 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -35,7 +35,7 @@ struct meson_sm_chip { struct meson_sm_cmd cmd[]; }; -struct meson_sm_chip gxbb_chip = { +static const struct meson_sm_chip gxbb_chip = { .shmem_size = SZ_4K, .cmd_shmem_in_base = 0x82000020, .cmd_shmem_out_base = 0x82000021, @@ -54,8 +54,6 @@ struct meson_sm_firmware { void __iomem *sm_shmem_out_base; }; -static struct meson_sm_firmware fw; - static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip, unsigned int cmd_index) { @@ -90,6 +88,7 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size) /** * meson_sm_call - generic SMC32 call to the secure-monitor * + * @fw: Pointer to secure-monitor firmware * @cmd_index: Index of the SMC32 function ID * @ret: Returned value * @arg0: SMC32 Argument 0 @@ -100,15 +99,15 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size) * * Return: 0 on success, a negative value on error */ -int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, - u32 arg1, u32 arg2, u32 arg3, u32 arg4) +int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index, + u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { u32 cmd, lret; - if (!fw.chip) + if (!fw->chip) return -ENOENT; - cmd = meson_sm_get_cmd(fw.chip, cmd_index); + cmd = meson_sm_get_cmd(fw->chip, cmd_index); if (!cmd) return -EINVAL; @@ -124,6 +123,7 @@ EXPORT_SYMBOL(meson_sm_call); /** * meson_sm_call_read - retrieve data from secure-monitor * + * @fw: Pointer to secure-monitor firmware * @buffer: Buffer to store the retrieved data * @bsize: Size of the buffer * @cmd_index: Index of the SMC32 function ID @@ -137,22 +137,23 @@ EXPORT_SYMBOL(meson_sm_call); * When 0 is returned there is no guarantee about the amount of * data read and bsize bytes are copied in buffer. */ -int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index, - u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) +int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer, + unsigned int bsize, unsigned int cmd_index, u32 arg0, + u32 arg1, u32 arg2, u32 arg3, u32 arg4) { u32 size; int ret; - if (!fw.chip) + if (!fw->chip) return -ENOENT; - if (!fw.chip->cmd_shmem_out_base) + if (!fw->chip->cmd_shmem_out_base) return -EINVAL; - if (bsize > fw.chip->shmem_size) + if (bsize > fw->chip->shmem_size) return -EINVAL; - if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) + if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) return -EINVAL; if (size > bsize) @@ -164,7 +165,7 @@ int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index, size = bsize; if (buffer) - memcpy(buffer, fw.sm_shmem_out_base, size); + memcpy(buffer, fw->sm_shmem_out_base, size); return ret; } @@ -173,6 +174,7 @@ EXPORT_SYMBOL(meson_sm_call_read); /** * meson_sm_call_write - send data to secure-monitor * + * @fw: Pointer to secure-monitor firmware * @buffer: Buffer containing data to send * @size: Size of the data to send * @cmd_index: Index of the SMC32 function ID @@ -184,23 +186,24 @@ EXPORT_SYMBOL(meson_sm_call_read); * * Return: size of sent data on success, a negative value on error */ -int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index, - u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) +int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer, + unsigned int size, unsigned int cmd_index, u32 arg0, + u32 arg1, u32 arg2, u32 arg3, u32 arg4) { u32 written; - if (!fw.chip) + if (!fw->chip) return -ENOENT; - if (size > fw.chip->shmem_size) + if (size > fw->chip->shmem_size) return -EINVAL; - if (!fw.chip->cmd_shmem_in_base) + if (!fw->chip->cmd_shmem_in_base) return -EINVAL; - memcpy(fw.sm_shmem_in_base, buffer, size); + memcpy(fw->sm_shmem_in_base, buffer, size); - if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0) + if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0) return -EINVAL; if (!written) @@ -210,6 +213,24 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index, } EXPORT_SYMBOL(meson_sm_call_write); +/** + * meson_sm_get - get pointer to meson_sm_firmware structure. + * + * @sm_node: Pointer to the secure-monitor Device Tree node. + * + * Return: NULL is the secure-monitor device is not ready. + */ +struct meson_sm_firmware *meson_sm_get(struct device_node *sm_node) +{ + struct platform_device *pdev = of_find_device_by_node(sm_node); + + if (!pdev) + return NULL; + + return platform_get_drvdata(pdev); +} +EXPORT_SYMBOL_GPL(meson_sm_get); + #define SM_CHIP_ID_LENGTH 119 #define SM_CHIP_ID_OFFSET 4 #define SM_CHIP_ID_SIZE 12 @@ -217,33 +238,25 @@ EXPORT_SYMBOL(meson_sm_call_write); static ssize_t serial_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct platform_device *pdev = to_platform_device(dev); + struct meson_sm_firmware *fw; uint8_t *id_buf; int ret; + fw = platform_get_drvdata(pdev); + id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL); if (!id_buf) return -ENOMEM; - ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID, + ret = meson_sm_call_read(fw, id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID, 0, 0, 0, 0, 0); if (ret < 0) { kfree(id_buf); return ret; } - ret = sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", - id_buf[SM_CHIP_ID_OFFSET + 0], - id_buf[SM_CHIP_ID_OFFSET + 1], - id_buf[SM_CHIP_ID_OFFSET + 2], - id_buf[SM_CHIP_ID_OFFSET + 3], - id_buf[SM_CHIP_ID_OFFSET + 4], - id_buf[SM_CHIP_ID_OFFSET + 5], - id_buf[SM_CHIP_ID_OFFSET + 6], - id_buf[SM_CHIP_ID_OFFSET + 7], - id_buf[SM_CHIP_ID_OFFSET + 8], - id_buf[SM_CHIP_ID_OFFSET + 9], - id_buf[SM_CHIP_ID_OFFSET + 10], - id_buf[SM_CHIP_ID_OFFSET + 11]); + ret = sprintf(buf, "%12phN\n", &id_buf[SM_CHIP_ID_OFFSET]); kfree(id_buf); @@ -268,25 +281,34 @@ static const struct of_device_id meson_sm_ids[] = { static int __init meson_sm_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; const struct meson_sm_chip *chip; + struct meson_sm_firmware *fw; + + fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); + if (!fw) + return -ENOMEM; - chip = of_match_device(meson_sm_ids, &pdev->dev)->data; + chip = of_match_device(meson_sm_ids, dev)->data; if (chip->cmd_shmem_in_base) { - fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base, - chip->shmem_size); - if (WARN_ON(!fw.sm_shmem_in_base)) + fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base, + chip->shmem_size); + if (WARN_ON(!fw->sm_shmem_in_base)) goto out; } if (chip->cmd_shmem_out_base) { - fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base, - chip->shmem_size); - if (WARN_ON(!fw.sm_shmem_out_base)) + fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base, + chip->shmem_size); + if (WARN_ON(!fw->sm_shmem_out_base)) goto out_in_base; } - fw.chip = chip; + fw->chip = chip; + + platform_set_drvdata(pdev, fw); + pr_info("secure-monitor enabled\n"); if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group)) @@ -295,7 +317,7 @@ static int __init meson_sm_probe(struct platform_device *pdev) return 0; out_in_base: - iounmap(fw.sm_shmem_in_base); + iounmap(fw->sm_shmem_in_base); out: return -EINVAL; } diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index 84f4ff351c62..b3b6c15e7b36 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -53,10 +53,18 @@ bool psci_tos_resident_on(int cpu) } struct psci_operations psci_ops = { - .conduit = PSCI_CONDUIT_NONE, + .conduit = SMCCC_CONDUIT_NONE, .smccc_version = SMCCC_VERSION_1_0, }; +enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) +{ + if (psci_ops.smccc_version < SMCCC_VERSION_1_1) + return SMCCC_CONDUIT_NONE; + + return psci_ops.conduit; +} + typedef unsigned long (psci_fn)(unsigned long, unsigned long, unsigned long, unsigned long); static psci_fn *invoke_psci_fn; @@ -212,13 +220,13 @@ static unsigned long psci_migrate_info_up_cpu(void) 0, 0, 0); } -static void set_conduit(enum psci_conduit conduit) +static void set_conduit(enum arm_smccc_conduit conduit) { switch (conduit) { - case PSCI_CONDUIT_HVC: + case SMCCC_CONDUIT_HVC: invoke_psci_fn = __invoke_psci_fn_hvc; break; - case PSCI_CONDUIT_SMC: + case SMCCC_CONDUIT_SMC: invoke_psci_fn = __invoke_psci_fn_smc; break; default: @@ -240,9 +248,9 @@ static int get_set_conduit_method(struct device_node *np) } if (!strcmp("hvc", method)) { - set_conduit(PSCI_CONDUIT_HVC); + set_conduit(SMCCC_CONDUIT_HVC); } else if (!strcmp("smc", method)) { - set_conduit(PSCI_CONDUIT_SMC); + set_conduit(SMCCC_CONDUIT_SMC); } else { pr_warn("invalid \"method\" property: %s\n", method); return -EINVAL; @@ -583,9 +591,9 @@ int __init psci_acpi_init(void) pr_info("probing for conduit method from ACPI.\n"); if (acpi_psci_use_hvc()) - set_conduit(PSCI_CONDUIT_HVC); + set_conduit(SMCCC_CONDUIT_HVC); else - set_conduit(PSCI_CONDUIT_SMC); + set_conduit(SMCCC_CONDUIT_SMC); return psci_probe(); } diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 215061c581e1..bee8729525ec 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -614,3 +614,8 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE, addr, val); } + +int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable) +{ + return -ENODEV; +} diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index 91d5ad7cf58b..e1cd933ea9ae 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -62,32 +62,72 @@ static DEFINE_MUTEX(qcom_scm_lock); #define FIRST_EXT_ARG_IDX 3 #define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1) -/** - * qcom_scm_call() - Invoke a syscall in the secure world - * @dev: device - * @svc_id: service identifier - * @cmd_id: command identifier - * @desc: Descriptor structure containing arguments and return values - * - * Sends a command to the SCM and waits for the command to finish processing. - * This should *only* be called in pre-emptible context. -*/ -static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, - const struct qcom_scm_desc *desc, - struct arm_smccc_res *res) +static void __qcom_scm_call_do(const struct qcom_scm_desc *desc, + struct arm_smccc_res *res, u32 fn_id, + u64 x5, u32 type) +{ + u64 cmd; + struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 }; + + cmd = ARM_SMCCC_CALL_VAL(type, qcom_smccc_convention, + ARM_SMCCC_OWNER_SIP, fn_id); + + quirk.state.a6 = 0; + + do { + arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0], + desc->args[1], desc->args[2], x5, + quirk.state.a6, 0, res, &quirk); + + if (res->a0 == QCOM_SCM_INTERRUPTED) + cmd = res->a0; + + } while (res->a0 == QCOM_SCM_INTERRUPTED); +} + +static void qcom_scm_call_do(const struct qcom_scm_desc *desc, + struct arm_smccc_res *res, u32 fn_id, + u64 x5, bool atomic) +{ + int retry_count = 0; + + if (atomic) { + __qcom_scm_call_do(desc, res, fn_id, x5, ARM_SMCCC_FAST_CALL); + return; + } + + do { + mutex_lock(&qcom_scm_lock); + + __qcom_scm_call_do(desc, res, fn_id, x5, + ARM_SMCCC_STD_CALL); + + mutex_unlock(&qcom_scm_lock); + + if (res->a0 == QCOM_SCM_V2_EBUSY) { + if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) + break; + msleep(QCOM_SCM_EBUSY_WAIT_MS); + } + } while (res->a0 == QCOM_SCM_V2_EBUSY); +} + +static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, + const struct qcom_scm_desc *desc, + struct arm_smccc_res *res, bool atomic) { int arglen = desc->arginfo & 0xf; - int retry_count = 0, i; + int i; u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id); - u64 cmd, x5 = desc->args[FIRST_EXT_ARG_IDX]; + u64 x5 = desc->args[FIRST_EXT_ARG_IDX]; dma_addr_t args_phys = 0; void *args_virt = NULL; size_t alloc_len; - struct arm_smccc_quirk quirk = {.id = ARM_SMCCC_QUIRK_QCOM_A6}; + gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL; if (unlikely(arglen > N_REGISTER_ARGS)) { alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64); - args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); + args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag); if (!args_virt) return -ENOMEM; @@ -117,46 +157,56 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, x5 = args_phys; } - do { - mutex_lock(&qcom_scm_lock); - - cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, - qcom_smccc_convention, - ARM_SMCCC_OWNER_SIP, fn_id); - - quirk.state.a6 = 0; - - do { - arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0], - desc->args[1], desc->args[2], x5, - quirk.state.a6, 0, res, &quirk); - - if (res->a0 == QCOM_SCM_INTERRUPTED) - cmd = res->a0; - - } while (res->a0 == QCOM_SCM_INTERRUPTED); - - mutex_unlock(&qcom_scm_lock); - - if (res->a0 == QCOM_SCM_V2_EBUSY) { - if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) - break; - msleep(QCOM_SCM_EBUSY_WAIT_MS); - } - } while (res->a0 == QCOM_SCM_V2_EBUSY); + qcom_scm_call_do(desc, res, fn_id, x5, atomic); if (args_virt) { dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE); kfree(args_virt); } - if (res->a0 < 0) + if ((long)res->a0 < 0) return qcom_scm_remap_error(res->a0); return 0; } /** + * qcom_scm_call() - Invoke a syscall in the secure world + * @dev: device + * @svc_id: service identifier + * @cmd_id: command identifier + * @desc: Descriptor structure containing arguments and return values + * + * Sends a command to the SCM and waits for the command to finish processing. + * This should *only* be called in pre-emptible context. + */ +static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, + const struct qcom_scm_desc *desc, + struct arm_smccc_res *res) +{ + might_sleep(); + return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, false); +} + +/** + * qcom_scm_call_atomic() - atomic variation of qcom_scm_call() + * @dev: device + * @svc_id: service identifier + * @cmd_id: command identifier + * @desc: Descriptor structure containing arguments and return values + * @res: Structure containing results from SMC/HVC call + * + * Sends a command to the SCM and waits for the command to finish processing. + * This can be called in atomic context. + */ +static int qcom_scm_call_atomic(struct device *dev, u32 svc_id, u32 cmd_id, + const struct qcom_scm_desc *desc, + struct arm_smccc_res *res) +{ + return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, true); +} + +/** * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus * @entry: Entry point function for the cpus * @cpus: The cpumask of cpus that will use the entry point @@ -502,3 +552,16 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE, &desc, &res); } + +int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + + desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL; + desc.args[1] = en; + desc.arginfo = QCOM_SCM_ARGS(2); + + return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM, + QCOM_SCM_CONFIG_ERRATA1, &desc, &res); +} diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 4802ab170fe5..a729e05c21b8 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -345,6 +345,12 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) } EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init); +int qcom_scm_qsmmu500_wait_safe_toggle(bool en) +{ + return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en); +} +EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle); + int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return __qcom_scm_io_readl(__scm->dev, addr, val); diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 99506bd873c0..baee744dbcfe 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -91,10 +91,15 @@ extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare); #define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3 #define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4 +#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15 +#define QCOM_SCM_CONFIG_ERRATA1 0x3 +#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2 extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, size_t *size); extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, u32 spare); +extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, + bool enable); #define QCOM_MEM_PROT_ASSIGN_ID 0x16 extern int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, size_t mem_sz, diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c index bb008c019920..f8533338b018 100644 --- a/drivers/firmware/stratix10-rsu.c +++ b/drivers/firmware/stratix10-rsu.c @@ -20,7 +20,6 @@ #define RSU_VERSION_MASK GENMASK_ULL(63, 32) #define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0) #define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32) -#define RSU_FW_VERSION_MASK GENMASK_ULL(15, 0) #define RSU_TIMEOUT (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS)) @@ -109,9 +108,12 @@ static void rsu_command_callback(struct stratix10_svc_client *client, { struct stratix10_rsu_priv *priv = client->priv; - if (data->status != BIT(SVC_STATUS_RSU_OK)) - dev_err(client->dev, "RSU returned status is %i\n", - data->status); + if (data->status == BIT(SVC_STATUS_RSU_NO_SUPPORT)) + dev_warn(client->dev, "Secure FW doesn't support notify\n"); + else if (data->status == BIT(SVC_STATUS_RSU_ERROR)) + dev_err(client->dev, "Failure, returned status is %lu\n", + BIT(data->status)); + complete(&priv->completion); } @@ -133,9 +135,11 @@ static void rsu_retry_callback(struct stratix10_svc_client *client, if (data->status == BIT(SVC_STATUS_RSU_OK)) priv->retry_counter = *counter; + else if (data->status == BIT(SVC_STATUS_RSU_NO_SUPPORT)) + dev_warn(client->dev, "Secure FW doesn't support retry\n"); else - dev_err(client->dev, "Failed to get retry counter %i\n", - data->status); + dev_err(client->dev, "Failed to get retry counter %lu\n", + BIT(data->status)); complete(&priv->completion); } @@ -333,15 +337,10 @@ static ssize_t notify_store(struct device *dev, return ret; } - /* only 19.3 or late version FW supports retry counter feature */ - if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) { - ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, - 0, rsu_retry_callback); - if (ret) { - dev_err(dev, - "Error, getting RSU retry %i\n", ret); - return ret; - } + ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); + if (ret) { + dev_err(dev, "Error, getting RSU retry %i\n", ret); + return ret; } return count; @@ -413,15 +412,10 @@ static int stratix10_rsu_probe(struct platform_device *pdev) stratix10_svc_free_channel(priv->chan); } - /* only 19.3 or late version FW supports retry counter feature */ - if (FIELD_GET(RSU_FW_VERSION_MASK, priv->status.version)) { - ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, - rsu_retry_callback); - if (ret) { - dev_err(dev, - "Error, getting RSU retry %i\n", ret); - stratix10_svc_free_channel(priv->chan); - } + ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); + if (ret) { + dev_err(dev, "Error, getting RSU retry %i\n", ret); + stratix10_svc_free_channel(priv->chan); } return ret; diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index b485321189e1..c6c31402848d 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -493,8 +493,24 @@ static int svc_normal_to_secure_thread(void *data) pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata); break; default: - pr_warn("it shouldn't happen\n"); + pr_warn("Secure firmware doesn't support...\n"); + + /* + * be compatible with older version firmware which + * doesn't support RSU notify or retry + */ + if ((pdata->command == COMMAND_RSU_RETRY) || + (pdata->command == COMMAND_RSU_NOTIFY)) { + cbdata->status = + BIT(SVC_STATUS_RSU_NO_SUPPORT); + cbdata->kaddr1 = NULL; + cbdata->kaddr2 = NULL; + cbdata->kaddr3 = NULL; + pdata->chan->scl->receive_cb( + pdata->chan->scl, cbdata); + } break; + } }; diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 19c56133234b..6741fcda0c37 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -804,7 +804,7 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev) } static const struct dev_pm_ops tegra_bpmp_pm_ops = { - .resume_early = tegra_bpmp_resume, + .resume_noirq = tegra_bpmp_resume, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index fd3d83745208..75bdfaa08380 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -711,8 +711,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) int ret; np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp"); - if (!np) - return 0; + if (!np) { + np = of_find_compatible_node(NULL, NULL, "xlnx,versal"); + if (!np) + return 0; + } of_node_put(np); ret = get_set_conduit_method(dev->of_node); @@ -770,6 +773,7 @@ static int zynqmp_firmware_remove(struct platform_device *pdev) static const struct of_device_id zynqmp_firmware_of_match[] = { {.compatible = "xlnx,zynqmp-firmware"}, + {.compatible = "xlnx,versal-firmware"}, {}, }; MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match); |