diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/arm_scmi/base.c | 2 | ||||
-rw-r--r-- | drivers/firmware/arm_scmi/driver.c | 37 | ||||
-rw-r--r-- | drivers/firmware/arm_scmi/scmi_pm_domain.c | 20 | ||||
-rw-r--r-- | drivers/firmware/arm_scpi.c | 61 | ||||
-rw-r--r-- | drivers/firmware/arm_sdei.c | 37 | ||||
-rw-r--r-- | drivers/firmware/dmi-sysfs.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/capsule-loader.c | 33 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 13 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/fdt.c | 8 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/secureboot.c | 8 | ||||
-rw-r--r-- | drivers/firmware/efi/memattr.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/runtime-wrappers.c | 1 | ||||
-rw-r--r-- | drivers/firmware/efi/vars.c | 17 | ||||
-rw-r--r-- | drivers/firmware/google/coreboot_table.c | 44 | ||||
-rw-r--r-- | drivers/firmware/google/framebuffer-coreboot.c | 4 | ||||
-rw-r--r-- | drivers/firmware/google/gsmi.c | 16 | ||||
-rw-r--r-- | drivers/firmware/meson/meson_sm.c | 96 | ||||
-rw-r--r-- | drivers/firmware/qcom_scm.c | 3 | ||||
-rw-r--r-- | drivers/firmware/raspberrypi.c | 70 | ||||
-rw-r--r-- | drivers/firmware/stratix10-svc.c | 20 | ||||
-rw-r--r-- | drivers/firmware/ti_sci.c | 58 | ||||
-rw-r--r-- | drivers/firmware/ti_sci.h | 2 |
22 files changed, 350 insertions, 204 deletions
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index f986ee8919f0..2be32e86445f 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -164,7 +164,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, break; loop_num_ret = le32_to_cpu(*num_ret); - if (tot_num_ret + loop_num_ret > MAX_PROTOCOLS_IMP) { + if (loop_num_ret > MAX_PROTOCOLS_IMP - tot_num_ret) { dev_err(dev, "No. of Protocol > MAX_PROTOCOLS_IMP"); break; } diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index f0b055bc027c..9dae841b6167 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -737,6 +737,39 @@ static int scmi_mailbox_check(struct device_node *np, int idx) idx, NULL); } +static int scmi_mailbox_chan_validate(struct device *cdev) +{ + int num_mb, num_sh, ret = 0; + struct device_node *np = cdev->of_node; + + num_mb = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); + num_sh = of_count_phandle_with_args(np, "shmem", NULL); + /* Bail out if mboxes and shmem descriptors are inconsistent */ + if (num_mb <= 0 || num_sh > 2 || num_mb != num_sh) { + dev_warn(cdev, "Invalid channel descriptor for '%s'\n", + of_node_full_name(np)); + return -EINVAL; + } + + if (num_sh > 1) { + struct device_node *np_tx, *np_rx; + + np_tx = of_parse_phandle(np, "shmem", 0); + np_rx = of_parse_phandle(np, "shmem", 1); + /* SCMI Tx and Rx shared mem areas have to be distinct */ + if (!np_tx || !np_rx || np_tx == np_rx) { + dev_warn(cdev, "Invalid shmem descriptor for '%s'\n", + of_node_full_name(np)); + ret = -EINVAL; + } + + of_node_put(np_tx); + of_node_put(np_rx); + } + + return ret; +} + static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id, bool tx) { @@ -760,6 +793,10 @@ static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, goto idr_alloc; } + ret = scmi_mailbox_chan_validate(dev); + if (ret) + return ret; + cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL); if (!cinfo) return -ENOMEM; diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c index 177874adccf0..b0c8962b9885 100644 --- a/drivers/firmware/arm_scmi/scmi_pm_domain.c +++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c @@ -106,9 +106,28 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) scmi_pd_data->domains = domains; scmi_pd_data->num_domains = num_domains; + dev_set_drvdata(dev, scmi_pd_data); + return of_genpd_add_provider_onecell(np, scmi_pd_data); } +static void scmi_pm_domain_remove(struct scmi_device *sdev) +{ + int i; + struct genpd_onecell_data *scmi_pd_data; + struct device *dev = &sdev->dev; + struct device_node *np = dev->of_node; + + of_genpd_del_provider(np); + + scmi_pd_data = dev_get_drvdata(dev); + for (i = 0; i < scmi_pd_data->num_domains; i++) { + if (!scmi_pd_data->domains[i]) + continue; + pm_genpd_remove(scmi_pd_data->domains[i]); + } +} + static const struct scmi_device_id scmi_id_table[] = { { SCMI_PROTOCOL_POWER }, { }, @@ -118,6 +137,7 @@ MODULE_DEVICE_TABLE(scmi, scmi_id_table); static struct scmi_driver scmi_power_domain_driver = { .name = "scmi-power-domain", .probe = scmi_pm_domain_probe, + .remove = scmi_pm_domain_remove, .id_table = scmi_id_table, }; module_scmi_driver(scmi_power_domain_driver); diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index e2995ec14401..72634e9d8116 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -815,7 +815,7 @@ static int scpi_init_versions(struct scpi_drvinfo *info) info->firmware_version = le32_to_cpu(caps.platform_version); } /* Ignore error if not implemented */ - if (scpi_info->is_legacy && ret == -EOPNOTSUPP) + if (info->is_legacy && ret == -EOPNOTSUPP) return 0; return ret; @@ -905,13 +905,14 @@ static int scpi_probe(struct platform_device *pdev) struct resource res; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + struct scpi_drvinfo *scpi_drvinfo; - scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL); - if (!scpi_info) + scpi_drvinfo = devm_kzalloc(dev, sizeof(*scpi_drvinfo), GFP_KERNEL); + if (!scpi_drvinfo) return -ENOMEM; if (of_match_device(legacy_scpi_of_match, &pdev->dev)) - scpi_info->is_legacy = true; + scpi_drvinfo->is_legacy = true; count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); if (count < 0) { @@ -919,19 +920,19 @@ static int scpi_probe(struct platform_device *pdev) return -ENODEV; } - scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan), - GFP_KERNEL); - if (!scpi_info->channels) + scpi_drvinfo->channels = + devm_kcalloc(dev, count, sizeof(struct scpi_chan), GFP_KERNEL); + if (!scpi_drvinfo->channels) return -ENOMEM; - ret = devm_add_action(dev, scpi_free_channels, scpi_info); + ret = devm_add_action(dev, scpi_free_channels, scpi_drvinfo); if (ret) return ret; - for (; scpi_info->num_chans < count; scpi_info->num_chans++) { + for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) { resource_size_t size; - int idx = scpi_info->num_chans; - struct scpi_chan *pchan = scpi_info->channels + idx; + int idx = scpi_drvinfo->num_chans; + struct scpi_chan *pchan = scpi_drvinfo->channels + idx; struct mbox_client *cl = &pchan->cl; struct device_node *shmem = of_parse_phandle(np, "shmem", idx); @@ -975,45 +976,53 @@ static int scpi_probe(struct platform_device *pdev) return ret; } - scpi_info->commands = scpi_std_commands; + scpi_drvinfo->commands = scpi_std_commands; - platform_set_drvdata(pdev, scpi_info); + platform_set_drvdata(pdev, scpi_drvinfo); - if (scpi_info->is_legacy) { + if (scpi_drvinfo->is_legacy) { /* Replace with legacy variants */ scpi_ops.clk_set_val = legacy_scpi_clk_set_val; - scpi_info->commands = scpi_legacy_commands; + scpi_drvinfo->commands = scpi_legacy_commands; /* Fill priority bitmap */ for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++) set_bit(legacy_hpriority_cmds[idx], - scpi_info->cmd_priority); + scpi_drvinfo->cmd_priority); } - ret = scpi_init_versions(scpi_info); + scpi_info = scpi_drvinfo; + + ret = scpi_init_versions(scpi_drvinfo); if (ret) { dev_err(dev, "incorrect or no SCP firmware found\n"); + scpi_info = NULL; return ret; } - if (scpi_info->is_legacy && !scpi_info->protocol_version && - !scpi_info->firmware_version) + if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version && + !scpi_drvinfo->firmware_version) dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n"); else dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n", FIELD_GET(PROTO_REV_MAJOR_MASK, - scpi_info->protocol_version), + scpi_drvinfo->protocol_version), FIELD_GET(PROTO_REV_MINOR_MASK, - scpi_info->protocol_version), + scpi_drvinfo->protocol_version), FIELD_GET(FW_REV_MAJOR_MASK, - scpi_info->firmware_version), + scpi_drvinfo->firmware_version), FIELD_GET(FW_REV_MINOR_MASK, - scpi_info->firmware_version), + scpi_drvinfo->firmware_version), FIELD_GET(FW_REV_PATCH_MASK, - scpi_info->firmware_version)); - scpi_info->scpi_ops = &scpi_ops; + scpi_drvinfo->firmware_version)); + + scpi_drvinfo->scpi_ops = &scpi_ops; - return devm_of_platform_populate(dev); + ret = devm_of_platform_populate(dev); + if (ret) + scpi_info = NULL; + + return ret; } static const struct of_device_id scpi_of_match[] = { diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c index e497785cd99f..b0e8752174c6 100644 --- a/drivers/firmware/arm_sdei.c +++ b/drivers/firmware/arm_sdei.c @@ -44,6 +44,8 @@ static asmlinkage void (*sdei_firmware_call)(unsigned long function_id, /* entry point from firmware to arch asm code */ static unsigned long sdei_entry_point; +static int sdei_hp_state; + struct sdei_event { /* These three are protected by the sdei_list_lock */ struct list_head list; @@ -305,8 +307,6 @@ int sdei_mask_local_cpu(void) { int err; - WARN_ON_ONCE(preemptible()); - err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) { pr_warn_once("failed to mask CPU[%u]: %d\n", @@ -319,6 +319,7 @@ int sdei_mask_local_cpu(void) static void _ipi_mask_cpu(void *ignored) { + WARN_ON_ONCE(preemptible()); sdei_mask_local_cpu(); } @@ -326,8 +327,6 @@ int sdei_unmask_local_cpu(void) { int err; - WARN_ON_ONCE(preemptible()); - err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) { pr_warn_once("failed to unmask CPU[%u]: %d\n", @@ -340,6 +339,7 @@ int sdei_unmask_local_cpu(void) static void _ipi_unmask_cpu(void *ignored) { + WARN_ON_ONCE(preemptible()); sdei_unmask_local_cpu(); } @@ -347,6 +347,8 @@ static void _ipi_private_reset(void *ignored) { int err; + WARN_ON_ONCE(preemptible()); + err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) @@ -393,8 +395,6 @@ static void _local_event_enable(void *data) int err; struct sdei_crosscall_args *arg = data; - WARN_ON_ONCE(preemptible()); - err = sdei_api_event_enable(arg->event->event_num); sdei_cross_call_return(arg, err); @@ -485,8 +485,6 @@ static void _local_event_unregister(void *data) int err; struct sdei_crosscall_args *arg = data; - WARN_ON_ONCE(preemptible()); - err = sdei_api_event_unregister(arg->event->event_num); sdei_cross_call_return(arg, err); @@ -575,8 +573,6 @@ static void _local_event_register(void *data) struct sdei_registered_event *reg; struct sdei_crosscall_args *arg = data; - WARN_ON(preemptible()); - reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id()); err = sdei_api_event_register(arg->event->event_num, sdei_entry_point, reg, 0, 0); @@ -756,6 +752,8 @@ static int sdei_pm_notifier(struct notifier_block *nb, unsigned long action, { int rv; + WARN_ON_ONCE(preemptible()); + switch (action) { case CPU_PM_ENTER: rv = sdei_mask_local_cpu(); @@ -804,7 +802,7 @@ static int sdei_device_freeze(struct device *dev) int err; /* unregister private events */ - cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + cpuhp_remove_state(sdei_entry_point); err = sdei_unregister_shared(); if (err) @@ -825,12 +823,15 @@ static int sdei_device_thaw(struct device *dev) return err; } - err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI", &sdei_cpuhp_up, &sdei_cpuhp_down); - if (err) + if (err < 0) { pr_warn("Failed to re-register CPU hotplug notifier...\n"); + return err; + } - return err; + sdei_hp_state = err; + return 0; } static int sdei_device_restore(struct device *dev) @@ -862,7 +863,7 @@ static int sdei_reboot_notifier(struct notifier_block *nb, unsigned long action, * We are going to reset the interface, after this there is no point * doing work when we take CPUs offline. */ - cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + cpuhp_remove_state(sdei_hp_state); sdei_platform_reset(); @@ -1044,13 +1045,15 @@ static int sdei_probe(struct platform_device *pdev) goto remove_cpupm; } - err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI", &sdei_cpuhp_up, &sdei_cpuhp_down); - if (err) { + if (err < 0) { pr_warn("Failed to register CPU hotplug notifier...\n"); goto remove_reboot; } + sdei_hp_state = err; + return 0; remove_reboot: diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c index b6180023eba7..2858e05636e9 100644 --- a/drivers/firmware/dmi-sysfs.c +++ b/drivers/firmware/dmi-sysfs.c @@ -603,7 +603,7 @@ static void __init dmi_sysfs_register_handle(const struct dmi_header *dh, "%d-%d", dh->type, entry->instance); if (*ret) { - kfree(entry); + kobject_put(&entry->kobj); return; } diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index b1395133389e..78c02717c368 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -242,29 +242,6 @@ failed: } /** - * efi_capsule_flush - called by file close or file flush - * @file: file pointer - * @id: not used - * - * If a capsule is being partially uploaded then calling this function - * will be treated as upload termination and will free those completed - * buffer pages and -ECANCELED will be returned. - **/ -static int efi_capsule_flush(struct file *file, fl_owner_t id) -{ - int ret = 0; - struct capsule_info *cap_info = file->private_data; - - if (cap_info->index > 0) { - pr_err("capsule upload not complete\n"); - efi_free_all_buff_pages(cap_info); - ret = -ECANCELED; - } - - return ret; -} - -/** * efi_capsule_release - called by file close * @inode: not used * @file: file pointer @@ -276,6 +253,13 @@ static int efi_capsule_release(struct inode *inode, struct file *file) { struct capsule_info *cap_info = file->private_data; + if (cap_info->index > 0 && + (cap_info->header.headersize == 0 || + cap_info->count < cap_info->total_size)) { + pr_err("capsule upload not complete\n"); + efi_free_all_buff_pages(cap_info); + } + kfree(cap_info->pages); kfree(cap_info->phys); kfree(file->private_data); @@ -307,7 +291,7 @@ static int efi_capsule_open(struct inode *inode, struct file *file) return -ENOMEM; } - cap_info->phys = kzalloc(sizeof(void *), GFP_KERNEL); + cap_info->phys = kzalloc(sizeof(phys_addr_t), GFP_KERNEL); if (!cap_info->phys) { kfree(cap_info->pages); kfree(cap_info); @@ -323,7 +307,6 @@ static const struct file_operations efi_capsule_fops = { .owner = THIS_MODULE, .open = efi_capsule_open, .write = efi_capsule_write, - .flush = efi_capsule_flush, .release = efi_capsule_release, .llseek = no_llseek, }; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 8fd74a7501d4..ed31b08855f9 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -345,8 +345,8 @@ static int __init efisubsys_init(void) efi_kobj = kobject_create_and_add("efi", firmware_kobj); if (!efi_kobj) { pr_err("efi: Firmware registration failed.\n"); - destroy_workqueue(efi_rts_wq); - return -ENOMEM; + error = -ENOMEM; + goto err_destroy_wq; } error = generic_ops_register(); @@ -382,7 +382,10 @@ err_unregister: generic_ops_unregister(); err_put: kobject_put(efi_kobj); - destroy_workqueue(efi_rts_wq); +err_destroy_wq: + if (efi_rts_wq) + destroy_workqueue(efi_rts_wq); + return error; } @@ -546,7 +549,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, seed = early_memremap(efi.rng_seed, sizeof(*seed)); if (seed != NULL) { - size = READ_ONCE(seed->size); + size = min(seed->size, EFI_RANDOM_SEED_SIZE); early_memunmap(seed, sizeof(*seed)); } else { pr_err("Could not map UEFI random seed!\n"); @@ -1019,6 +1022,8 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) /* first try to find a slot in an existing linked list entry */ for (prsv = efi_memreserve_root->next; prsv; ) { rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB); + if (!rsv) + return -ENOMEM; index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size); if (index < rsv->size) { rsv->entry[index].base = addr; diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 0bf0190917e0..9d9a3b698351 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -291,14 +291,6 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, goto fail; } - /* - * Now that we have done our final memory allocation (and free) - * we can get the memory map key needed for exit_boot_services(). - */ - status = efi_get_memory_map(sys_table, &map); - if (status != EFI_SUCCESS) - goto fail_free_new_fdt; - status = update_fdt(sys_table, (void *)fdt_addr, fdt_size, (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr, initrd_addr, initrd_size); diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c index edba5e7a3743..c8a1ef872e0d 100644 --- a/drivers/firmware/efi/libstub/secureboot.c +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -19,7 +19,7 @@ static const efi_char16_t efi_SetupMode_name[] = L"SetupMode"; /* SHIM variables */ static const efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID; -static const efi_char16_t shim_MokSBState_name[] = L"MokSBState"; +static const efi_char16_t shim_MokSBState_name[] = L"MokSBStateRT"; #define get_efi_var(name, vendor, ...) \ efi_call_runtime(get_variable, \ @@ -58,8 +58,8 @@ enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) /* * See if a user has put the shim into insecure mode. If so, and if the - * variable doesn't have the runtime attribute set, we might as well - * honor that. + * variable doesn't have the non-volatile attribute set, we might as + * well honor that. */ size = sizeof(moksbstate); status = get_efi_var(shim_MokSBState_name, &shim_guid, @@ -68,7 +68,7 @@ enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) /* If it fails, we don't care why. Default to secure */ if (status != EFI_SUCCESS) goto secure_boot_enabled; - if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS) && moksbstate == 1) + if (!(attr & EFI_VARIABLE_NON_VOLATILE) && moksbstate == 1) return efi_secureboot_mode_disabled; secure_boot_enabled: diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c index 5d343dc8e535..5f577357c3e7 100644 --- a/drivers/firmware/efi/memattr.c +++ b/drivers/firmware/efi/memattr.c @@ -32,7 +32,7 @@ int __init efi_memattr_init(void) return -ENOMEM; } - if (tbl->version > 1) { + if (tbl->version > 2) { pr_warn("Unexpected EFI Memory Attributes table version %d\n", tbl->version); goto unmap; diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 136b9c7f9ac9..a6735f1a16d1 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -62,6 +62,7 @@ struct efi_runtime_work efi_rts_work; \ if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \ pr_warn_once("EFI Runtime Services are disabled!\n"); \ + efi_rts_work.status = EFI_DEVICE_ERROR; \ goto exit; \ } \ \ diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index a32d15b2928f..ec555ad61741 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -427,7 +427,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), void *data, bool duplicates, struct list_head *head) { const struct efivar_operations *ops; - unsigned long variable_name_size = 1024; + unsigned long variable_name_size = 512; efi_char16_t *variable_name; efi_status_t status; efi_guid_t vendor_guid; @@ -450,12 +450,13 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), } /* - * Per EFI spec, the maximum storage allocated for both - * the variable name and variable data is 1024 bytes. + * A small set of old UEFI implementations reject sizes + * above a certain threshold, the lowest seen in the wild + * is 512. */ do { - variable_name_size = 1024; + variable_name_size = 512; status = ops->get_next_variable(&variable_name_size, variable_name, @@ -499,9 +500,13 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), break; case EFI_NOT_FOUND: break; + case EFI_BUFFER_TOO_SMALL: + pr_warn("efivars: Variable name size exceeds maximum (%lu > 512)\n", + variable_name_size); + status = EFI_NOT_FOUND; + break; default: - printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n", - status); + pr_warn("efivars: get_next_variable: status=%lx\n", status); status = EFI_NOT_FOUND; break; } diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 8d132e4f008a..568074148f62 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -152,20 +152,22 @@ static int coreboot_table_probe(struct platform_device *pdev) if (!ptr) return -ENOMEM; - ret = bus_register(&coreboot_bus_type); - if (!ret) { - ret = coreboot_table_populate(dev, ptr); - if (ret) - bus_unregister(&coreboot_bus_type); - } + ret = coreboot_table_populate(dev, ptr); + memunmap(ptr); return ret; } +static int __cb_dev_unregister(struct device *dev, void *dummy) +{ + device_unregister(dev); + return 0; +} + static int coreboot_table_remove(struct platform_device *pdev) { - bus_unregister(&coreboot_bus_type); + bus_for_each_dev(&coreboot_bus_type, NULL, NULL, __cb_dev_unregister); return 0; } @@ -195,6 +197,32 @@ static struct platform_driver coreboot_table_driver = { .of_match_table = of_match_ptr(coreboot_of_match), }, }; -module_platform_driver(coreboot_table_driver); + +static int __init coreboot_table_driver_init(void) +{ + int ret; + + ret = bus_register(&coreboot_bus_type); + if (ret) + return ret; + + ret = platform_driver_register(&coreboot_table_driver); + if (ret) { + bus_unregister(&coreboot_bus_type); + return ret; + } + + return 0; +} + +static void __exit coreboot_table_driver_exit(void) +{ + platform_driver_unregister(&coreboot_table_driver); + bus_unregister(&coreboot_bus_type); +} + +module_init(coreboot_table_driver_init); +module_exit(coreboot_table_driver_exit); + MODULE_AUTHOR("Google, Inc."); MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c index 916f26adc595..922c079d13c8 100644 --- a/drivers/firmware/google/framebuffer-coreboot.c +++ b/drivers/firmware/google/framebuffer-coreboot.c @@ -43,9 +43,7 @@ static int framebuffer_probe(struct coreboot_device *dev) fb->green_mask_pos == formats[i].green.offset && fb->green_mask_size == formats[i].green.length && fb->blue_mask_pos == formats[i].blue.offset && - fb->blue_mask_size == formats[i].blue.length && - fb->reserved_mask_pos == formats[i].transp.offset && - fb->reserved_mask_size == formats[i].transp.length) + fb->blue_mask_size == formats[i].blue.length) pdata.format = formats[i].name; } if (!pdata.format) diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index edaa4e5d84ad..94753ad18ca6 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -359,9 +359,10 @@ static efi_status_t gsmi_get_variable(efi_char16_t *name, memcpy(data, gsmi_dev.data_buf->start, *data_size); /* All variables are have the following attributes */ - *attr = EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; + if (attr) + *attr = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; } spin_unlock_irqrestore(&gsmi_dev.lock, flags); @@ -679,6 +680,15 @@ static struct notifier_block gsmi_die_notifier = { static int gsmi_panic_callback(struct notifier_block *nb, unsigned long reason, void *arg) { + + /* + * Panic callbacks are executed with all other CPUs stopped, + * so we must not attempt to spin waiting for gsmi_dev.lock + * to be released. + */ + if (spin_is_locked(&gsmi_dev.lock)) + return NOTIFY_DONE; + gsmi_shutdown_reason(GSMI_SHUTDOWN_PANIC); return NOTIFY_DONE; } diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index 8d908a8e0d20..a63ce2815d7d 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -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,14 +238,18 @@ 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); @@ -268,25 +293,36 @@ 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; - chip = of_match_device(meson_sm_ids, &pdev->dev)->data; + fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); + if (!fw) + return -ENOMEM; + + chip = of_match_device(meson_sm_ids, dev)->data; + if (!chip) + return -EINVAL; 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 +331,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/qcom_scm.c b/drivers/firmware/qcom_scm.c index b9fdc20b4eb9..eda25d506059 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -585,8 +585,7 @@ static int qcom_scm_probe(struct platform_device *pdev) static void qcom_scm_shutdown(struct platform_device *pdev) { /* Clean shutdown, disable download mode to allow normal restart */ - if (download_mode) - qcom_scm_set_download_mode(false); + qcom_scm_set_download_mode(false); } static const struct of_device_id qcom_scm_dt_match[] = { diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index da26a584dca0..1a690b2c1e2f 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -7,6 +7,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/kref.h> #include <linux/mailbox_client.h> #include <linux/module.h> #include <linux/of_platform.h> @@ -27,6 +28,8 @@ struct rpi_firmware { struct mbox_chan *chan; /* The property channel. */ struct completion c; u32 enabled; + + struct kref consumers; }; static DEFINE_MUTEX(transaction_lock); @@ -214,12 +217,38 @@ static void rpi_register_clk_driver(struct device *dev) -1, NULL, 0); } +static void rpi_firmware_delete(struct kref *kref) +{ + struct rpi_firmware *fw = container_of(kref, struct rpi_firmware, + consumers); + + mbox_free_channel(fw->chan); + kfree(fw); +} + +void rpi_firmware_put(struct rpi_firmware *fw) +{ + kref_put(&fw->consumers, rpi_firmware_delete); +} +EXPORT_SYMBOL_GPL(rpi_firmware_put); + +static void devm_rpi_firmware_put(void *data) +{ + struct rpi_firmware *fw = data; + + rpi_firmware_put(fw); +} + static int rpi_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpi_firmware *fw; - fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); + /* + * Memory will be freed by rpi_firmware_delete() once all users have + * released their firmware handles. Don't use devm_kzalloc() here. + */ + fw = kzalloc(sizeof(*fw), GFP_KERNEL); if (!fw) return -ENOMEM; @@ -232,10 +261,12 @@ static int rpi_firmware_probe(struct platform_device *pdev) int ret = PTR_ERR(fw->chan); if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get mbox channel: %d\n", ret); + kfree(fw); return ret; } init_completion(&fw->c); + kref_init(&fw->consumers); platform_set_drvdata(pdev, fw); @@ -264,7 +295,8 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_hwmon = NULL; platform_device_unregister(rpi_clk); rpi_clk = NULL; - mbox_free_channel(fw->chan); + + rpi_firmware_put(fw); return 0; } @@ -273,19 +305,51 @@ static int rpi_firmware_remove(struct platform_device *pdev) * rpi_firmware_get - Get pointer to rpi_firmware structure. * @firmware_node: Pointer to the firmware Device Tree node. * + * The reference to rpi_firmware has to be released with rpi_firmware_put(). + * * Returns NULL is the firmware device is not ready. */ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { struct platform_device *pdev = of_find_device_by_node(firmware_node); + struct rpi_firmware *fw; if (!pdev) return NULL; - return platform_get_drvdata(pdev); + fw = platform_get_drvdata(pdev); + if (!fw) + return NULL; + + if (!kref_get_unless_zero(&fw->consumers)) + return NULL; + + return fw; } EXPORT_SYMBOL_GPL(rpi_firmware_get); +/** + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. + * @firmware_node: Pointer to the firmware Device Tree node. + * + * Returns NULL is the firmware device is not ready. + */ +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + struct rpi_firmware *fw; + + fw = rpi_firmware_get(firmware_node); + if (!fw) + return NULL; + + if (devm_add_action_or_reset(dev, devm_rpi_firmware_put, fw)) + return NULL; + + return fw; +} +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); + static const struct of_device_id rpi_firmware_of_match[] = { { .compatible = "raspberrypi,bcm2835-firmware", }, {}, diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index b2b4ba240fb1..c871b4227a64 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -615,8 +615,8 @@ svc_create_memory_pool(struct platform_device *pdev, end = rounddown(sh_memory->addr + sh_memory->size, PAGE_SIZE); paddr = begin; size = end - begin; - va = memremap(paddr, size, MEMREMAP_WC); - if (!va) { + va = devm_memremap(dev, paddr, size, MEMREMAP_WC); + if (IS_ERR(va)) { dev_err(dev, "fail to remap shared memory\n"); return ERR_PTR(-EINVAL); } @@ -934,17 +934,17 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory); void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr) { struct stratix10_svc_data_mem *pmem; - size_t size = 0; list_for_each_entry(pmem, &svc_data_mem, node) if (pmem->vaddr == kaddr) { - size = pmem->size; - break; + gen_pool_free(chan->ctrl->genpool, + (unsigned long)kaddr, pmem->size); + pmem->vaddr = NULL; + list_del(&pmem->node); + return; } - gen_pool_free(chan->ctrl->genpool, (unsigned long)kaddr, size); - pmem->vaddr = NULL; - list_del(&pmem->node); + list_del(&svc_data_mem); } EXPORT_SYMBOL_GPL(stratix10_svc_free_memory); @@ -981,8 +981,8 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) return ret; genpool = svc_create_memory_pool(pdev, sh_memory); - if (!genpool) - return -ENOMEM; + if (IS_ERR(genpool)) + return PTR_ERR(genpool); /* allocate service controller and supporting channel */ controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 4126be9e3216..00259a5f3b3b 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -2,7 +2,7 @@ /* * Texas Instruments System Control Interface Protocol Driver * - * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ * Nishanth Menon */ @@ -179,7 +179,7 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct resource *res; - char debug_name[50] = "ti_sci_debug@"; + char debug_name[50]; /* Debug region is optional */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -196,10 +196,10 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, /* Setup NULL termination */ info->debug_buffer[info->debug_region_size] = 0; - info->d = debugfs_create_file(strncat(debug_name, dev_name(dev), - sizeof(debug_name) - - sizeof("ti_sci_debug@")), - 0444, NULL, info, &ti_sci_debug_fops); + snprintf(debug_name, sizeof(debug_name), "ti_sci_debug@%s", + dev_name(dev)); + info->d = debugfs_create_file(debug_name, 0444, NULL, info, + &ti_sci_debug_fops); if (IS_ERR(info->d)) return PTR_ERR(info->d); @@ -208,19 +208,6 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, return 0; } -/** - * ti_sci_debugfs_destroy() - clean up log debug file - * @pdev: platform device pointer - * @info: Pointer to SCI entity information - */ -static void ti_sci_debugfs_destroy(struct platform_device *pdev, - struct ti_sci_info *info) -{ - if (IS_ERR(info->debug_region)) - return; - - debugfs_remove(info->d); -} #else /* CONFIG_DEBUG_FS */ static inline int ti_sci_debugfs_create(struct platform_device *dev, struct ti_sci_info *info) @@ -3527,43 +3514,12 @@ out: return ret; } -static int ti_sci_remove(struct platform_device *pdev) -{ - struct ti_sci_info *info; - struct device *dev = &pdev->dev; - int ret = 0; - - of_platform_depopulate(dev); - - info = platform_get_drvdata(pdev); - - if (info->nb.notifier_call) - unregister_restart_handler(&info->nb); - - mutex_lock(&ti_sci_list_mutex); - if (info->users) - ret = -EBUSY; - else - list_del(&info->node); - mutex_unlock(&ti_sci_list_mutex); - - if (!ret) { - ti_sci_debugfs_destroy(pdev, info); - - /* Safe to free channels since no more users */ - mbox_free_channel(info->chan_tx); - mbox_free_channel(info->chan_rx); - } - - return ret; -} - static struct platform_driver ti_sci_driver = { .probe = ti_sci_probe, - .remove = ti_sci_remove, .driver = { .name = "ti-sci", .of_match_table = of_match_ptr(ti_sci_of_match), + .suppress_bind_attrs = true, }, }; module_platform_driver(ti_sci_driver); diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index f0d068c03944..57cd04062994 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -6,7 +6,7 @@ * The system works in a message response protocol * See: http://processors.wiki.ti.com/index.php/TISCI for details * - * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef __TI_SCI_H |