diff options
Diffstat (limited to 'drivers/firmware')
29 files changed, 233 insertions, 134 deletions
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 37eb2e6c2f9f..65bf1685350a 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -2059,7 +2059,7 @@ free_drv_info: kfree(drv_info); return ret; } -module_init(ffa_init); +rootfs_initcall(ffa_init); static void __exit ffa_exit(void) { diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index 1adef0389475..24e59ddf85e7 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -323,6 +323,31 @@ static struct attribute *scmi_device_attributes_attrs[] = { }; ATTRIBUTE_GROUPS(scmi_device_attributes); +static int scmi_pm_suspend(struct device *dev) +{ + const struct device_driver *drv = dev->driver; + + if (drv && drv->pm && drv->pm->suspend) + return drv->pm->suspend(dev); + + return 0; +} + +static int scmi_pm_resume(struct device *dev) +{ + const struct device_driver *drv = dev->driver; + + if (drv && drv->pm && drv->pm->resume) + return drv->pm->resume(dev); + + return 0; +} + +static const struct dev_pm_ops scmi_dev_pm_ops = { + .suspend = pm_sleep_ptr(scmi_pm_suspend), + .resume = pm_sleep_ptr(scmi_pm_resume), +}; + const struct bus_type scmi_bus_type = { .name = "scmi_protocol", .match = scmi_dev_match, @@ -330,6 +355,7 @@ const struct bus_type scmi_bus_type = { .remove = scmi_dev_remove, .uevent = scmi_device_uevent, .dev_groups = scmi_device_attributes_groups, + .pm = &scmi_dev_pm_ops, }; EXPORT_SYMBOL_GPL(scmi_bus_type); diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index dab758c5fdea..07b9e629276d 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -305,6 +305,7 @@ enum debug_counters { ERR_MSG_INVALID, ERR_MSG_NOMEM, ERR_PROTOCOL, + XFERS_INFLIGHT, SCMI_DEBUG_COUNTERS_LAST }; @@ -314,6 +315,12 @@ static inline void scmi_inc_count(atomic_t *arr, int stat) atomic_inc(&arr[stat]); } +static inline void scmi_dec_count(atomic_t *arr, int stat) +{ + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) + atomic_dec(&arr[stat]); +} + enum scmi_bad_msg { MSG_UNEXPECTED = -1, MSG_INVALID = -2, @@ -498,4 +505,5 @@ static struct platform_driver __drv = { \ void scmi_notification_instance_data_set(const struct scmi_handle *handle, void *priv); void *scmi_notification_instance_data_get(const struct scmi_handle *handle); +int scmi_inflight_count(const struct scmi_handle *handle); #endif /* _SCMI_COMMON_H */ diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 395fe9289035..bd56a877fdfc 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -190,6 +190,7 @@ struct scmi_info { }; #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) +#define tx_minfo_to_scmi_info(h) container_of(h, struct scmi_info, tx_minfo) #define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb) #define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb) @@ -603,9 +604,14 @@ static inline void scmi_xfer_inflight_register_unlocked(struct scmi_xfer *xfer, struct scmi_xfers_info *minfo) { + /* In this context minfo will be tx_minfo due to the xfer pending */ + struct scmi_info *info = tx_minfo_to_scmi_info(minfo); + /* Set in-flight */ set_bit(xfer->hdr.seq, minfo->xfer_alloc_table); hash_add(minfo->pending_xfers, &xfer->node, xfer->hdr.seq); + scmi_inc_count(info->dbg->counters, XFERS_INFLIGHT); + xfer->pending = true; } @@ -807,9 +813,13 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer) spin_lock_irqsave(&minfo->xfer_lock, flags); if (refcount_dec_and_test(&xfer->users)) { if (xfer->pending) { + struct scmi_info *info = tx_minfo_to_scmi_info(minfo); + scmi_xfer_token_clear(minfo, xfer); hash_del(&xfer->node); xfer->pending = false; + + scmi_dec_count(info->dbg->counters, XFERS_INFLIGHT); } hlist_add_head(&xfer->node, &minfo->free_xfers); } @@ -1433,7 +1443,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph, trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id, xfer->hdr.protocol_id, xfer->hdr.seq, - xfer->hdr.poll_completion); + xfer->hdr.poll_completion, + scmi_inflight_count(&info->handle)); /* Clear any stale status */ xfer->hdr.status = SCMI_SUCCESS; @@ -1469,7 +1480,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph, info->desc->ops->mark_txdone(cinfo, ret, xfer); trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id, - xfer->hdr.protocol_id, xfer->hdr.seq, ret); + xfer->hdr.protocol_id, xfer->hdr.seq, ret, + scmi_inflight_count(&info->handle)); return ret; } @@ -2912,6 +2924,7 @@ static const char * const dbg_counter_strs[] = { "err_msg_invalid", "err_msg_nomem", "err_protocol", + "xfers_inflight", }; static ssize_t reset_all_on_write(struct file *filp, const char __user *buf, @@ -3405,6 +3418,17 @@ static struct dentry *scmi_debugfs_init(void) return d; } +int scmi_inflight_count(const struct scmi_handle *handle) +{ + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) { + struct scmi_info *info = handle_to_scmi_info(handle); + + return atomic_read(&info->dbg->counters[XFERS_INFLIGHT]); + } else { + return 0; + } +} + static int __init scmi_driver_init(void) { scmi_quirks_initialize(); diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index e160ecb22948..dee9f238f6fd 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -318,6 +318,9 @@ struct scmi_registered_events_desc { * customized event report * @num_sources: The number of possible sources for this event as stated at * events' registration time + * @not_supported_by_platform: A flag to indicate that not even one source was + * found to be supported by the platform for this + * event * @sources: A reference to a dynamically allocated array used to refcount the * events' enable requests for all the existing sources * @sources_mtx: A mutex to serialize the access to @sources @@ -334,6 +337,7 @@ struct scmi_registered_event { const struct scmi_event *evt; void *report; u32 num_sources; + bool not_supported_by_platform; refcount_t *sources; /* locking to serialize the access to sources */ struct mutex sources_mtx; @@ -811,10 +815,19 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, if (!r_evt->report) return -ENOMEM; - for (id = 0; id < r_evt->num_sources; id++) - if (ee->ops->is_notify_supported && - !ee->ops->is_notify_supported(ph, r_evt->evt->id, id)) - refcount_set(&r_evt->sources[id], NOTIF_UNSUPP); + if (ee->ops->is_notify_supported) { + int supported = 0; + + for (id = 0; id < r_evt->num_sources; id++) { + if (!ee->ops->is_notify_supported(ph, r_evt->evt->id, id)) + refcount_set(&r_evt->sources[id], NOTIF_UNSUPP); + else + supported++; + } + + /* Not even one source has been found to be supported */ + r_evt->not_supported_by_platform = !supported; + } pd->registered_events[i] = r_evt; /* Ensure events are updated */ @@ -936,6 +949,11 @@ static inline int scmi_bind_event_handler(struct scmi_notify_instance *ni, * of protocol instance. */ hash_del(&hndl->hash); + + /* Bailout if event is not supported at all */ + if (r_evt->not_supported_by_platform) + return -EOPNOTSUPP; + /* * Acquire protocols only for NON pending handlers, so as NOT to trigger * protocol initialization when a notifier is registered against a still @@ -1060,6 +1078,9 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni, r_evt = SCMI_GET_REVT(ni, KEY_XTRACT_PROTO_ID(evt_key), KEY_XTRACT_EVT_ID(evt_key)); + if (r_evt && r_evt->not_supported_by_platform) + return ERR_PTR(-EOPNOTSUPP); + mutex_lock(&ni->pending_mtx); /* Search registered events at first ... if possible at all */ if (r_evt) { @@ -1087,7 +1108,7 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni, hndl->key); /* this hndl can be only a pending one */ scmi_put_handler_unlocked(ni, hndl); - hndl = NULL; + hndl = ERR_PTR(-EINVAL); } } mutex_unlock(&ni->pending_mtx); @@ -1370,8 +1391,8 @@ static int scmi_notifier_register(const struct scmi_handle *handle, evt_key = MAKE_HASH_KEY(proto_id, evt_id, src_id ? *src_id : SRC_ID_MASK); hndl = scmi_get_or_create_handler(ni, evt_key); - if (!hndl) - return -EINVAL; + if (IS_ERR(hndl)) + return PTR_ERR(hndl); blocking_notifier_chain_register(&hndl->chain, nb); @@ -1416,8 +1437,8 @@ static int scmi_notifier_unregister(const struct scmi_handle *handle, evt_key = MAKE_HASH_KEY(proto_id, evt_id, src_id ? *src_id : SRC_ID_MASK); hndl = scmi_get_handler(ni, evt_key); - if (!hndl) - return -EINVAL; + if (IS_ERR(hndl)) + return PTR_ERR(hndl); /* * Note that this chain unregistration call is safe on its own diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index c7e5a34b254b..683fd9b85c5c 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -892,7 +892,7 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, freq = dom->opp[idx].indicative_freq * dom->mult_factor; /* All OPPs above the sustained frequency are treated as turbo */ - data.turbo = freq > dom->sustained_freq_khz * 1000; + data.turbo = freq > dom->sustained_freq_khz * 1000UL; data.level = dom->opp[idx].perf; data.freq = freq; diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c index 3d543b1d8947..73db5492ab44 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -475,7 +475,8 @@ static void scmi_xfer_raw_worker(struct work_struct *work) raw->desc->ops->mark_txdone(rw->cinfo, ret, xfer); trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id, - xfer->hdr.protocol_id, xfer->hdr.seq, ret); + xfer->hdr.protocol_id, xfer->hdr.seq, + ret, scmi_inflight_count(raw->handle)); /* Wait also for an async delayed response if needed */ if (!ret && xfer->async_done) { @@ -642,7 +643,8 @@ static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw, trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id, xfer->hdr.protocol_id, xfer->hdr.seq, - xfer->hdr.poll_completion); + xfer->hdr.poll_completion, + scmi_inflight_count(raw->handle)); ret = raw->desc->ops->send_message(rw->cinfo, xfer); if (ret) { diff --git a/drivers/firmware/arm_scmi/scmi_power_control.c b/drivers/firmware/arm_scmi/scmi_power_control.c index 21f467a92942..955736336061 100644 --- a/drivers/firmware/arm_scmi/scmi_power_control.c +++ b/drivers/firmware/arm_scmi/scmi_power_control.c @@ -46,6 +46,7 @@ #include <linux/math.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pm.h> #include <linux/printk.h> #include <linux/reboot.h> #include <linux/scmi_protocol.h> @@ -324,12 +325,7 @@ static int scmi_userspace_notifier(struct notifier_block *nb, static void scmi_suspend_work_func(struct work_struct *work) { - struct scmi_syspower_conf *sc = - container_of(work, struct scmi_syspower_conf, suspend_work); - pm_suspend(PM_SUSPEND_MEM); - - sc->state = SCMI_SYSPOWER_IDLE; } static int scmi_syspower_probe(struct scmi_device *sdev) @@ -354,6 +350,7 @@ static int scmi_syspower_probe(struct scmi_device *sdev) sc->required_transition = SCMI_SYSTEM_MAX; sc->userspace_nb.notifier_call = &scmi_userspace_notifier; sc->dev = &sdev->dev; + dev_set_drvdata(&sdev->dev, sc); INIT_WORK(&sc->suspend_work, scmi_suspend_work_func); @@ -363,6 +360,18 @@ static int scmi_syspower_probe(struct scmi_device *sdev) NULL, &sc->userspace_nb); } +static int scmi_system_power_resume(struct device *dev) +{ + struct scmi_syspower_conf *sc = dev_get_drvdata(dev); + + sc->state = SCMI_SYSPOWER_IDLE; + return 0; +} + +static const struct dev_pm_ops scmi_system_power_pmops = { + SYSTEM_SLEEP_PM_OPS(NULL, scmi_system_power_resume) +}; + static const struct scmi_device_id scmi_id_table[] = { { SCMI_PROTOCOL_SYSTEM, "syspower" }, { }, @@ -370,6 +379,9 @@ static const struct scmi_device_id scmi_id_table[] = { MODULE_DEVICE_TABLE(scmi, scmi_id_table); static struct scmi_driver scmi_system_power_driver = { + .driver = { + .pm = pm_sleep_ptr(&scmi_system_power_pmops), + }, .name = "scmi-system-power", .probe = scmi_syspower_probe, .id_table = scmi_id_table, diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 560724ce21aa..f51047d8ea64 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -311,6 +311,11 @@ static const struct cs_dsp_ops cs_dsp_adsp2_ops[]; static const struct cs_dsp_ops cs_dsp_halo_ops; static const struct cs_dsp_ops cs_dsp_halo_ao_ops; +struct cs_dsp_alg_region_list_item { + struct list_head list; + struct cs_dsp_alg_region alg_region; +}; + struct cs_dsp_buf { struct list_head list; void *buf; @@ -1752,13 +1757,13 @@ static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs, struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, int type, unsigned int id) { - struct cs_dsp_alg_region *alg_region; + struct cs_dsp_alg_region_list_item *item; lockdep_assert_held(&dsp->pwr_lock); - list_for_each_entry(alg_region, &dsp->alg_regions, list) { - if (id == alg_region->alg && type == alg_region->type) - return alg_region; + list_for_each_entry(item, &dsp->alg_regions, list) { + if (id == item->alg_region.alg && type == item->alg_region.type) + return &item->alg_region; } return NULL; @@ -1769,35 +1774,35 @@ static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, int type, __be32 id, __be32 ver, __be32 base) { - struct cs_dsp_alg_region *alg_region; + struct cs_dsp_alg_region_list_item *item; - alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); - if (!alg_region) + item = kzalloc(sizeof(*item), GFP_KERNEL); + if (!item) return ERR_PTR(-ENOMEM); - alg_region->type = type; - alg_region->alg = be32_to_cpu(id); - alg_region->ver = be32_to_cpu(ver); - alg_region->base = be32_to_cpu(base); + item->alg_region.type = type; + item->alg_region.alg = be32_to_cpu(id); + item->alg_region.ver = be32_to_cpu(ver); + item->alg_region.base = be32_to_cpu(base); - list_add_tail(&alg_region->list, &dsp->alg_regions); + list_add_tail(&item->list, &dsp->alg_regions); if (dsp->wmfw_ver > 0) - cs_dsp_ctl_fixup_base(dsp, alg_region); + cs_dsp_ctl_fixup_base(dsp, &item->alg_region); - return alg_region; + return &item->alg_region; } static void cs_dsp_free_alg_regions(struct cs_dsp *dsp) { - struct cs_dsp_alg_region *alg_region; + struct cs_dsp_alg_region_list_item *item; while (!list_empty(&dsp->alg_regions)) { - alg_region = list_first_entry(&dsp->alg_regions, - struct cs_dsp_alg_region, - list); - list_del(&alg_region->list); - kfree(alg_region); + item = list_first_entry(&dsp->alg_regions, + struct cs_dsp_alg_region_list_item, + list); + list_del(&item->list); + kfree(item); } } diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index db8c5c03d3a2..16baa038d412 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -286,7 +286,7 @@ config EFI_SBAT config EFI_SBAT_FILE string "Embedded SBAT section file path" - depends on EFI_ZBOOT + depends on EFI_ZBOOT || (EFI_STUB && X86) help SBAT section provides a way to improve SecureBoot revocations of UEFI binaries by introducing a generation-based mechanism. With SBAT, older diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 939a4955e00b..94b05e4451dd 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -22,16 +22,16 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -std=gnu11 \ # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly # disable the stackleak plugin -cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_STACKLEAK_PLUGIN) \ +cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_KSTACK_ERASE) \ -fno-unwind-tables -fno-asynchronous-unwind-tables cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \ -DEFI_HAVE_STRCMP -fno-builtin -fpic \ $(call cc-option,-mno-single-pic-base) \ - $(DISABLE_STACKLEAK_PLUGIN) + $(DISABLE_KSTACK_ERASE) cflags-$(CONFIG_RISCV) += -fpic -DNO_ALTERNATIVE -mno-relax \ - $(DISABLE_STACKLEAK_PLUGIN) -cflags-$(CONFIG_LOONGARCH) += -fpie $(DISABLE_STACKLEAK_PLUGIN) + $(DISABLE_KSTACK_ERASE) +cflags-$(CONFIG_LOONGARCH) += -fpie $(DISABLE_KSTACK_ERASE) cflags-$(CONFIG_EFI_PARAMS_FROM_FDT) += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot index 92e3c73502ba..832deee36e48 100644 --- a/drivers/firmware/efi/libstub/Makefile.zboot +++ b/drivers/firmware/efi/libstub/Makefile.zboot @@ -36,7 +36,7 @@ aflags-zboot-header-$(EFI_ZBOOT_FORWARD_CFI) := \ -DPE_DLL_CHAR_EX=IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT AFLAGS_zboot-header.o += -DMACHINE_TYPE=IMAGE_FILE_MACHINE_$(EFI_ZBOOT_MACH_TYPE) \ - -DZBOOT_EFI_PATH="\"$(realpath $(obj)/vmlinuz.efi.elf)\"" \ + -DZBOOT_EFI_PATH="\"$(abspath $(obj)/vmlinuz.efi.elf)\"" \ -DZBOOT_SIZE_LEN=$(zboot-size-len-y) \ -DCOMP_TYPE="\"$(comp-type-y)\"" \ $(aflags-zboot-header-y) diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds index c3a166675450..367907eb7d86 100644 --- a/drivers/firmware/efi/libstub/zboot.lds +++ b/drivers/firmware/efi/libstub/zboot.lds @@ -29,14 +29,12 @@ SECTIONS . = _etext; } -#ifdef CONFIG_EFI_SBAT .sbat : ALIGN(4096) { _sbat = .; *(.sbat) _esbat = ALIGN(4096); . = _esbat; } -#endif .data : ALIGN(4096) { _data = .; @@ -60,6 +58,6 @@ SECTIONS PROVIDE(__efistub__gzdata_size = ABSOLUTE(__efistub__gzdata_end - __efistub__gzdata_start)); -PROVIDE(__data_rawsize = ABSOLUTE(_edata - _etext)); -PROVIDE(__data_size = ABSOLUTE(_end - _etext)); +PROVIDE(__data_rawsize = ABSOLUTE(_edata - _data)); +PROVIDE(__data_size = ABSOLUTE(_end - _data)); PROVIDE(__sbat_size = ABSOLUTE(_esbat - _sbat)); diff --git a/drivers/firmware/efi/mokvar-table.c b/drivers/firmware/efi/mokvar-table.c index 0a856c3f69a3..aedbbd627706 100644 --- a/drivers/firmware/efi/mokvar-table.c +++ b/drivers/firmware/efi/mokvar-table.c @@ -340,7 +340,7 @@ static int __init efi_mokvar_sysfs_init(void) mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name; mokvar_sysfs->bin_attr.attr.mode = 0400; mokvar_sysfs->bin_attr.size = mokvar_entry->data_size; - mokvar_sysfs->bin_attr.read_new = efi_mokvar_sysfs_read; + mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read; err = sysfs_create_bin_file(mokvar_kobj, &mokvar_sysfs->bin_attr); diff --git a/drivers/firmware/google/cbmem.c b/drivers/firmware/google/cbmem.c index 773d05078e0a..54c3b8b05e5d 100644 --- a/drivers/firmware/google/cbmem.c +++ b/drivers/firmware/google/cbmem.c @@ -86,7 +86,7 @@ static const struct bin_attribute *const bin_attrs[] = { static const struct attribute_group cbmem_entry_group = { .attrs = attrs, - .bin_attrs_new = bin_attrs, + .bin_attrs = bin_attrs, }; static const struct attribute_group *dev_groups[] = { diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index e8fb00dcaf65..0ceccde5a302 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -530,7 +530,7 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, static const struct bin_attribute eventlog_bin_attr = { .attr = {.name = "append_to_eventlog", .mode = 0200}, - .write_new = eventlog_write, + .write = eventlog_write, }; static ssize_t gsmi_clear_eventlog_store(struct kobject *kobj, diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c index d957af6f9349..6138a1653ec5 100644 --- a/drivers/firmware/google/memconsole.c +++ b/drivers/firmware/google/memconsole.c @@ -28,7 +28,7 @@ static ssize_t memconsole_read(struct file *filp, struct kobject *kobp, static struct bin_attribute memconsole_bin_attr = { .attr = {.name = "log", .mode = 0444}, - .read_new = memconsole_read, + .read = memconsole_read, }; void memconsole_setup(ssize_t (*read_func)(char *, loff_t, size_t)) diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index 254ac6545d68..339a3f74b247 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -121,7 +121,7 @@ static int vpd_section_attrib_add(const u8 *key, u32 key_len, info->bin_attr.attr.name = info->key; info->bin_attr.attr.mode = 0444; info->bin_attr.size = value_len; - info->bin_attr.read_new = vpd_attrib_read; + info->bin_attr.read = vpd_attrib_read; info->bin_attr.private = info; info->value = value; @@ -201,7 +201,7 @@ static int vpd_section_init(const char *name, struct vpd_section *sec, sec->bin_attr.attr.name = sec->raw_name; sec->bin_attr.attr.mode = 0444; sec->bin_attr.size = size; - sec->bin_attr.read_new = vpd_section_read; + sec->bin_attr.read = vpd_section_read; sec->bin_attr.private = sec; err = sysfs_create_bin_file(vpd_kobj, &sec->bin_attr); diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index f63b716be5b0..26cd0458aacd 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -1603,7 +1603,13 @@ bool qcom_scm_lmh_dcvsh_available(void) } EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh_available); -int qcom_scm_shm_bridge_enable(void) +/* + * This is only supposed to be called once by the TZMem module. It takes the + * SCM struct device as argument and uses it to pass the call as at the time + * the SHM Bridge is enabled, the SCM is not yet fully set up and doesn't + * accept global user calls. Don't try to use the __scm pointer here. + */ +int qcom_scm_shm_bridge_enable(struct device *scm_dev) { int ret; @@ -1615,11 +1621,11 @@ int qcom_scm_shm_bridge_enable(void) struct qcom_scm_res res; - if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_MP, + if (!__qcom_scm_is_call_available(scm_dev, QCOM_SCM_SVC_MP, QCOM_SCM_MP_SHM_BRIDGE_ENABLE)) return -EOPNOTSUPP; - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(scm_dev, &desc, &res); if (ret) return ret; @@ -1631,7 +1637,7 @@ int qcom_scm_shm_bridge_enable(void) } EXPORT_SYMBOL_GPL(qcom_scm_shm_bridge_enable); -int qcom_scm_shm_bridge_create(struct device *dev, u64 pfn_and_ns_perm_flags, +int qcom_scm_shm_bridge_create(u64 pfn_and_ns_perm_flags, u64 ipfn_and_s_perm_flags, u64 size_and_flags, u64 ns_vmids, u64 *handle) { @@ -1659,7 +1665,7 @@ int qcom_scm_shm_bridge_create(struct device *dev, u64 pfn_and_ns_perm_flags, } EXPORT_SYMBOL_GPL(qcom_scm_shm_bridge_create); -int qcom_scm_shm_bridge_delete(struct device *dev, u64 handle) +int qcom_scm_shm_bridge_delete(u64 handle) { struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_MP, @@ -2250,24 +2256,47 @@ static int qcom_scm_probe(struct platform_device *pdev) if (ret) return ret; - /* Paired with smp_load_acquire() in qcom_scm_is_available(). */ - smp_store_release(&__scm, scm); + ret = of_reserved_mem_device_init(scm->dev); + if (ret && ret != -ENODEV) + return dev_err_probe(scm->dev, ret, + "Failed to setup the reserved memory region for TZ mem\n"); + + ret = qcom_tzmem_enable(scm->dev); + if (ret) + return dev_err_probe(scm->dev, ret, + "Failed to enable the TrustZone memory allocator\n"); + + memset(&pool_config, 0, sizeof(pool_config)); + pool_config.initial_size = 0; + pool_config.policy = QCOM_TZMEM_POLICY_ON_DEMAND; + pool_config.max_size = SZ_256K; + + scm->mempool = devm_qcom_tzmem_pool_new(scm->dev, &pool_config); + if (IS_ERR(scm->mempool)) + return dev_err_probe(scm->dev, PTR_ERR(scm->mempool), + "Failed to create the SCM memory pool\n"); irq = platform_get_irq_optional(pdev, 0); if (irq < 0) { - if (irq != -ENXIO) { - ret = irq; - goto err; - } + if (irq != -ENXIO) + return irq; } else { - ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler, - IRQF_ONESHOT, "qcom-scm", __scm); - if (ret < 0) { - dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n"); - goto err; - } + ret = devm_request_threaded_irq(scm->dev, irq, NULL, qcom_scm_irq_handler, + IRQF_ONESHOT, "qcom-scm", scm); + if (ret < 0) + return dev_err_probe(scm->dev, ret, + "Failed to request qcom-scm irq\n"); } + /* + * Paired with smp_load_acquire() in qcom_scm_is_available(). + * + * This marks the SCM API as ready to accept user calls and can only + * be called after the TrustZone memory pool is initialized and the + * waitqueue interrupt requested. + */ + smp_store_release(&__scm, scm); + __get_convention(); /* @@ -2283,32 +2312,6 @@ static int qcom_scm_probe(struct platform_device *pdev) if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled") || !download_mode) qcom_scm_disable_sdi(); - ret = of_reserved_mem_device_init(__scm->dev); - if (ret && ret != -ENODEV) { - dev_err_probe(__scm->dev, ret, - "Failed to setup the reserved memory region for TZ mem\n"); - goto err; - } - - ret = qcom_tzmem_enable(__scm->dev); - if (ret) { - dev_err_probe(__scm->dev, ret, - "Failed to enable the TrustZone memory allocator\n"); - goto err; - } - - memset(&pool_config, 0, sizeof(pool_config)); - pool_config.initial_size = 0; - pool_config.policy = QCOM_TZMEM_POLICY_ON_DEMAND; - pool_config.max_size = SZ_256K; - - __scm->mempool = devm_qcom_tzmem_pool_new(__scm->dev, &pool_config); - if (IS_ERR(__scm->mempool)) { - ret = dev_err_probe(__scm->dev, PTR_ERR(__scm->mempool), - "Failed to create the SCM memory pool\n"); - goto err; - } - /* * Initialize the QSEECOM interface. * @@ -2323,12 +2326,6 @@ static int qcom_scm_probe(struct platform_device *pdev) WARN(ret < 0, "failed to initialize qseecom: %d\n", ret); return 0; - -err: - /* Paired with smp_load_acquire() in qcom_scm_is_available(). */ - smp_store_release(&__scm, NULL); - - return ret; } static void qcom_scm_shutdown(struct platform_device *pdev) diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index 3133d826f5fa..0e8dd838099e 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -83,6 +83,7 @@ int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, struct qcom_scm_res *res); struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void); +int qcom_scm_shm_bridge_enable(struct device *scm_dev); #define QCOM_SCM_SVC_BOOT 0x01 #define QCOM_SCM_BOOT_SET_ADDR 0x01 diff --git a/drivers/firmware/qcom/qcom_tzmem.c b/drivers/firmware/qcom/qcom_tzmem.c index 94196ad87105..ea0a35355657 100644 --- a/drivers/firmware/qcom/qcom_tzmem.c +++ b/drivers/firmware/qcom/qcom_tzmem.c @@ -20,6 +20,7 @@ #include <linux/spinlock.h> #include <linux/types.h> +#include "qcom_scm.h" #include "qcom_tzmem.h" struct qcom_tzmem_area { @@ -94,7 +95,7 @@ static int qcom_tzmem_init(void) goto notsupp; } - ret = qcom_scm_shm_bridge_enable(); + ret = qcom_scm_shm_bridge_enable(qcom_tzmem_dev); if (ret == -EOPNOTSUPP) goto notsupp; @@ -124,9 +125,9 @@ static int qcom_tzmem_init_area(struct qcom_tzmem_area *area) if (!handle) return -ENOMEM; - ret = qcom_scm_shm_bridge_create(qcom_tzmem_dev, pfn_and_ns_perm, - ipfn_and_s_perm, size_and_flags, - QCOM_SCM_VMID_HLOS, handle); + ret = qcom_scm_shm_bridge_create(pfn_and_ns_perm, ipfn_and_s_perm, + size_and_flags, QCOM_SCM_VMID_HLOS, + handle); if (ret) return ret; @@ -142,7 +143,7 @@ static void qcom_tzmem_cleanup_area(struct qcom_tzmem_area *area) if (!qcom_tzmem_using_shm_bridge) return; - qcom_scm_shm_bridge_delete(qcom_tzmem_dev, *handle); + qcom_scm_shm_bridge_delete(*handle); kfree(handle); } diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 2615fb780e3c..0eebd572f9a5 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -476,7 +476,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, struct kobject *kobj, static const struct bin_attribute fw_cfg_sysfs_attr_raw = { .attr = { .name = "raw", .mode = S_IRUSR }, - .read_new = fw_cfg_sysfs_read_raw, + .read = fw_cfg_sysfs_read_raw, }; /* diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c index cd65b434dc6e..bdee057db2fd 100644 --- a/drivers/firmware/smccc/smccc.c +++ b/drivers/firmware/smccc/smccc.c @@ -72,10 +72,7 @@ bool arm_smccc_hypervisor_has_uuid(const uuid_t *hyp_uuid) struct arm_smccc_res res = {}; uuid_t uuid; - if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_HVC) - return false; - - arm_smccc_1_1_hvc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res); + arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res); if (res.a0 == SMCCC_RET_NOT_SUPPORTED) return false; diff --git a/drivers/firmware/tegra/Kconfig b/drivers/firmware/tegra/Kconfig index cde1ab8bd9d1..91f2320c0d0f 100644 --- a/drivers/firmware/tegra/Kconfig +++ b/drivers/firmware/tegra/Kconfig @@ -2,7 +2,7 @@ menu "Tegra firmware driver" config TEGRA_IVC - bool "Tegra IVC protocol" + bool "Tegra IVC protocol" if COMPILE_TEST depends on ARCH_TEGRA help IVC (Inter-VM Communication) protocol is part of the IPC @@ -13,8 +13,9 @@ config TEGRA_IVC config TEGRA_BPMP bool "Tegra BPMP driver" - depends on ARCH_TEGRA && TEGRA_HSP_MBOX && TEGRA_IVC + depends on ARCH_TEGRA && TEGRA_HSP_MBOX depends on !CPU_BIG_ENDIAN + select TEGRA_IVC help BPMP (Boot and Power Management Processor) is designed to off-loading the PM functions which include clock/DVFS/thermal/power from the CPU. diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile index 620cf3fdd607..41e2e4dc31d6 100644 --- a/drivers/firmware/tegra/Makefile +++ b/drivers/firmware/tegra/Makefile @@ -4,6 +4,7 @@ tegra-bpmp-$(CONFIG_ARCH_TEGRA_210_SOC) += bpmp-tegra210.o tegra-bpmp-$(CONFIG_ARCH_TEGRA_186_SOC) += bpmp-tegra186.o tegra-bpmp-$(CONFIG_ARCH_TEGRA_194_SOC) += bpmp-tegra186.o tegra-bpmp-$(CONFIG_ARCH_TEGRA_234_SOC) += bpmp-tegra186.o +tegra-bpmp-$(CONFIG_ARCH_TEGRA_264_SOC) += bpmp-tegra186.o tegra-bpmp-$(CONFIG_DEBUG_FS) += bpmp-debugfs.o obj-$(CONFIG_TEGRA_BPMP) += tegra-bpmp.o obj-$(CONFIG_TEGRA_IVC) += ivc.o diff --git a/drivers/firmware/tegra/bpmp-private.h b/drivers/firmware/tegra/bpmp-private.h index 182bfe396516..07c3d46abb87 100644 --- a/drivers/firmware/tegra/bpmp-private.h +++ b/drivers/firmware/tegra/bpmp-private.h @@ -23,13 +23,7 @@ struct tegra_bpmp_ops { int (*resume)(struct tegra_bpmp *bpmp); }; -#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) extern const struct tegra_bpmp_ops tegra186_bpmp_ops; -#endif -#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) extern const struct tegra_bpmp_ops tegra210_bpmp_ops; -#endif #endif diff --git a/drivers/firmware/tegra/bpmp-tegra186.c b/drivers/firmware/tegra/bpmp-tegra186.c index 6f0d0511b486..7cfc5fdfa49d 100644 --- a/drivers/firmware/tegra/bpmp-tegra186.c +++ b/drivers/firmware/tegra/bpmp-tegra186.c @@ -6,7 +6,7 @@ #include <linux/genalloc.h> #include <linux/io.h> #include <linux/mailbox_client.h> -#include <linux/of_address.h> +#include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <soc/tegra/bpmp.h> @@ -192,16 +192,11 @@ static void tegra186_bpmp_teardown_channels(struct tegra_bpmp *bpmp) static int tegra186_bpmp_dram_init(struct tegra_bpmp *bpmp) { struct tegra186_bpmp *priv = bpmp->priv; - struct device_node *np; struct resource res; size_t size; int err; - np = of_parse_phandle(bpmp->dev->of_node, "memory-region", 0); - if (!np) - return -ENODEV; - - err = of_address_to_resource(np, 0, &res); + err = of_reserved_mem_region_to_resource(bpmp->dev->of_node, 0, &res); if (err < 0) { dev_warn(bpmp->dev, "failed to parse memory region: %d\n", err); return err; diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index c3a1dc344961..e74bba7ccc44 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -836,7 +836,8 @@ static const struct dev_pm_ops tegra_bpmp_pm_ops = { #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_264_SOC) static const struct tegra_bpmp_soc tegra186_soc = { .channels = { .cpu_tx = { @@ -884,7 +885,8 @@ static const struct tegra_bpmp_soc tegra210_soc = { static const struct of_device_id tegra_bpmp_match[] = { #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_264_SOC) { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc }, #endif #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 7356e860e65c..02da3e48bc8f 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -20,6 +20,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/hashtable.h> @@ -1299,11 +1300,10 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write); * This API function is to be used for notify the power management controller * about the completed power management initialization. */ -int zynqmp_pm_init_finalize(void) +static int zynqmp_pm_init_finalize(void) { return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, NULL, 0); } -EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize); /** * zynqmp_pm_set_suspend_mode() - Set system suspend mode @@ -2100,6 +2100,19 @@ static void zynqmp_firmware_remove(struct platform_device *pdev) platform_device_unregister(em_dev); } +static void zynqmp_firmware_sync_state(struct device *dev) +{ + struct device_node *np = dev->of_node; + + if (!of_device_is_compatible(np, "xlnx,zynqmp-firmware")) + return; + + of_genpd_sync_state(np); + + if (zynqmp_pm_init_finalize()) + dev_warn(dev, "failed to release power management to firmware\n"); +} + static const struct of_device_id zynqmp_firmware_of_match[] = { {.compatible = "xlnx,zynqmp-firmware"}, {.compatible = "xlnx,versal-firmware"}, @@ -2112,6 +2125,7 @@ static struct platform_driver zynqmp_firmware_driver = { .name = "zynqmp_firmware", .of_match_table = zynqmp_firmware_of_match, .dev_groups = zynqmp_firmware_groups, + .sync_state = zynqmp_firmware_sync_state, }, .probe = zynqmp_firmware_probe, .remove = zynqmp_firmware_remove, |