Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+39 -9
+39 -9
drivers/firmware/arm_ffa/driver.c
··· 246 246 } 247 247 248 248 #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) 249 254 250 255 /* buffer must be sizeof(struct ffa_partition_info) * num_partitions */ 251 256 static int ··· 260 255 int idx, count, flags = 0, sz, buf_sz; 261 256 ffa_value_t partition_info; 262 257 263 - if (drv_info->version > FFA_VERSION_1_0 && 258 + if (FFA_SUPPORTS_GET_COUNT_ONLY(drv_info->version) && 264 259 (!buffer || !num_partitions)) /* Just get the count for now */ 265 260 flags = PARTITION_INFO_GET_RETURN_COUNT_ONLY; 266 261 ··· 278 273 279 274 count = partition_info.a2; 280 275 281 - if (drv_info->version > FFA_VERSION_1_0) { 276 + if (FFA_PART_INFO_HAS_SIZE_IN_RESP(drv_info->version)) { 282 277 buf_sz = sz = partition_info.a3; 283 278 if (sz > sizeof(*buffer)) 284 279 buf_sz = sizeof(*buffer); 285 280 } else { 286 - /* FFA_VERSION_1_0 lacks size in the response */ 287 281 buf_sz = sz = 8; 288 282 } 289 283 ··· 985 981 } 986 982 } 987 983 984 + /* 985 + * Map logical ID index to the u16 index within the packed ID list. 986 + * 987 + * For native responses (FF-A width == kernel word size), IDs are 988 + * tightly packed: idx -> idx. 989 + * 990 + * For 32-bit responses on a 64-bit kernel, each 64-bit register 991 + * contributes 4 x u16 values but only the lower 2 are defined; the 992 + * upper 2 are garbage. This mapping skips those upper halves: 993 + * 0,1,2,3,4,5,... -> 0,1,4,5,8,9,... 994 + */ 995 + static int list_idx_to_u16_idx(int idx, bool is_native_resp) 996 + { 997 + return is_native_resp ? idx : idx + 2 * (idx >> 1); 998 + } 999 + 988 1000 static void ffa_notification_info_get(void) 989 1001 { 990 - int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64]; 991 - bool is_64b_resp; 1002 + int ids_processed, ids_count[MAX_IDS_64]; 1003 + int idx, list, max_ids, lists_cnt; 1004 + bool is_64b_resp, is_native_resp; 992 1005 ffa_value_t ret; 993 1006 u64 id_list; 994 1007 ··· 1022 1001 } 1023 1002 1024 1003 is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS); 1004 + is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS)); 1025 1005 1026 1006 ids_processed = 0; 1027 1007 lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2); ··· 1039 1017 1040 1018 /* Process IDs */ 1041 1019 for (list = 0; list < lists_cnt; list++) { 1020 + int u16_idx; 1042 1021 u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3; 1043 1022 1044 1023 if (ids_processed >= max_ids - 1) 1045 1024 break; 1046 1025 1047 - part_id = packed_id_list[ids_processed++]; 1026 + u16_idx = list_idx_to_u16_idx(ids_processed, 1027 + is_native_resp); 1028 + part_id = packed_id_list[u16_idx]; 1029 + ids_processed++; 1048 1030 1049 1031 if (ids_count[list] == 1) { /* Global Notification */ 1050 1032 __do_sched_recv_cb(part_id, 0, false); ··· 1060 1034 if (ids_processed >= max_ids - 1) 1061 1035 break; 1062 1036 1063 - vcpu_id = packed_id_list[ids_processed++]; 1037 + u16_idx = list_idx_to_u16_idx(ids_processed, 1038 + is_native_resp); 1039 + vcpu_id = packed_id_list[u16_idx]; 1040 + ids_processed++; 1064 1041 1065 1042 __do_sched_recv_cb(part_id, vcpu_id, true); 1066 1043 } ··· 1735 1706 struct ffa_device *ffa_dev; 1736 1707 struct ffa_partition_info *pbuf, *tpbuf; 1737 1708 1738 - if (drv_info->version == FFA_VERSION_1_0) { 1709 + if (!FFA_PART_INFO_HAS_UUID_IN_RESP(drv_info->version)) { 1739 1710 ret = bus_register_notifier(&ffa_bus_type, &ffa_bus_nb); 1740 1711 if (ret) 1741 1712 pr_err("Failed to register FF-A bus notifiers\n"); ··· 1762 1733 continue; 1763 1734 } 1764 1735 1765 - if (drv_info->version > FFA_VERSION_1_0 && 1736 + if (FFA_PART_INFO_HAS_EXEC_STATE_IN_RESP(drv_info->version) && 1766 1737 !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) 1767 1738 ffa_mode_32bit_set(ffa_dev); 1768 1739 ··· 2097 2068 2098 2069 pr_err("failed to setup partitions\n"); 2099 2070 ffa_notifications_cleanup(); 2071 + ffa_rxtx_unmap(drv_info->vm_id); 2100 2072 free_pages: 2101 2073 if (drv_info->tx_buffer) 2102 2074 free_pages_exact(drv_info->tx_buffer, rxtx_bufsz);