diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/dmi-sysfs.c | 2 | ||||
-rw-r--r-- | drivers/firmware/edd.c | 3 | ||||
-rw-r--r-- | drivers/firmware/stratix10-svc.c | 12 | ||||
-rw-r--r-- | drivers/firmware/xilinx/zynqmp.c | 131 |
4 files changed, 116 insertions, 32 deletions
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c index 3a353776bd34..66727ad3361b 100644 --- a/drivers/firmware/dmi-sysfs.c +++ b/drivers/firmware/dmi-sysfs.c @@ -604,7 +604,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/edd.c b/drivers/firmware/edd.c index 69353dd0ea22..5cc238916551 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -685,8 +685,7 @@ static void edd_populate_dir(struct edd_device * edev) int i; for (i = 0; (attr = edd_attrs[i]) && !error; i++) { - if (!attr->test || - (attr->test && attr->test(edev))) + if (!attr->test || attr->test(edev)) error = sysfs_create_file(&edev->kobj,&attr->attr); } diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index 8177a0fae11d..14663f671323 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -948,17 +948,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); diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index f21ece56695e..7977a494a651 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -36,8 +36,16 @@ /* BOOT_PIN_CTRL_MASK- out_val[11:8], out_en[3:0] */ #define CRL_APB_BOOTPIN_CTRL_MASK 0xF0FU +/* IOCTL/QUERY feature payload size */ +#define FEATURE_PAYLOAD_SIZE 2 + +/* Firmware feature check version mask */ +#define FIRMWARE_VERSION_MASK GENMASK(15, 0) + static bool feature_check_enabled; static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER); +static u32 ioctl_features[FEATURE_PAYLOAD_SIZE]; +static u32 query_features[FEATURE_PAYLOAD_SIZE]; static struct platform_device *em_dev; @@ -167,21 +175,28 @@ static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2, return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); } -/** - * zynqmp_pm_feature() - Check weather given feature is supported or not - * @api_id: API ID to check - * - * Return: Returns status, either success or error+reason - */ -int zynqmp_pm_feature(const u32 api_id) +static int __do_feature_check_call(const u32 api_id, u32 *ret_payload) { int ret; - u32 ret_payload[PAYLOAD_ARG_CNT]; u64 smc_arg[2]; - struct pm_api_feature_data *feature_data; - if (!feature_check_enabled) - return 0; + smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK; + smc_arg[1] = api_id; + + ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload); + if (ret) + ret = -EOPNOTSUPP; + else + ret = ret_payload[1]; + + return ret; +} + +static int do_feature_check_call(const u32 api_id) +{ + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + struct pm_api_feature_data *feature_data; /* Check for existing entry in hash table for given api */ hash_for_each_possible(pm_api_features_map, feature_data, hentry, @@ -196,23 +211,86 @@ int zynqmp_pm_feature(const u32 api_id) return -ENOMEM; feature_data->pm_api_id = api_id; - smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK; - smc_arg[1] = api_id; - - ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload); - if (ret) - ret = -EOPNOTSUPP; - else - ret = ret_payload[1]; + ret = __do_feature_check_call(api_id, ret_payload); feature_data->feature_status = ret; hash_add(pm_api_features_map, &feature_data->hentry, api_id); + if (api_id == PM_IOCTL) + /* Store supported IOCTL IDs mask */ + memcpy(ioctl_features, &ret_payload[2], FEATURE_PAYLOAD_SIZE * 4); + else if (api_id == PM_QUERY_DATA) + /* Store supported QUERY IDs mask */ + memcpy(query_features, &ret_payload[2], FEATURE_PAYLOAD_SIZE * 4); + return ret; } EXPORT_SYMBOL_GPL(zynqmp_pm_feature); /** + * zynqmp_pm_feature() - Check whether given feature is supported or not and + * store supported IOCTL/QUERY ID mask + * @api_id: API ID to check + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_feature(const u32 api_id) +{ + int ret; + + if (!feature_check_enabled) + return 0; + + ret = do_feature_check_call(api_id); + + return ret; +} + +/** + * zynqmp_pm_is_function_supported() - Check whether given IOCTL/QUERY function + * is supported or not + * @api_id: PM_IOCTL or PM_QUERY_DATA + * @id: IOCTL or QUERY function IDs + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) +{ + int ret; + u32 *bit_mask; + + /* Input arguments validation */ + if (id >= 64 || (api_id != PM_IOCTL && api_id != PM_QUERY_DATA)) + return -EINVAL; + + /* Check feature check API version */ + ret = do_feature_check_call(PM_FEATURE_CHECK); + if (ret < 0) + return ret; + + /* Check if feature check version 2 is supported or not */ + if ((ret & FIRMWARE_VERSION_MASK) == PM_API_VERSION_2) { + /* + * Call feature check for IOCTL/QUERY API to get IOCTL ID or + * QUERY ID feature status. + */ + ret = do_feature_check_call(api_id); + if (ret < 0) + return ret; + + bit_mask = (api_id == PM_IOCTL) ? ioctl_features : query_features; + + if ((bit_mask[(id / 32)] & BIT((id % 32))) == 0U) + return -EOPNOTSUPP; + } else { + return -ENODATA; + } + + return 0; +} +EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported); + +/** * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer * caller function depending on the configuration * @pm_api_id: Requested PM-API call @@ -1584,6 +1662,10 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) struct zynqmp_devinfo *devinfo; int ret; + ret = get_set_conduit_method(dev->of_node); + if (ret) + return ret; + np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp"); if (!np) { np = of_find_compatible_node(NULL, NULL, "xlnx,versal"); @@ -1592,11 +1674,14 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) feature_check_enabled = true; } - of_node_put(np); - ret = get_set_conduit_method(dev->of_node); - if (ret) - return ret; + if (!feature_check_enabled) { + ret = do_feature_check_call(PM_FEATURE_CHECK); + if (ret >= 0) + feature_check_enabled = true; + } + + of_node_put(np); devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL); if (!devinfo) |