Skip to content

Commit 7a39124

Browse files
committed
Merge tag 'ffa-updates-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers
Arm FF-A updates for v7.0 A small set of updates to the Arm FF-A driver: 1. Fix a correctness issue in NOTIFICATION_INFO_GET handling of 32-bit firmware responses, avoiding reads from undefined register bits. 2. Improve clarity and robustness of FF-A feature checks by tying them to explicit version requirements. 3. Ensure Rx/Tx buffers are unmapped on FF-A initialization failure to prevent resource leaks. * tag 'ffa-updates-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_ffa: Correct 32-bit response handling in NOTIFICATION_INFO_GET firmware: arm_ffa: Tie FF-A version checks to specific features firmware: arm_ffa: Unmap Rx/Tx buffers on init failure Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2 parents 4e2c045 + be4d454 commit 7a39124

1 file changed

Lines changed: 39 additions & 9 deletions

File tree

drivers/firmware/arm_ffa/driver.c

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@ static int ffa_features(u32 func_feat_id, u32 input_props,
246246
}
247247

248248
#define PARTITION_INFO_GET_RETURN_COUNT_ONLY BIT(0)
249+
#define FFA_SUPPORTS_GET_COUNT_ONLY(version) ((version) > FFA_VERSION_1_0)
250+
#define FFA_PART_INFO_HAS_SIZE_IN_RESP(version) ((version) > FFA_VERSION_1_0)
251+
#define FFA_PART_INFO_HAS_UUID_IN_RESP(version) ((version) > FFA_VERSION_1_0)
252+
#define FFA_PART_INFO_HAS_EXEC_STATE_IN_RESP(version) \
253+
((version) > FFA_VERSION_1_0)
249254

250255
/* buffer must be sizeof(struct ffa_partition_info) * num_partitions */
251256
static int
@@ -255,7 +260,7 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
255260
int idx, count, flags = 0, sz, buf_sz;
256261
ffa_value_t partition_info;
257262

258-
if (drv_info->version > FFA_VERSION_1_0 &&
263+
if (FFA_SUPPORTS_GET_COUNT_ONLY(drv_info->version) &&
259264
(!buffer || !num_partitions)) /* Just get the count for now */
260265
flags = PARTITION_INFO_GET_RETURN_COUNT_ONLY;
261266

@@ -273,12 +278,11 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
273278

274279
count = partition_info.a2;
275280

276-
if (drv_info->version > FFA_VERSION_1_0) {
281+
if (FFA_PART_INFO_HAS_SIZE_IN_RESP(drv_info->version)) {
277282
buf_sz = sz = partition_info.a3;
278283
if (sz > sizeof(*buffer))
279284
buf_sz = sizeof(*buffer);
280285
} else {
281-
/* FFA_VERSION_1_0 lacks size in the response */
282286
buf_sz = sz = 8;
283287
}
284288

@@ -981,10 +985,27 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu)
981985
}
982986
}
983987

988+
/*
989+
* Map logical ID index to the u16 index within the packed ID list.
990+
*
991+
* For native responses (FF-A width == kernel word size), IDs are
992+
* tightly packed: idx -> idx.
993+
*
994+
* For 32-bit responses on a 64-bit kernel, each 64-bit register
995+
* contributes 4 x u16 values but only the lower 2 are defined; the
996+
* upper 2 are garbage. This mapping skips those upper halves:
997+
* 0,1,2,3,4,5,... -> 0,1,4,5,8,9,...
998+
*/
999+
static int list_idx_to_u16_idx(int idx, bool is_native_resp)
1000+
{
1001+
return is_native_resp ? idx : idx + 2 * (idx >> 1);
1002+
}
1003+
9841004
static void ffa_notification_info_get(void)
9851005
{
986-
int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64];
987-
bool is_64b_resp;
1006+
int ids_processed, ids_count[MAX_IDS_64];
1007+
int idx, list, max_ids, lists_cnt;
1008+
bool is_64b_resp, is_native_resp;
9881009
ffa_value_t ret;
9891010
u64 id_list;
9901011

@@ -1001,6 +1022,7 @@ static void ffa_notification_info_get(void)
10011022
}
10021023

10031024
is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS);
1025+
is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS));
10041026

10051027
ids_processed = 0;
10061028
lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2);
@@ -1017,12 +1039,16 @@ static void ffa_notification_info_get(void)
10171039

10181040
/* Process IDs */
10191041
for (list = 0; list < lists_cnt; list++) {
1042+
int u16_idx;
10201043
u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3;
10211044

10221045
if (ids_processed >= max_ids - 1)
10231046
break;
10241047

1025-
part_id = packed_id_list[ids_processed++];
1048+
u16_idx = list_idx_to_u16_idx(ids_processed,
1049+
is_native_resp);
1050+
part_id = packed_id_list[u16_idx];
1051+
ids_processed++;
10261052

10271053
if (ids_count[list] == 1) { /* Global Notification */
10281054
__do_sched_recv_cb(part_id, 0, false);
@@ -1034,7 +1060,10 @@ static void ffa_notification_info_get(void)
10341060
if (ids_processed >= max_ids - 1)
10351061
break;
10361062

1037-
vcpu_id = packed_id_list[ids_processed++];
1063+
u16_idx = list_idx_to_u16_idx(ids_processed,
1064+
is_native_resp);
1065+
vcpu_id = packed_id_list[u16_idx];
1066+
ids_processed++;
10381067

10391068
__do_sched_recv_cb(part_id, vcpu_id, true);
10401069
}
@@ -1706,7 +1735,7 @@ static int ffa_setup_partitions(void)
17061735
struct ffa_device *ffa_dev;
17071736
struct ffa_partition_info *pbuf, *tpbuf;
17081737

1709-
if (drv_info->version == FFA_VERSION_1_0) {
1738+
if (!FFA_PART_INFO_HAS_UUID_IN_RESP(drv_info->version)) {
17101739
ret = bus_register_notifier(&ffa_bus_type, &ffa_bus_nb);
17111740
if (ret)
17121741
pr_err("Failed to register FF-A bus notifiers\n");
@@ -1733,7 +1762,7 @@ static int ffa_setup_partitions(void)
17331762
continue;
17341763
}
17351764

1736-
if (drv_info->version > FFA_VERSION_1_0 &&
1765+
if (FFA_PART_INFO_HAS_EXEC_STATE_IN_RESP(drv_info->version) &&
17371766
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
17381767
ffa_mode_32bit_set(ffa_dev);
17391768

@@ -2068,6 +2097,7 @@ static int __init ffa_init(void)
20682097

20692098
pr_err("failed to setup partitions\n");
20702099
ffa_notifications_cleanup();
2100+
ffa_rxtx_unmap(drv_info->vm_id);
20712101
free_pages:
20722102
if (drv_info->tx_buffer)
20732103
free_pages_exact(drv_info->tx_buffer, rxtx_bufsz);

0 commit comments

Comments
 (0)