Hi,

On 24. 11. 20 6:52, Rajan Vaja wrote:
> From: Amit Sunil Dhamne <amit.sunil.dha...@xilinx.com>
> 
> Currently array of fix length PM_API_MAX is used to cache
> the pm_api version (valid or invalid). However ATF based
> PM APIs values are much higher then PM_API_MAX.
> So to include ATF based PM APIs also, use hash-table to
> store the pm_api version status.
> 
> Signed-off-by: Amit Sunil Dhamne <amit.sunil.dha...@xilinx.com>
> Reported-by: Arnd Bergmann <a...@arndb.de>
> Signed-off-by: Ravi Patel <ravi.pa...@xilinx.com>
> Signed-off-by: Rajan Vaja <rajan.v...@xilinx.com>
> ---
>  drivers/firmware/xilinx/zynqmp.c     | 63 
> ++++++++++++++++++++++++++++--------
>  include/linux/firmware/xlnx-zynqmp.h |  4 ---
>  2 files changed, 49 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/firmware/xilinx/zynqmp.c 
> b/drivers/firmware/xilinx/zynqmp.c
> index efb8a66..349ab39 100644
> --- a/drivers/firmware/xilinx/zynqmp.c
> +++ b/drivers/firmware/xilinx/zynqmp.c
> @@ -20,12 +20,28 @@
>  #include <linux/of_platform.h>
>  #include <linux/slab.h>
>  #include <linux/uaccess.h>
> +#include <linux/hashtable.h>
>  
>  #include <linux/firmware/xlnx-zynqmp.h>
>  #include "zynqmp-debug.h"
>  
> +/* Max HashMap Order for PM API feature check (1<<7 = 128) */
> +#define PM_API_FEATURE_CHECK_MAX_ORDER  7
> +
>  static bool feature_check_enabled;
> -static u32 zynqmp_pm_features[PM_API_MAX];
> +DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
> +
> +/**
> + * struct pm_api_feature_data - PM API Feature data
> + * @pm_api_id:               PM API Id, used as key to index into hashmap
> + * @feature_status:  status of PM API feature: valid, invalid
> + * @hentry:          hlist_node that hooks this entry into hashtable
> + */
> +struct pm_api_feature_data {
> +     u32 pm_api_id;
> +     int feature_status;
> +     struct hlist_node hentry;
> +};
>  
>  static const struct mfd_cell firmware_devs[] = {
>       {
> @@ -142,29 +158,37 @@ static int zynqmp_pm_feature(u32 api_id)
>       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;
>  
> -     /* Return value if feature is already checked */
> -     if (api_id > ARRAY_SIZE(zynqmp_pm_features))
> -             return PM_FEATURE_INVALID;
> +     /* Check for existing entry in hash table for given api */
> +     hash_for_each_possible(pm_api_features_map, feature_data, hentry,
> +                            api_id) {
> +             if (feature_data->pm_api_id == api_id)
> +                     return feature_data->feature_status;
> +     }
>  
> -     if (zynqmp_pm_features[api_id] != PM_FEATURE_UNCHECKED)
> -             return zynqmp_pm_features[api_id];
> +     /* Add new entry if not present */
> +     feature_data = kmalloc(sizeof(*feature_data), GFP_KERNEL);
> +     if (!feature_data)
> +             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) {
> -             zynqmp_pm_features[api_id] = PM_FEATURE_INVALID;
> -             return PM_FEATURE_INVALID;
> -     }
> +     if (ret)
> +             ret = -EOPNOTSUPP;
> +     else
> +             ret = ret_payload[1];
>  
> -     zynqmp_pm_features[api_id] = ret_payload[1];
> +     feature_data->feature_status = ret;
> +     hash_add(pm_api_features_map, &feature_data->hentry, api_id);
>  
> -     return zynqmp_pm_features[api_id];
> +     return ret;
>  }
>  
>  /**
> @@ -200,9 +224,12 @@ int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 
> arg1,
>        * Make sure to stay in x0 register
>        */
>       u64 smc_arg[4];
> +     int ret;
>  
> -     if (zynqmp_pm_feature(pm_api_id) == PM_FEATURE_INVALID)
> -             return -ENOTSUPP;
> +     /* Check if feature is supported or not */
> +     ret = zynqmp_pm_feature(pm_api_id);
> +     if (ret < 0)
> +             return ret;
>  
>       smc_arg[0] = PM_SIP_SVC | pm_api_id;
>       smc_arg[1] = ((u64)arg1 << 32) | arg0;
> @@ -1252,9 +1279,17 @@ static int zynqmp_firmware_probe(struct 
> platform_device *pdev)
>  
>  static int zynqmp_firmware_remove(struct platform_device *pdev)
>  {
> +     struct pm_api_feature_data *feature_data;
> +     int i;
> +
>       mfd_remove_devices(&pdev->dev);
>       zynqmp_pm_api_debugfs_exit();
>  
> +     hash_for_each(pm_api_features_map, i, feature_data, hentry) {
> +             hash_del(&feature_data->hentry);
> +             kfree(feature_data);
> +     }
> +
>       return 0;
>  }
>  
> diff --git a/include/linux/firmware/xlnx-zynqmp.h 
> b/include/linux/firmware/xlnx-zynqmp.h
> index 5968df8..41a1bab 100644
> --- a/include/linux/firmware/xlnx-zynqmp.h
> +++ b/include/linux/firmware/xlnx-zynqmp.h
> @@ -50,10 +50,6 @@
>  #define      ZYNQMP_PM_CAPABILITY_WAKEUP     0x4U
>  #define      ZYNQMP_PM_CAPABILITY_UNUSABLE   0x8U
>  
> -/* Feature check status */
> -#define PM_FEATURE_INVALID           -1
> -#define PM_FEATURE_UNCHECKED         0
> -
>  /*
>   * Firmware FPGA Manager flags
>   * XILINX_ZYNQMP_PM_FPGA_FULL:       FPGA full reconfiguration
> 

Some lines should be added.

Cc: stable <sta...@vger.kernel.org>
Fixes: f3217d6f2f7a ("firmware: xilinx: fix out-of-bounds access")

Tested-by: Michal Simek <michal.si...@xilinx.com>

Arnd: do you see any issue with this?
I found that your origin patch was taken by Greg and pushed to any
5.10-rc version which caused panic on Xilinx Versal. That's why I would
like to get this patch to v5.10 if possible.

Thanks,
Michal



Reply via email to