From 9fda364cb78c8b9e1abe4029f877300c94655742 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Wed, 10 Dec 2025 11:16:56 +0800 Subject: firmware: arm_ffa: Unmap Rx/Tx buffers on init failure ffa_init() maps the Rx/Tx buffers via ffa_rxtx_map() but on the partition setup failure path it never unmaps them. Add the missing ffa_rxtx_unmap() call in the error path so that the Rx/Tx buffers are properly released before freeing the backing pages. Signed-off-by: Haoxiang Li Message-Id: <20251210031656.56194-1-lihaoxiang@isrc.iscas.ac.cn> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index c72ee4756585..7209a630f6d1 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -2068,6 +2068,7 @@ static int __init ffa_init(void) pr_err("failed to setup partitions\n"); ffa_notifications_cleanup(); + ffa_rxtx_unmap(drv_info->vm_id); free_pages: if (drv_info->tx_buffer) free_pages_exact(drv_info->tx_buffer, rxtx_bufsz); -- cgit v1.2.3 From f183b1dda4fc0348c4016f6289588d5853ab7936 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 16 Oct 2025 10:41:11 +0100 Subject: firmware: arm_ffa: Tie FF-A version checks to specific features The FF-A driver currently performs loose comparisons when checking the supported FF-A feature, which can inadvertently treat future or intermediate revisions as compatible. Replace generic `version {>,<} FFA_VERSION_1_*` pattern checks with feature-specific macros that clearly express which functionality depends on FF-A versioning. This improves readability and future maintainability by tying each feature (e.g. GET_COUNT_ONLY, size/UUID/exec state in responses) to explicit version requirements instead of relying on generic version comparisons. This improves robustness and clarity as the FF-A specification evolves. No functional change, only improves code readability. Message-Id: <20251016094111.946236-1-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 7209a630f6d1..351780ac8d72 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -246,6 +246,11 @@ static int ffa_features(u32 func_feat_id, u32 input_props, } #define PARTITION_INFO_GET_RETURN_COUNT_ONLY BIT(0) +#define FFA_SUPPORTS_GET_COUNT_ONLY(version) ((version) > FFA_VERSION_1_0) +#define FFA_PART_INFO_HAS_SIZE_IN_RESP(version) ((version) > FFA_VERSION_1_0) +#define FFA_PART_INFO_HAS_UUID_IN_RESP(version) ((version) > FFA_VERSION_1_0) +#define FFA_PART_INFO_HAS_EXEC_STATE_IN_RESP(version) \ + ((version) > FFA_VERSION_1_0) /* buffer must be sizeof(struct ffa_partition_info) * num_partitions */ static int @@ -255,7 +260,7 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, int idx, count, flags = 0, sz, buf_sz; ffa_value_t partition_info; - if (drv_info->version > FFA_VERSION_1_0 && + if (FFA_SUPPORTS_GET_COUNT_ONLY(drv_info->version) && (!buffer || !num_partitions)) /* Just get the count for now */ flags = PARTITION_INFO_GET_RETURN_COUNT_ONLY; @@ -273,12 +278,11 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, count = partition_info.a2; - if (drv_info->version > FFA_VERSION_1_0) { + if (FFA_PART_INFO_HAS_SIZE_IN_RESP(drv_info->version)) { buf_sz = sz = partition_info.a3; if (sz > sizeof(*buffer)) buf_sz = sizeof(*buffer); } else { - /* FFA_VERSION_1_0 lacks size in the response */ buf_sz = sz = 8; } @@ -1706,7 +1710,7 @@ static int ffa_setup_partitions(void) struct ffa_device *ffa_dev; struct ffa_partition_info *pbuf, *tpbuf; - if (drv_info->version == FFA_VERSION_1_0) { + if (!FFA_PART_INFO_HAS_UUID_IN_RESP(drv_info->version)) { ret = bus_register_notifier(&ffa_bus_type, &ffa_bus_nb); if (ret) pr_err("Failed to register FF-A bus notifiers\n"); @@ -1733,7 +1737,7 @@ static int ffa_setup_partitions(void) continue; } - if (drv_info->version > FFA_VERSION_1_0 && + if (FFA_PART_INFO_HAS_EXEC_STATE_IN_RESP(drv_info->version) && !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) ffa_mode_32bit_set(ffa_dev); -- cgit v1.2.3 From be4d4543f78074fbebd530ba5109d39a2a34e668 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 18 Dec 2025 14:20:01 +0000 Subject: firmware: arm_ffa: Correct 32-bit response handling in NOTIFICATION_INFO_GET The FF-A specification allows NOTIFICATION_INFO_GET to return either a 64-bit (FFA_FN64_SUCCESS) or a 32-bit (FFA_SUCCESS) response, depending on whether the firmware chooses the SMC64 or SMC32 calling convention. The driver previously detected the response format by checking ret.a0, but still interpreted the returned ID lists (x3..x17 or w3..w7) as if they always followed the 64-bit SMC64 layout. In the SMC32 case, the upper 32 bits of each argument register are undefined by the calling convention, meaning the driver could read stale or garbage values when parsing notification IDs. This resulted in incorrectly decoded partition/VCPU IDs whenever the FF-A firmware used an SMC32 return path. Fix the issue by: - Introducing logic to map list indices to the correct u16 offsets, depending on whether the response width matches the kernel word size or is a 32-bit response on a 64-bit kernel. - Ensuring that the packed ID list is parsed using the proper layout, avoiding reads from undefined upper halves in the SMC32 case. With this change, NOTIFICATION_INFO_GET now correctly interprets ID list entries regardless of the response width, aligning the driver with the FF-A specification. Fixes: 3522be48d82b ("firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface") Reported-by: Sourav Mohapatra Message-Id: <20251218142001.2457111-1-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 351780ac8d72..8144f6a9f0e9 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -985,10 +985,27 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) } } +/* + * Map logical ID index to the u16 index within the packed ID list. + * + * For native responses (FF-A width == kernel word size), IDs are + * tightly packed: idx -> idx. + * + * For 32-bit responses on a 64-bit kernel, each 64-bit register + * contributes 4 x u16 values but only the lower 2 are defined; the + * upper 2 are garbage. This mapping skips those upper halves: + * 0,1,2,3,4,5,... -> 0,1,4,5,8,9,... + */ +static int list_idx_to_u16_idx(int idx, bool is_native_resp) +{ + return is_native_resp ? idx : idx + 2 * (idx >> 1); +} + static void ffa_notification_info_get(void) { - int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64]; - bool is_64b_resp; + int ids_processed, ids_count[MAX_IDS_64]; + int idx, list, max_ids, lists_cnt; + bool is_64b_resp, is_native_resp; ffa_value_t ret; u64 id_list; @@ -1005,6 +1022,7 @@ static void ffa_notification_info_get(void) } is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS); + is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS)); ids_processed = 0; lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2); @@ -1021,12 +1039,16 @@ static void ffa_notification_info_get(void) /* Process IDs */ for (list = 0; list < lists_cnt; list++) { + int u16_idx; u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3; if (ids_processed >= max_ids - 1) break; - part_id = packed_id_list[ids_processed++]; + u16_idx = list_idx_to_u16_idx(ids_processed, + is_native_resp); + part_id = packed_id_list[u16_idx]; + ids_processed++; if (ids_count[list] == 1) { /* Global Notification */ __do_sched_recv_cb(part_id, 0, false); @@ -1038,7 +1060,10 @@ static void ffa_notification_info_get(void) if (ids_processed >= max_ids - 1) break; - vcpu_id = packed_id_list[ids_processed++]; + u16_idx = list_idx_to_u16_idx(ids_processed, + is_native_resp); + vcpu_id = packed_id_list[u16_idx]; + ids_processed++; __do_sched_recv_cb(part_id, vcpu_id, true); } -- cgit v1.2.3