Skip to content

Commit acfdd18

Browse files
Amit Sunil DhamneMichal Simek
authored andcommitted
firmware: xilinx: Use hash-table for api feature check
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.dhamne@xilinx.com> Reported-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Ravi Patel <ravi.patel@xilinx.com> Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de> Tested-by: Michal Simek <michal.simek@xilinx.com> Fixes: f3217d6 ("firmware: xilinx: fix out-of-bounds access") Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/1606197161-25976-1-git-send-email-rajan.vaja@xilinx.com Signed-off-by: Michal Simek <michal.simek@xilinx.com>
1 parent f442631 commit acfdd18

File tree

2 files changed

+49
-18
lines changed

2 files changed

+49
-18
lines changed

drivers/firmware/xilinx/zynqmp.c

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,28 @@
2020
#include <linux/of_platform.h>
2121
#include <linux/slab.h>
2222
#include <linux/uaccess.h>
23+
#include <linux/hashtable.h>
2324

2425
#include <linux/firmware/xlnx-zynqmp.h>
2526
#include "zynqmp-debug.h"
2627

28+
/* Max HashMap Order for PM API feature check (1<<7 = 128) */
29+
#define PM_API_FEATURE_CHECK_MAX_ORDER 7
30+
2731
static bool feature_check_enabled;
28-
static u32 zynqmp_pm_features[PM_API_MAX];
32+
DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
33+
34+
/**
35+
* struct pm_api_feature_data - PM API Feature data
36+
* @pm_api_id: PM API Id, used as key to index into hashmap
37+
* @feature_status: status of PM API feature: valid, invalid
38+
* @hentry: hlist_node that hooks this entry into hashtable
39+
*/
40+
struct pm_api_feature_data {
41+
u32 pm_api_id;
42+
int feature_status;
43+
struct hlist_node hentry;
44+
};
2945

3046
static const struct mfd_cell firmware_devs[] = {
3147
{
@@ -142,29 +158,37 @@ static int zynqmp_pm_feature(u32 api_id)
142158
int ret;
143159
u32 ret_payload[PAYLOAD_ARG_CNT];
144160
u64 smc_arg[2];
161+
struct pm_api_feature_data *feature_data;
145162

146163
if (!feature_check_enabled)
147164
return 0;
148165

149-
/* Return value if feature is already checked */
150-
if (api_id > ARRAY_SIZE(zynqmp_pm_features))
151-
return PM_FEATURE_INVALID;
166+
/* Check for existing entry in hash table for given api */
167+
hash_for_each_possible(pm_api_features_map, feature_data, hentry,
168+
api_id) {
169+
if (feature_data->pm_api_id == api_id)
170+
return feature_data->feature_status;
171+
}
152172

153-
if (zynqmp_pm_features[api_id] != PM_FEATURE_UNCHECKED)
154-
return zynqmp_pm_features[api_id];
173+
/* Add new entry if not present */
174+
feature_data = kmalloc(sizeof(*feature_data), GFP_KERNEL);
175+
if (!feature_data)
176+
return -ENOMEM;
155177

178+
feature_data->pm_api_id = api_id;
156179
smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK;
157180
smc_arg[1] = api_id;
158181

159182
ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload);
160-
if (ret) {
161-
zynqmp_pm_features[api_id] = PM_FEATURE_INVALID;
162-
return PM_FEATURE_INVALID;
163-
}
183+
if (ret)
184+
ret = -EOPNOTSUPP;
185+
else
186+
ret = ret_payload[1];
164187

165-
zynqmp_pm_features[api_id] = ret_payload[1];
188+
feature_data->feature_status = ret;
189+
hash_add(pm_api_features_map, &feature_data->hentry, api_id);
166190

167-
return zynqmp_pm_features[api_id];
191+
return ret;
168192
}
169193

170194
/**
@@ -200,9 +224,12 @@ int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
200224
* Make sure to stay in x0 register
201225
*/
202226
u64 smc_arg[4];
227+
int ret;
203228

204-
if (zynqmp_pm_feature(pm_api_id) == PM_FEATURE_INVALID)
205-
return -ENOTSUPP;
229+
/* Check if feature is supported or not */
230+
ret = zynqmp_pm_feature(pm_api_id);
231+
if (ret < 0)
232+
return ret;
206233

207234
smc_arg[0] = PM_SIP_SVC | pm_api_id;
208235
smc_arg[1] = ((u64)arg1 << 32) | arg0;
@@ -1252,9 +1279,17 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
12521279

12531280
static int zynqmp_firmware_remove(struct platform_device *pdev)
12541281
{
1282+
struct pm_api_feature_data *feature_data;
1283+
int i;
1284+
12551285
mfd_remove_devices(&pdev->dev);
12561286
zynqmp_pm_api_debugfs_exit();
12571287

1288+
hash_for_each(pm_api_features_map, i, feature_data, hentry) {
1289+
hash_del(&feature_data->hentry);
1290+
kfree(feature_data);
1291+
}
1292+
12581293
return 0;
12591294
}
12601295

include/linux/firmware/xlnx-zynqmp.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
#define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U
5151
#define ZYNQMP_PM_CAPABILITY_UNUSABLE 0x8U
5252

53-
/* Feature check status */
54-
#define PM_FEATURE_INVALID -1
55-
#define PM_FEATURE_UNCHECKED 0
56-
5753
/*
5854
* Firmware FPGA Manager flags
5955
* XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration

0 commit comments

Comments
 (0)