diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/arm_scmi/virtio.c | 2 | ||||
-rw-r--r-- | drivers/firmware/cirrus/cs_dsp.c | 156 | ||||
-rw-r--r-- | drivers/firmware/dmi-sysfs.c | 7 | ||||
-rw-r--r-- | drivers/firmware/edd.c | 9 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-init.c | 5 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 7 | ||||
-rw-r--r-- | drivers/firmware/efi/efivars.c | 3 | ||||
-rw-r--r-- | drivers/firmware/efi/esrt.c | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm64-stub.c | 6 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 73 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub.c | 12 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 30 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/x86-stub.c | 26 | ||||
-rw-r--r-- | drivers/firmware/efi/runtime-map.c | 3 | ||||
-rw-r--r-- | drivers/firmware/google/Kconfig | 6 | ||||
-rw-r--r-- | drivers/firmware/memmap.c | 3 | ||||
-rw-r--r-- | drivers/firmware/qemu_fw_cfg.c | 26 | ||||
-rw-r--r-- | drivers/firmware/scpi_pm_domain.c | 10 | ||||
-rw-r--r-- | drivers/firmware/sysfb_simplefb.c | 10 | ||||
-rw-r--r-- | drivers/firmware/tegra/bpmp-debugfs.c | 5 | ||||
-rw-r--r-- | drivers/firmware/ti_sci.c | 2 | ||||
-rw-r--r-- | drivers/firmware/xilinx/zynqmp.c | 45 |
22 files changed, 323 insertions, 127 deletions
diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/virtio.c index 87039c5c03fd..eefcc4146749 100644 --- a/drivers/firmware/arm_scmi/virtio.c +++ b/drivers/firmware/arm_scmi/virtio.c @@ -452,7 +452,7 @@ static void scmi_vio_remove(struct virtio_device *vdev) * outstanding message on any vqueue to be ignored by complete_cb: now * we can just stop processing buffers and destroy the vqueues. */ - vdev->config->reset(vdev); + virtio_reset_device(vdev); vdev->config->del_vqs(vdev); /* Ensure scmi_vdev is visible as NULL */ smp_store_mb(scmi_vdev, NULL); diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 948dd8382686..e48108e694f8 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -12,16 +12,10 @@ #include <linux/ctype.h> #include <linux/debugfs.h> #include <linux/delay.h> -#include <linux/device.h> -#include <linux/firmware.h> -#include <linux/interrupt.h> -#include <linux/list.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/regmap.h> #include <linux/slab.h> #include <linux/vmalloc.h> -#include <linux/workqueue.h> #include <linux/firmware/cirrus/cs_dsp.h> #include <linux/firmware/cirrus/wmfw.h> @@ -622,7 +616,8 @@ static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp) offs[0], offs[1], offs[2], offs[3]); } -static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg) +static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg, + unsigned int off) { const struct cs_dsp_alg_region *alg_region = &ctl->alg_region; struct cs_dsp *dsp = ctl->dsp; @@ -635,7 +630,7 @@ static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg return -EINVAL; } - *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset); + *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset + off); return 0; } @@ -659,10 +654,12 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int unsigned int reg; int i, ret; + lockdep_assert_held(&dsp->pwr_lock); + if (!dsp->running) return -EPERM; - ret = cs_dsp_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®, 0); if (ret) return ret; @@ -716,14 +713,14 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control); static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, - const void *buf, size_t len) + unsigned int off, const void *buf, size_t len) { struct cs_dsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - ret = cs_dsp_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®, off); if (ret) return ret; @@ -749,38 +746,49 @@ static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, /** * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control * @ctl: pointer to coefficient control + * @off: word offset at which data should be written * @buf: the buffer to write to the given control - * @len: the length of the buffer + * @len: the length of the buffer in bytes * * Must be called with pwr_lock held. * * Return: Zero for success, a negative number on error. */ -int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, const void *buf, size_t len) +int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, + unsigned int off, const void *buf, size_t len) { int ret = 0; + if (!ctl) + return -ENOENT; + + lockdep_assert_held(&ctl->dsp->pwr_lock); + + if (len + off * sizeof(u32) > ctl->len) + return -EINVAL; + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) ret = -EPERM; else if (buf != ctl->cache) - memcpy(ctl->cache, buf, len); + memcpy(ctl->cache + off * sizeof(u32), buf, len); ctl->set = 1; if (ctl->enabled && ctl->dsp->running) - ret = cs_dsp_coeff_write_ctrl_raw(ctl, buf, len); + ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len); return ret; } EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl); -static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) +static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, + unsigned int off, void *buf, size_t len) { struct cs_dsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - ret = cs_dsp_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®, off); if (ret) return ret; @@ -806,28 +814,38 @@ static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, void *buf, s /** * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer * @ctl: pointer to coefficient control + * @off: word offset at which data should be read * @buf: the buffer to store to the given control - * @len: the length of the buffer + * @len: the length of the buffer in bytes * * Must be called with pwr_lock held. * * Return: Zero for success, a negative number on error. */ -int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) +int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, + unsigned int off, void *buf, size_t len) { int ret = 0; + if (!ctl) + return -ENOENT; + + lockdep_assert_held(&ctl->dsp->pwr_lock); + + if (len + off * sizeof(u32) > ctl->len) + return -EINVAL; + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { if (ctl->enabled && ctl->dsp->running) - return cs_dsp_coeff_read_ctrl_raw(ctl, buf, len); + return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len); else return -EPERM; } else { if (!ctl->flags && ctl->enabled && ctl->dsp->running) - ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); + ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); if (buf != ctl->cache) - memcpy(buf, ctl->cache, len); + memcpy(buf, ctl->cache + off * sizeof(u32), len); } return ret; @@ -851,7 +869,7 @@ static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp) * created so we don't need to do anything. */ if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) { - ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); + ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); if (ret < 0) return ret; } @@ -869,7 +887,7 @@ static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp) if (!ctl->enabled) continue; if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { - ret = cs_dsp_coeff_write_ctrl_raw(ctl, ctl->cache, + ret = cs_dsp_coeff_write_ctrl_raw(ctl, 0, ctl->cache, ctl->len); if (ret < 0) return ret; @@ -1159,6 +1177,7 @@ static int cs_dsp_parse_coeff(struct cs_dsp *dsp, return -EINVAL; break; case WMFW_CTL_TYPE_HOSTEVENT: + case WMFW_CTL_TYPE_FWEVENT: ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | @@ -1459,6 +1478,8 @@ struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, in { struct cs_dsp_coeff_ctl *pos, *rslt = NULL; + lockdep_assert_held(&dsp->pwr_lock); + list_for_each_entry(pos, &dsp->ctl_list, list) { if (!pos->subname) continue; @@ -1554,6 +1575,8 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, { struct cs_dsp_alg_region *alg_region; + 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; @@ -1565,7 +1588,7 @@ EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region); static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, int type, __be32 id, - __be32 base) + __be32 ver, __be32 base) { struct cs_dsp_alg_region *alg_region; @@ -1575,6 +1598,7 @@ static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, 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); list_add_tail(&alg_region->list, &dsp->alg_regions); @@ -1624,14 +1648,14 @@ static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp, nalgs); } -static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, int nregions, - const int *type, __be32 *base) +static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, + int nregions, const int *type, __be32 *base) { struct cs_dsp_alg_region *alg_region; int i; for (i = 0; i < nregions; i++) { - alg_region = cs_dsp_create_region(dsp, type[i], id, base[i]); + alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); } @@ -1666,12 +1690,14 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, - adsp1_id.fw.id, adsp1_id.zm); + adsp1_id.fw.id, adsp1_id.fw.ver, + adsp1_id.zm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, - adsp1_id.fw.id, adsp1_id.dm); + adsp1_id.fw.id, adsp1_id.fw.ver, + adsp1_id.dm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); @@ -1694,6 +1720,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, adsp1_alg[i].alg.id, + adsp1_alg[i].alg.ver, adsp1_alg[i].dm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1715,6 +1742,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, adsp1_alg[i].alg.id, + adsp1_alg[i].alg.ver, adsp1_alg[i].zm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1767,17 +1795,20 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, - adsp2_id.fw.id, adsp2_id.xm); + adsp2_id.fw.id, adsp2_id.fw.ver, + adsp2_id.xm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, - adsp2_id.fw.id, adsp2_id.ym); + adsp2_id.fw.id, adsp2_id.fw.ver, + adsp2_id.ym); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, - adsp2_id.fw.id, adsp2_id.zm); + adsp2_id.fw.id, adsp2_id.fw.ver, + adsp2_id.zm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); @@ -1802,6 +1833,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, adsp2_alg[i].alg.id, + adsp2_alg[i].alg.ver, adsp2_alg[i].xm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1823,6 +1855,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, adsp2_alg[i].alg.id, + adsp2_alg[i].alg.ver, adsp2_alg[i].ym); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1844,6 +1877,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, adsp2_alg[i].alg.id, + adsp2_alg[i].alg.ver, adsp2_alg[i].zm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1869,7 +1903,7 @@ out: return ret; } -static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, +static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, __be32 xm_base, __be32 ym_base) { static const int types[] = { @@ -1878,7 +1912,7 @@ static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, }; __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; - return cs_dsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases); + return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases); } static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) @@ -1906,7 +1940,7 @@ static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs); - ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, + ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver, halo_id.xm_base, halo_id.ym_base); if (ret) return ret; @@ -1930,6 +1964,7 @@ static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) be32_to_cpu(halo_alg[i].ym_base)); ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, + halo_alg[i].alg.ver, halo_alg[i].xm_base, halo_alg[i].ym_base); if (ret) @@ -1951,7 +1986,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware const struct cs_dsp_region *mem; struct cs_dsp_alg_region *alg_region; const char *region_name; - int ret, pos, blocks, type, offset, reg; + int ret, pos, blocks, type, offset, reg, version; + char *text = NULL; struct cs_dsp_buf *buf; if (!firmware) @@ -1973,6 +2009,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware switch (be32_to_cpu(hdr->rev) & 0xff) { case 1: + case 2: break; default: cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n", @@ -1995,6 +2032,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware type = le16_to_cpu(blk->type); offset = le16_to_cpu(blk->offset); + version = le32_to_cpu(blk->ver) >> 8; cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", file, blocks, le32_to_cpu(blk->id), @@ -2008,6 +2046,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware region_name = "Unknown"; switch (type) { case (WMFW_NAME_TEXT << 8): + text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL); + break; case (WMFW_INFO_TEXT << 8): case (WMFW_METADATA << 8): break; @@ -2052,6 +2092,16 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware alg_region = cs_dsp_find_alg_region(dsp, type, le32_to_cpu(blk->id)); if (alg_region) { + if (version != alg_region->ver) + cs_dsp_warn(dsp, + "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n", + (version >> 16) & 0xFF, + (version >> 8) & 0xFF, + version & 0xFF, + (alg_region->ver >> 16) & 0xFF, + (alg_region->ver >> 8) & 0xFF, + alg_region->ver & 0xFF); + reg = alg_region->base; reg = dsp->ops->region_to_reg(mem, reg); reg += offset; @@ -2067,6 +2117,13 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware break; } + if (text) { + memcpy(text, blk->data, le32_to_cpu(blk->len)); + cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text); + kfree(text); + text = NULL; + } + if (reg) { if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) { @@ -2117,6 +2174,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware out_fw: regmap_async_complete(regmap); cs_dsp_buf_free(&buf_list); + kfree(text); return ret; } @@ -2600,6 +2658,12 @@ int cs_dsp_run(struct cs_dsp *dsp) goto err; } + if (dsp->client_ops->pre_run) { + ret = dsp->client_ops->pre_run(dsp); + if (ret) + goto err; + } + /* Sync set controls */ ret = cs_dsp_coeff_sync_controls(dsp); if (ret != 0) @@ -2680,10 +2744,16 @@ EXPORT_SYMBOL_GPL(cs_dsp_stop); static int cs_dsp_halo_start_core(struct cs_dsp *dsp) { - return regmap_update_bits(dsp->regmap, - dsp->base + HALO_CCM_CORE_CONTROL, - HALO_CORE_RESET | HALO_CORE_EN, - HALO_CORE_RESET | HALO_CORE_EN); + int ret; + + ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, + HALO_CORE_RESET | HALO_CORE_EN, + HALO_CORE_RESET | HALO_CORE_EN); + if (ret) + return ret; + + return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, + HALO_CORE_RESET, 0); } static void cs_dsp_halo_stop_core(struct cs_dsp *dsp) @@ -2789,6 +2859,8 @@ int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int me unsigned int reg; int ret; + lockdep_assert_held(&dsp->pwr_lock); + if (!mem) return -EINVAL; @@ -2842,6 +2914,8 @@ int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_ad __be32 val = cpu_to_be32(data & 0x00ffffffu); unsigned int reg; + lockdep_assert_held(&dsp->pwr_lock); + if (!mem) return -EINVAL; diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c index 8b8127fa8955..3a353776bd34 100644 --- a/drivers/firmware/dmi-sysfs.c +++ b/drivers/firmware/dmi-sysfs.c @@ -302,12 +302,12 @@ static struct attribute *dmi_sysfs_sel_attrs[] = { &dmi_sysfs_attr_sel_per_log_type_descriptor_length.attr, NULL, }; - +ATTRIBUTE_GROUPS(dmi_sysfs_sel); static struct kobj_type dmi_system_event_log_ktype = { .release = dmi_entry_free, .sysfs_ops = &dmi_sysfs_specialize_attr_ops, - .default_attrs = dmi_sysfs_sel_attrs, + .default_groups = dmi_sysfs_sel_groups, }; typedef u8 (*sel_io_reader)(const struct dmi_system_event_log *sel, @@ -518,6 +518,7 @@ static struct attribute *dmi_sysfs_entry_attrs[] = { &dmi_sysfs_attr_entry_position.attr, NULL, }; +ATTRIBUTE_GROUPS(dmi_sysfs_entry); static ssize_t dmi_entry_raw_read_helper(struct dmi_sysfs_entry *entry, const struct dmi_header *dh, @@ -565,7 +566,7 @@ static void dmi_sysfs_entry_release(struct kobject *kobj) static struct kobj_type dmi_sysfs_entry_ktype = { .release = dmi_sysfs_entry_release, .sysfs_ops = &dmi_sysfs_attr_ops, - .default_attrs = dmi_sysfs_entry_attrs, + .default_groups = dmi_sysfs_entry_groups, }; static struct kset *dmi_kset; diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 14d0970a7198..69353dd0ea22 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -574,14 +574,6 @@ static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30); static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30); static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_mbr_signature, edd_has_mbr_signature); - -/* These are default attributes that are added for every edd - * device discovered. There are none. - */ -static struct attribute * def_attrs[] = { - NULL, -}; - /* These attributes are conditional and only added for some devices. */ static struct edd_attribute * edd_attrs[] = { &edd_attr_raw_data, @@ -619,7 +611,6 @@ static void edd_release(struct kobject * kobj) static struct kobj_type edd_ktype = { .release = edd_release, .sysfs_ops = &edd_attr_ops, - .default_attrs = def_attrs, }; static struct kset *edd_kset; diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c index b19ce1a83f91..b2c829e95bd1 100644 --- a/drivers/firmware/efi/efi-init.c +++ b/drivers/firmware/efi/efi-init.c @@ -235,6 +235,11 @@ void __init efi_init(void) } reserve_regions(); + /* + * For memblock manipulation, the cap should come after the memblock_add(). + * And now, memblock is fully populated, it is time to do capping. + */ + early_init_dt_check_for_usable_mem_range(); efi_esrt_init(); efi_mokvar_table_init(); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index ae79c3300129..7de3f5b6e8d0 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -722,6 +722,13 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr, systab_hdr->revision >> 16, systab_hdr->revision & 0xffff, vendor); + + if (IS_ENABLED(CONFIG_X86_64) && + systab_hdr->revision > EFI_1_10_SYSTEM_TABLE_REVISION && + !strcmp(vendor, "Apple")) { + pr_info("Apple Mac detected, using EFI v1.10 runtime services only\n"); + efi.runtime_version = EFI_1_10_SYSTEM_TABLE_REVISION; + } } static __initdata char memory_type_name[][13] = { diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index e6b16b3a17a8..ea0bc39dc965 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -352,11 +352,12 @@ static struct attribute *def_attrs[] = { &efivar_attr_raw_var.attr, NULL, }; +ATTRIBUTE_GROUPS(def); static struct kobj_type efivar_ktype = { .release = efivar_release, .sysfs_ops = &efivar_attr_ops, - .default_attrs = def_attrs, + .default_groups = def_groups, }; static ssize_t efivar_create(struct file *filp, struct kobject *kobj, diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index d5915272141f..2a2f52b017e7 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -146,6 +146,8 @@ static struct attribute *esre1_attrs[] = { &esre_last_attempt_status.attr, NULL }; +ATTRIBUTE_GROUPS(esre1); + static void esre_release(struct kobject *kobj) { struct esre_entry *entry = to_entry(kobj); @@ -157,7 +159,7 @@ static void esre_release(struct kobject *kobj) static struct kobj_type esre1_ktype = { .release = esre_release, .sysfs_ops = &esre_attr_ops, - .default_attrs = esre1_attrs, + .default_groups = esre1_groups, }; diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index 2363fee9211c..9cc556013d08 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -119,9 +119,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, if (image->image_base != _text) efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n"); - if (!IS_ALIGNED((u64)_text, EFI_KIMG_ALIGN)) - efi_err("FIRMWARE BUG: kernel image not aligned on %ldk boundary\n", - EFI_KIMG_ALIGN >> 10); + if (!IS_ALIGNED((u64)_text, SEGMENT_ALIGN)) + efi_err("FIRMWARE BUG: kernel image not aligned on %dk boundary\n", + SEGMENT_ALIGN >> 10); kernel_size = _edata - _text; kernel_memsize = kernel_size + (_end - _edata); diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index d489bdc645fe..3d972061c1b0 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -20,10 +20,10 @@ bool efi_nochunk; bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE); -bool efi_noinitrd; int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT; bool efi_novamap; +static bool efi_noinitrd; static bool efi_nosoftreserve; static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); @@ -625,6 +625,47 @@ efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image, load_addr, load_size); } +static const struct { + efi_tcg2_event_t event_data; + efi_tcg2_tagged_event_t tagged_event; + u8 tagged_event_data[]; +} initrd_tcg2_event = { + { + sizeof(initrd_tcg2_event) + sizeof("Linux initrd"), + { + sizeof(initrd_tcg2_event.event_data.event_header), + EFI_TCG2_EVENT_HEADER_VERSION, + 9, + EV_EVENT_TAG, + }, + }, + { + INITRD_EVENT_TAG_ID, + sizeof("Linux initrd"), + }, + { "Linux initrd" }, +}; + +static void efi_measure_initrd(unsigned long load_addr, unsigned long load_size) +{ + efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; + efi_tcg2_protocol_t *tcg2 = NULL; + efi_status_t status; + + efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2); + if (tcg2) { + status = efi_call_proto(tcg2, hash_log_extend_event, + 0, load_addr, load_size, + &initrd_tcg2_event.event_data); + if (status != EFI_SUCCESS) + efi_warn("Failed to measure initrd data: 0x%lx\n", + status); + else + efi_info("Measured initrd data into PCR %d\n", + initrd_tcg2_event.event_data.event_header.pcr_index); + } +} + /** * efi_load_initrd() - Load initial RAM disk * @image: EFI loaded image protocol @@ -643,17 +684,25 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, { efi_status_t status; - if (!load_addr || !load_size) - return EFI_INVALID_PARAMETER; - - status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit); - if (status == EFI_SUCCESS) { - efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); - } else if (status == EFI_NOT_FOUND) { - status = efi_load_initrd_cmdline(image, load_addr, load_size, - soft_limit, hard_limit); - if (status == EFI_SUCCESS && *load_size > 0) - efi_info("Loaded initrd from command line option\n"); + if (efi_noinitrd) { + *load_addr = *load_size = 0; + status = EFI_SUCCESS; + } else { + status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit); + if (status == EFI_SUCCESS) { + efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); + if (*load_size > 0) + efi_measure_initrd(*load_addr, *load_size); + } else if (status == EFI_NOT_FOUND) { + status = efi_load_initrd_cmdline(image, load_addr, load_size, + soft_limit, hard_limit); + if (status == EFI_SUCCESS && *load_size > 0) + efi_info("Loaded initrd from command line option\n"); + } + if (status != EFI_SUCCESS) { + efi_err("Failed to load initrd: 0x%lx\n", status); + *load_addr = *load_size = 0; + } } return status; diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index 26e69788f27a..da93864d7abc 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -40,6 +40,8 @@ #ifdef CONFIG_ARM64 # define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_64 +#elif defined(CONFIG_RISCV) +# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN #else # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE #endif @@ -134,7 +136,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, enum efi_secureboot_mode secure_boot; struct screen_info *si; efi_properties_table_t *prop_tbl; - unsigned long max_addr; efi_system_table = sys_table_arg; @@ -240,13 +241,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, if (!fdt_addr) efi_info("Generating empty DTB\n"); - if (!efi_noinitrd) { - max_addr = efi_get_max_initrd_addr(image_addr); - status = efi_load_initrd(image, &initrd_addr, &initrd_size, - ULONG_MAX, max_addr); - if (status != EFI_SUCCESS) - efi_err("Failed to load initrd!\n"); - } + efi_load_initrd(image, &initrd_addr, &initrd_size, ULONG_MAX, + efi_get_max_initrd_addr(image_addr)); efi_random_get_seed(); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index cde0a2ef507d..edb77b0621ea 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -31,7 +31,6 @@ extern bool efi_nochunk; extern bool efi_nokaslr; -extern bool efi_noinitrd; extern int efi_loglevel; extern bool efi_novamap; @@ -667,6 +666,29 @@ union apple_properties_protocol { typedef u32 efi_tcg2_event_log_format; +#define INITRD_EVENT_TAG_ID 0x8F3B22ECU +#define EV_EVENT_TAG 0x00000006U +#define EFI_TCG2_EVENT_HEADER_VERSION 0x1 + +struct efi_tcg2_event { + u32 event_size; + struct { + u32 header_size; + u16 header_version; + u32 pcr_index; + u32 event_type; + } __packed event_header; + /* u8[] event follows here */ +} __packed; + +struct efi_tcg2_tagged_event { + u32 tagged_event_id; + u32 tagged_event_data_size; + /* u8 tagged event data follows here */ +} __packed; + +typedef struct efi_tcg2_event efi_tcg2_event_t; +typedef struct efi_tcg2_tagged_event efi_tcg2_tagged_event_t; typedef union efi_tcg2_protocol efi_tcg2_protocol_t; union efi_tcg2_protocol { @@ -677,7 +699,11 @@ union efi_tcg2_protocol { efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *); - void *hash_log_extend_event; + efi_status_t (__efiapi *hash_log_extend_event)(efi_tcg2_protocol_t *, + u64, + efi_physical_addr_t, + u64, + const efi_tcg2_event_t *); void *submit_command; void *get_active_pcr_banks; void *set_active_pcr_banks; diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index f14c4ff5839f..01ddd4502e28 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -673,6 +673,7 @@ unsigned long efi_main(efi_handle_t handle, unsigned long bzimage_addr = (unsigned long)startup_32; unsigned long buffer_start, buffer_end; struct setup_header *hdr = &boot_params->hdr; + unsigned long addr, size; efi_status_t status; efi_system_table = sys_table_arg; @@ -761,22 +762,15 @@ unsigned long efi_main(efi_handle_t handle, * arguments will be processed only if image is not NULL, which will be * the case only if we were loaded via the PE entry point. */ - if (!efi_noinitrd) { - unsigned long addr, size; - - status = efi_load_initrd(image, &addr, &size, - hdr->initrd_addr_max, ULONG_MAX); - - if (status != EFI_SUCCESS) { - efi_err("Failed to load initrd!\n"); - goto fail; - } - if (size > 0) { - efi_set_u64_split(addr, &hdr->ramdisk_image, - &boot_params->ext_ramdisk_image); - efi_set_u64_split(size, &hdr->ramdisk_size, - &boot_params->ext_ramdisk_size); - } + status = efi_load_initrd(image, &addr, &size, hdr->initrd_addr_max, + ULONG_MAX); + if (status != EFI_SUCCESS) + goto fail; + if (size > 0) { + efi_set_u64_split(addr, &hdr->ramdisk_image, + &boot_params->ext_ramdisk_image); + efi_set_u64_split(size, &hdr->ramdisk_size, + &boot_params->ext_ramdisk_size); } /* diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index ad9ddefc9dcb..92a3d45a795c 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -79,6 +79,7 @@ static struct attribute *def_attrs[] = { &map_attribute_attr.attr, NULL }; +ATTRIBUTE_GROUPS(def); static const struct sysfs_ops map_attr_ops = { .show = map_attr_show, @@ -94,7 +95,7 @@ static void map_release(struct kobject *kobj) static struct kobj_type __refdata map_ktype = { .sysfs_ops = &map_attr_ops, - .default_attrs = def_attrs, + .default_groups = def_groups, .release = map_release, }; diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 97968aece54f..931544c9f63d 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -3,9 +3,9 @@ menuconfig GOOGLE_FIRMWARE bool "Google Firmware Drivers" default n help - These firmware drivers are used by Google's servers. They are - only useful if you are working directly on one of their - proprietary servers. If in doubt, say "N". + These firmware drivers are used by Google servers, + Chromebooks and other devices using coreboot firmware. + If in doubt, say "N". if GOOGLE_FIRMWARE diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 24945e2da77b..8e59be3782cb 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c @@ -69,6 +69,7 @@ static struct attribute *def_attrs[] = { &memmap_type_attr.attr, NULL }; +ATTRIBUTE_GROUPS(def); static const struct sysfs_ops memmap_attr_ops = { .show = memmap_attr_show, @@ -118,7 +119,7 @@ static void __meminit release_firmware_map_entry(struct kobject *kobj) static struct kobj_type __refdata memmap_ktype = { .release = release_firmware_map_entry, .sysfs_ops = &memmap_attr_ops, - .default_attrs = def_attrs, + .default_groups = def_groups, }; /* diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 172c751a4f6c..a69399a6b7c0 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -388,14 +388,13 @@ static void fw_cfg_sysfs_cache_cleanup(void) struct fw_cfg_sysfs_entry *entry, *next; list_for_each_entry_safe(entry, next, &fw_cfg_entry_cache, list) { - /* will end up invoking fw_cfg_sysfs_cache_delist() - * via each object's release() method (i.e. destructor) - */ + fw_cfg_sysfs_cache_delist(entry); + kobject_del(&entry->kobj); kobject_put(&entry->kobj); } } -/* default_attrs: per-entry attributes and show methods */ +/* per-entry attributes and show methods */ #define FW_CFG_SYSFS_ATTR(_attr) \ struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = { \ @@ -428,6 +427,7 @@ static struct attribute *fw_cfg_sysfs_entry_attrs[] = { &fw_cfg_sysfs_attr_name.attr, NULL, }; +ATTRIBUTE_GROUPS(fw_cfg_sysfs_entry); /* sysfs_ops: find fw_cfg_[entry, attribute] and call appropriate show method */ static ssize_t fw_cfg_sysfs_attr_show(struct kobject *kobj, struct attribute *a, @@ -448,13 +448,12 @@ static void fw_cfg_sysfs_release_entry(struct kobject *kobj) { struct fw_cfg_sysfs_entry *entry = to_entry(kobj); - fw_cfg_sysfs_cache_delist(entry); kfree(entry); } /* kobj_type: ties together all properties required to register an entry */ static struct kobj_type fw_cfg_sysfs_entry_ktype = { - .default_attrs = fw_cfg_sysfs_entry_attrs, + .default_groups = fw_cfg_sysfs_entry_groups, .sysfs_ops = &fw_cfg_sysfs_attr_ops, .release = fw_cfg_sysfs_release_entry, }; @@ -601,20 +600,18 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f) /* set file entry information */ entry->size = be32_to_cpu(f->size); entry->select = be16_to_cpu(f->select); - memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH); + strscpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH); /* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */ err = kobject_init_and_add(&entry->kobj, &fw_cfg_sysfs_entry_ktype, fw_cfg_sel_ko, "%d", entry->select); - if (err) { - kobject_put(&entry->kobj); - return err; - } + if (err) + goto err_put_entry; /* add raw binary content access */ err = sysfs_create_bin_file(&entry->kobj, &fw_cfg_sysfs_attr_raw); if (err) - goto err_add_raw; + goto err_del_entry; /* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */ fw_cfg_build_symlink(fw_cfg_fname_kset, &entry->kobj, entry->name); @@ -623,9 +620,10 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f) fw_cfg_sysfs_cache_enlist(entry); return 0; -err_add_raw: +err_del_entry: kobject_del(&entry->kobj); - kfree(entry); +err_put_entry: + kobject_put(&entry->kobj); return err; } diff --git a/drivers/firmware/scpi_pm_domain.c b/drivers/firmware/scpi_pm_domain.c index 51201600d789..800673910b51 100644 --- a/drivers/firmware/scpi_pm_domain.c +++ b/drivers/firmware/scpi_pm_domain.c @@ -16,7 +16,6 @@ struct scpi_pm_domain { struct generic_pm_domain genpd; struct scpi_ops *ops; u32 domain; - char name[30]; }; /* @@ -110,8 +109,13 @@ static int scpi_pm_domain_probe(struct platform_device *pdev) scpi_pd->domain = i; scpi_pd->ops = scpi_ops; - sprintf(scpi_pd->name, "%pOFn.%d", np, i); - scpi_pd->genpd.name = scpi_pd->name; + scpi_pd->genpd.name = devm_kasprintf(dev, GFP_KERNEL, + "%pOFn.%d", np, i); + if (!scpi_pd->genpd.name) { + dev_err(dev, "Failed to allocate genpd name:%pOFn.%d\n", + np, i); + continue; + } scpi_pd->genpd.power_off = scpi_pd_power_off; scpi_pd->genpd.power_on = scpi_pd_power_on; diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c index b86761904949..76c4abc42a30 100644 --- a/drivers/firmware/sysfb_simplefb.c +++ b/drivers/firmware/sysfb_simplefb.c @@ -99,7 +99,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, /* setup IORESOURCE_MEM as framebuffer memory */ memset(&res, 0, sizeof(res)); - res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + res.flags = IORESOURCE_MEM; res.name = simplefb_resname; res.start = base; res.end = res.start + length - 1; @@ -113,12 +113,16 @@ __init int sysfb_create_simplefb(const struct screen_info *si, sysfb_apply_efi_quirks(pd); ret = platform_device_add_resources(pd, &res, 1); - if (ret) + if (ret) { + platform_device_put(pd); return ret; + } ret = platform_device_add_data(pd, mode, sizeof(*mode)); - if (ret) + if (ret) { + platform_device_put(pd); return ret; + } return platform_device_add(pd); } diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c index 6d66fe03fb6a..fd89899aeeed 100644 --- a/drivers/firmware/tegra/bpmp-debugfs.c +++ b/drivers/firmware/tegra/bpmp-debugfs.c @@ -77,13 +77,14 @@ static const char *get_filename(struct tegra_bpmp *bpmp, const char *root_path, *filename = NULL; char *root_path_buf; size_t root_len; + size_t root_path_buf_len = 512; - root_path_buf = kzalloc(512, GFP_KERNEL); + root_path_buf = kzalloc(root_path_buf_len, GFP_KERNEL); if (!root_path_buf) goto out; root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf, - sizeof(root_path_buf)); + root_path_buf_len); if (IS_ERR(root_path)) goto out; diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 235c7e7869aa..5ae2040b8b02 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -1759,7 +1759,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle, desc->num = resp->range_num; desc->start_sec = resp->range_start_sec; desc->num_sec = resp->range_num_sec; - }; + } fail: ti_sci_put_one_xfer(&info->minfo, xfer); diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 3dd45a7420dc..450c5f6a1cbf 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -23,6 +23,7 @@ #include <linux/hashtable.h> #include <linux/firmware/xlnx-zynqmp.h> +#include <linux/firmware/xlnx-event-manager.h> #include "zynqmp-debug.h" /* Max HashMap Order for PM API feature check (1<<7 = 128) */ @@ -38,6 +39,8 @@ static bool feature_check_enabled; static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER); +static struct platform_device *em_dev; + /** * struct pm_api_feature_data - PM API Feature data * @pm_api_id: PM API Id, used as key to index into hashmap @@ -160,7 +163,7 @@ static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2, * * Return: Returns status, either success or error+reason */ -static int zynqmp_pm_feature(u32 api_id) +int zynqmp_pm_feature(const u32 api_id) { int ret; u32 ret_payload[PAYLOAD_ARG_CNT]; @@ -197,6 +200,7 @@ static int zynqmp_pm_feature(u32 api_id) return ret; } +EXPORT_SYMBOL_GPL(zynqmp_pm_feature); /** * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer @@ -1117,6 +1121,29 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out) EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine); /** + * zynqmp_pm_register_notifier() - PM API for register a subsystem + * to be notified about specific + * event/error. + * @node: Node ID to which the event is related. + * @event: Event Mask of Error events for which wants to get notified. + * @wake: Wake subsystem upon capturing the event if value 1 + * @enable: Enable the registration for value 1, disable for value 0 + * + * This function is used to register/un-register for particular node-event + * combination in firmware. + * + * Return: Returns status, either success or error+reason + */ + +int zynqmp_pm_register_notifier(const u32 node, const u32 event, + const u32 wake, const u32 enable) +{ + return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, node, event, + wake, enable, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier); + +/** * zynqmp_pm_system_shutdown - PM call to request a system shutdown or restart * @type: Shutdown or restart? 0 for shutdown, 1 for restart * @subtype: Specifies which system should be restarted or shut down @@ -1434,7 +1461,10 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) return ret; /* Check PM API version number */ - zynqmp_pm_get_api_version(&pm_api_version); + ret = zynqmp_pm_get_api_version(&pm_api_version); + if (ret) + return ret; + if (pm_api_version < ZYNQMP_PM_VERSION) { panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n", __func__, @@ -1468,6 +1498,15 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) zynqmp_pm_api_debugfs_init(); + np = of_find_compatible_node(NULL, NULL, "xlnx,versal"); + if (np) { + em_dev = platform_device_register_data(&pdev->dev, "xlnx_event_manager", + -1, NULL, 0); + if (IS_ERR(em_dev)) + dev_err_probe(&pdev->dev, PTR_ERR(em_dev), "EM register fail with error\n"); + } + of_node_put(np); + return of_platform_populate(dev->of_node, NULL, NULL, dev); } @@ -1485,6 +1524,8 @@ static int zynqmp_firmware_remove(struct platform_device *pdev) kfree(feature_data); } + platform_device_unregister(em_dev); + return 0; } |