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.

firmware: stratix10-svc: Add support for async communication

Introduce support for asynchronous communication with the Stratix10
service channel. Define new structures to enable asynchronous messaging
with the Secure Device Manager (SDM). Add and remove asynchronous
support for existing channels. Implement initialization and cleanup
routines for the asynchronous framework. Enable sending and polling of
messages to the SDM asynchronously.

The new public functions added are:
- stratix10_svc_add_async_client: Adds a client to the service channel.
- stratix10_svc_remove_async_client: Removes an asynchronous client from
the service channel.
- stratix10_svc_async_send: Sends an asynchronous message to the SDM
mailbox in EL3 secure firmware.
- stratix10_svc_async_poll: Polls the status of an asynchronous service
request in EL3 secure firmware.
- stratix10_svc_async_done: Marks an asynchronous transaction as
complete and frees up the resources.

These changes enhance the functionality of the Stratix10 service channel
by allowing for more efficient and flexible communication with the
firmware.

Signed-off-by: Mahesh Rao <mahesh.rao@altera.com>
Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com>
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>

authored by

Mahesh Rao and committed by
Dinh Nguyen
bcb9f4f0 85f96cbb

+765 -4
+652 -4
drivers/firmware/stratix10-svc.c
··· 4 4 * Copyright (C) 2025, Altera Corporation 5 5 */ 6 6 7 + #include <linux/atomic.h> 7 8 #include <linux/completion.h> 8 9 #include <linux/delay.h> 9 10 #include <linux/genalloc.h> 11 + #include <linux/hashtable.h> 12 + #include <linux/idr.h> 10 13 #include <linux/io.h> 11 14 #include <linux/kfifo.h> 12 15 #include <linux/kthread.h> ··· 47 44 #define STRATIX10_RSU "stratix10-rsu" 48 45 #define INTEL_FCS "intel-fcs" 49 46 47 + /* Maximum number of SDM client IDs. */ 48 + #define MAX_SDM_CLIENT_IDS 16 49 + /* Client ID for SIP Service Version 1. */ 50 + #define SIP_SVC_V1_CLIENT_ID 0x1 51 + /* Maximum number of SDM job IDs. */ 52 + #define MAX_SDM_JOB_IDS 16 53 + /* Number of bits used for asynchronous transaction hashing. */ 54 + #define ASYNC_TRX_HASH_BITS 3 55 + /** 56 + * Total number of transaction IDs, which is a combination of 57 + * client ID and job ID. 58 + */ 59 + #define TOTAL_TRANSACTION_IDS \ 60 + (MAX_SDM_CLIENT_IDS * MAX_SDM_JOB_IDS) 61 + 62 + /* Minimum major version of the ATF for Asynchronous transactions. */ 63 + #define ASYNC_ATF_MINIMUM_MAJOR_VERSION 0x3 64 + /* Minimum minor version of the ATF for Asynchronous transactions.*/ 65 + #define ASYNC_ATF_MINIMUM_MINOR_VERSION 0x0 66 + 67 + /* Job ID field in the transaction ID */ 68 + #define STRATIX10_JOB_FIELD GENMASK(3, 0) 69 + /* Client ID field in the transaction ID */ 70 + #define STRATIX10_CLIENT_FIELD GENMASK(7, 4) 71 + /* Transaction ID mask for Stratix10 service layer */ 72 + #define STRATIX10_TRANS_ID_FIELD GENMASK(7, 0) 73 + 74 + /* Macro to extract the job ID from a transaction ID. */ 75 + #define STRATIX10_GET_JOBID(transaction_id) \ 76 + (FIELD_GET(STRATIX10_JOB_FIELD, transaction_id)) 77 + /* Macro to set the job ID in a transaction ID. */ 78 + #define STRATIX10_SET_JOBID(jobid) \ 79 + (FIELD_PREP(STRATIX10_JOB_FIELD, jobid)) 80 + /* Macro to set the client ID in a transaction ID. */ 81 + #define STRATIX10_SET_CLIENTID(clientid) \ 82 + (FIELD_PREP(STRATIX10_CLIENT_FIELD, clientid)) 83 + /* Macro to set a transaction ID using a client ID and a job ID. */ 84 + #define STRATIX10_SET_TRANSACTIONID(clientid, jobid) \ 85 + (STRATIX10_SET_CLIENTID(clientid) | STRATIX10_SET_JOBID(jobid)) 86 + /* Macro to set a transaction ID for SIP SMC Async transactions */ 87 + #define STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(transaction_id) \ 88 + (FIELD_PREP(STRATIX10_TRANS_ID_FIELD, transaction_id)) 89 + 50 90 typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long, 51 91 unsigned long, unsigned long, unsigned long, 52 92 unsigned long, unsigned long, ··· 110 64 * @sync_complete: state for a completion 111 65 * @addr: physical address of shared memory block 112 66 * @size: size of shared memory block 113 - * @invoke_fn: function to issue secure monitor or hypervisor call 67 + * @invoke_fn: service clients to handle secure monitor or hypervisor calls 114 68 * 115 69 * This struct is used to save physical address and size of shared memory 116 70 * block. The shared memory blocked is allocated by secure monitor software ··· 169 123 }; 170 124 171 125 /** 126 + * struct stratix10_svc_async_handler - Asynchronous handler for Stratix10 127 + * service layer 128 + * @transaction_id: Unique identifier for the transaction 129 + * @achan: Pointer to the asynchronous channel structure 130 + * @cb_arg: Argument to be passed to the callback function 131 + * @cb: Callback function to be called upon completion 132 + * @msg: Pointer to the client message structure 133 + * @next: Node in the hash list 134 + * @res: Response structure to store result from the secure firmware 135 + * 136 + * This structure is used to handle asynchronous transactions in the 137 + * Stratix10 service layer. It maintains the necessary information 138 + * for processing and completing asynchronous requests. 139 + */ 140 + 141 + struct stratix10_svc_async_handler { 142 + u8 transaction_id; 143 + struct stratix10_async_chan *achan; 144 + void *cb_arg; 145 + async_callback_t cb; 146 + struct stratix10_svc_client_msg *msg; 147 + struct hlist_node next; 148 + struct arm_smccc_1_2_regs res; 149 + }; 150 + 151 + /** 152 + * struct stratix10_async_chan - Structure representing an asynchronous channel 153 + * @async_client_id: Unique client identifier for the asynchronous operation 154 + * @job_id_pool: Pointer to the job ID pool associated with this channel 155 + */ 156 + 157 + struct stratix10_async_chan { 158 + unsigned long async_client_id; 159 + struct ida job_id_pool; 160 + }; 161 + 162 + /** 163 + * struct stratix10_async_ctrl - Control structure for Stratix10 164 + * asynchronous operations 165 + * @initialized: Flag indicating whether the control structure has 166 + * been initialized 167 + * @invoke_fn: Function pointer for invoking Stratix10 service calls 168 + * to EL3 secure firmware 169 + * @async_id_pool: Pointer to the ID pool used for asynchronous 170 + * operations 171 + * @common_achan_refcount: Atomic reference count for the common 172 + * asynchronous channel usage 173 + * @common_async_chan: Pointer to the common asynchronous channel 174 + * structure 175 + * @trx_list_lock: Spinlock for protecting the transaction list 176 + * operations 177 + * @trx_list: Hash table for managing asynchronous transactions 178 + */ 179 + 180 + struct stratix10_async_ctrl { 181 + bool initialized; 182 + void (*invoke_fn)(struct stratix10_async_ctrl *actrl, 183 + const struct arm_smccc_1_2_regs *args, 184 + struct arm_smccc_1_2_regs *res); 185 + struct ida async_id_pool; 186 + atomic_t common_achan_refcount; 187 + struct stratix10_async_chan *common_async_chan; 188 + /* spinlock to protect trx_list hash table */ 189 + spinlock_t trx_list_lock; 190 + DECLARE_HASHTABLE(trx_list, ASYNC_TRX_HASH_BITS); 191 + }; 192 + 193 + /** 172 194 * struct stratix10_svc_controller - service controller 173 195 * @dev: device 174 196 * @chans: array of service channels ··· 249 135 * @complete_status: state for completion 250 136 * @svc_fifo_lock: protect access to service message data queue 251 137 * @invoke_fn: function to issue secure monitor call or hypervisor call 138 + * @actrl: async control structure 252 139 * 253 140 * This struct is used to create communication channels for service clients, to 254 141 * handle secure monitor or hypervisor call. ··· 266 151 struct completion complete_status; 267 152 spinlock_t svc_fifo_lock; 268 153 svc_invoke_fn *invoke_fn; 154 + struct stratix10_async_ctrl actrl; 269 155 }; 270 156 271 157 /** ··· 275 159 * @scl: pointer to service client which owns the channel 276 160 * @name: service client name associated with the channel 277 161 * @lock: protect access to the channel 162 + * @async_chan: reference to asynchronous channel object for this channel 278 163 * 279 - * This struct is used by service client to communicate with service layer, each 280 - * service client has its own channel created by service controller. 164 + * This struct is used by service client to communicate with service layer. 165 + * Each service client has its own channel created by service controller. 281 166 */ 282 167 struct stratix10_svc_chan { 283 168 struct stratix10_svc_controller *ctrl; 284 169 struct stratix10_svc_client *scl; 285 170 char *name; 286 171 spinlock_t lock; 172 + struct stratix10_async_chan *async_chan; 287 173 }; 288 174 289 175 static LIST_HEAD(svc_ctrl); ··· 1061 943 EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname); 1062 944 1063 945 /** 946 + * stratix10_svc_add_async_client - Add an asynchronous client to the 947 + * Stratix10 service channel. 948 + * @chan: Pointer to the Stratix10 service channel structure. 949 + * @use_unique_clientid: Boolean flag indicating whether to use a 950 + * unique client ID. 951 + * 952 + * This function adds an asynchronous client to the specified 953 + * Stratix10 service channel. If the `use_unique_clientid` flag is 954 + * set to true, a unique client ID is allocated for the asynchronous 955 + * channel. Otherwise, a common asynchronous channel is used. 956 + * 957 + * Return: 0 on success, or a negative error code on failure: 958 + * -EINVAL if the channel is NULL or the async controller is 959 + * not initialized. 960 + * -EALREADY if the async channel is already allocated. 961 + * -ENOMEM if memory allocation fails. 962 + * Other negative values if ID allocation fails. 963 + */ 964 + int stratix10_svc_add_async_client(struct stratix10_svc_chan *chan, 965 + bool use_unique_clientid) 966 + { 967 + struct stratix10_svc_controller *ctrl; 968 + struct stratix10_async_ctrl *actrl; 969 + struct stratix10_async_chan *achan; 970 + int ret = 0; 971 + 972 + if (!chan) 973 + return -EINVAL; 974 + 975 + ctrl = chan->ctrl; 976 + actrl = &ctrl->actrl; 977 + 978 + if (!actrl->initialized) { 979 + dev_err(ctrl->dev, "Async controller not initialized\n"); 980 + return -EINVAL; 981 + } 982 + 983 + if (chan->async_chan) { 984 + dev_err(ctrl->dev, "async channel already allocated\n"); 985 + return -EALREADY; 986 + } 987 + 988 + if (use_unique_clientid && 989 + atomic_read(&actrl->common_achan_refcount) > 0) { 990 + chan->async_chan = actrl->common_async_chan; 991 + atomic_inc(&actrl->common_achan_refcount); 992 + return 0; 993 + } 994 + 995 + achan = kzalloc(sizeof(*achan), GFP_KERNEL); 996 + if (!achan) 997 + return -ENOMEM; 998 + 999 + ida_init(&achan->job_id_pool); 1000 + 1001 + ret = ida_alloc_max(&actrl->async_id_pool, MAX_SDM_CLIENT_IDS, 1002 + GFP_KERNEL); 1003 + if (ret < 0) { 1004 + dev_err(ctrl->dev, 1005 + "Failed to allocate async client id\n"); 1006 + ida_destroy(&achan->job_id_pool); 1007 + kfree(achan); 1008 + return ret; 1009 + } 1010 + 1011 + achan->async_client_id = ret; 1012 + chan->async_chan = achan; 1013 + 1014 + if (use_unique_clientid && 1015 + atomic_read(&actrl->common_achan_refcount) == 0) { 1016 + actrl->common_async_chan = achan; 1017 + atomic_inc(&actrl->common_achan_refcount); 1018 + } 1019 + 1020 + return 0; 1021 + } 1022 + EXPORT_SYMBOL_GPL(stratix10_svc_add_async_client); 1023 + 1024 + /** 1025 + * stratix10_svc_remove_async_client - Remove an asynchronous client 1026 + * from the Stratix10 service 1027 + * channel. 1028 + * @chan: Pointer to the Stratix10 service channel structure. 1029 + * 1030 + * This function removes an asynchronous client associated with the 1031 + * given service channel. It checks if the channel and the 1032 + * asynchronous channel are valid, and then proceeds to decrement 1033 + * the reference count for the common asynchronous channel if 1034 + * applicable. If the reference count reaches zero, it destroys the 1035 + * job ID pool and deallocates the asynchronous client ID. For 1036 + * non-common asynchronous channels, it directly destroys the job ID 1037 + * pool, deallocates the asynchronous client ID, and frees the 1038 + * memory allocated for the asynchronous channel. 1039 + * 1040 + * Return: 0 on success, -EINVAL if the channel or asynchronous 1041 + * channel is invalid. 1042 + */ 1043 + int stratix10_svc_remove_async_client(struct stratix10_svc_chan *chan) 1044 + { 1045 + struct stratix10_svc_controller *ctrl; 1046 + struct stratix10_async_ctrl *actrl; 1047 + struct stratix10_async_chan *achan; 1048 + 1049 + if (!chan) 1050 + return -EINVAL; 1051 + 1052 + ctrl = chan->ctrl; 1053 + actrl = &ctrl->actrl; 1054 + achan = chan->async_chan; 1055 + 1056 + if (!achan) { 1057 + dev_err(ctrl->dev, "async channel not allocated\n"); 1058 + return -EINVAL; 1059 + } 1060 + 1061 + if (achan == actrl->common_async_chan) { 1062 + atomic_dec(&actrl->common_achan_refcount); 1063 + if (atomic_read(&actrl->common_achan_refcount) == 0) { 1064 + ida_destroy(&achan->job_id_pool); 1065 + ida_free(&actrl->async_id_pool, 1066 + achan->async_client_id); 1067 + kfree(achan); 1068 + actrl->common_async_chan = NULL; 1069 + } 1070 + } else { 1071 + ida_destroy(&achan->job_id_pool); 1072 + ida_free(&actrl->async_id_pool, achan->async_client_id); 1073 + kfree(achan); 1074 + } 1075 + chan->async_chan = NULL; 1076 + 1077 + return 0; 1078 + } 1079 + EXPORT_SYMBOL_GPL(stratix10_svc_remove_async_client); 1080 + 1081 + /** 1082 + * stratix10_svc_async_send - Send an asynchronous message to the 1083 + * Stratix10 service 1084 + * @chan: Pointer to the service channel structure 1085 + * @msg: Pointer to the message to be sent 1086 + * @handler: Pointer to the handler for the asynchronous message 1087 + * used by caller for later reference. 1088 + * @cb: Callback function to be called upon completion 1089 + * @cb_arg: Argument to be passed to the callback function 1090 + * 1091 + * This function sends an asynchronous message to the SDM mailbox in 1092 + * EL3 secure firmware. It performs various checks and setups, 1093 + * including allocating a job ID, setting up the transaction ID and 1094 + * packaging it to El3 firmware. The function handles different 1095 + * commands by setting up the appropriate arguments for the SMC call. 1096 + * If the SMC call is successful, the handler is set up and the 1097 + * function returns 0. If the SMC call fails, appropriate error 1098 + * handling is performed along with cleanup of resources. 1099 + * 1100 + * Return: 0 on success, -EINVAL for invalid argument, -ENOMEM if 1101 + * memory is not available, -EAGAIN if EL3 firmware is busy, -EBADF 1102 + * if the message is rejected by EL3 firmware and -EIO on other 1103 + * errors from EL3 firmware. 1104 + */ 1105 + int stratix10_svc_async_send(struct stratix10_svc_chan *chan, void *msg, 1106 + void **handler, async_callback_t cb, void *cb_arg) 1107 + { 1108 + struct arm_smccc_1_2_regs args = { 0 }, res = { 0 }; 1109 + struct stratix10_svc_async_handler *handle = NULL; 1110 + struct stratix10_svc_client_msg *p_msg = 1111 + (struct stratix10_svc_client_msg *)msg; 1112 + struct stratix10_svc_controller *ctrl; 1113 + struct stratix10_async_ctrl *actrl; 1114 + struct stratix10_async_chan *achan; 1115 + int ret = 0; 1116 + 1117 + if (!chan || !msg || !handler) 1118 + return -EINVAL; 1119 + 1120 + achan = chan->async_chan; 1121 + ctrl = chan->ctrl; 1122 + actrl = &ctrl->actrl; 1123 + 1124 + if (!actrl->initialized) { 1125 + dev_err(ctrl->dev, "Async controller not initialized\n"); 1126 + return -EINVAL; 1127 + } 1128 + 1129 + if (!achan) { 1130 + dev_err(ctrl->dev, "Async channel not allocated\n"); 1131 + return -EINVAL; 1132 + } 1133 + 1134 + handle = kzalloc(sizeof(*handle), GFP_KERNEL); 1135 + if (!handle) 1136 + return -ENOMEM; 1137 + 1138 + ret = ida_alloc_max(&achan->job_id_pool, MAX_SDM_JOB_IDS, 1139 + GFP_KERNEL); 1140 + if (ret < 0) { 1141 + dev_err(ctrl->dev, "Failed to allocate job id\n"); 1142 + kfree(handle); 1143 + return -ENOMEM; 1144 + } 1145 + 1146 + handle->transaction_id = 1147 + STRATIX10_SET_TRANSACTIONID(achan->async_client_id, ret); 1148 + handle->cb = cb; 1149 + handle->msg = p_msg; 1150 + handle->cb_arg = cb_arg; 1151 + handle->achan = achan; 1152 + 1153 + /*set the transaction jobid in args.a1*/ 1154 + args.a1 = 1155 + STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(handle->transaction_id); 1156 + 1157 + switch (p_msg->command) { 1158 + default: 1159 + dev_err(ctrl->dev, "Invalid command ,%d\n", p_msg->command); 1160 + ret = -EINVAL; 1161 + goto deallocate_id; 1162 + } 1163 + 1164 + /** 1165 + * There is a chance that during the execution of async_send() 1166 + * in one core, an interrupt might be received in another core; 1167 + * to mitigate this we are adding the handle to the DB and then 1168 + * send the smc call. If the smc call is rejected or busy then 1169 + * we will deallocate the handle for the client to retry again. 1170 + */ 1171 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1172 + hash_add(actrl->trx_list, &handle->next, 1173 + handle->transaction_id); 1174 + } 1175 + 1176 + actrl->invoke_fn(actrl, &args, &res); 1177 + 1178 + switch (res.a0) { 1179 + case INTEL_SIP_SMC_STATUS_OK: 1180 + dev_dbg(ctrl->dev, 1181 + "Async message sent with transaction_id 0x%02x\n", 1182 + handle->transaction_id); 1183 + *handler = handle; 1184 + return 0; 1185 + case INTEL_SIP_SMC_STATUS_BUSY: 1186 + dev_warn(ctrl->dev, "Mailbox is busy, try after some time\n"); 1187 + ret = -EAGAIN; 1188 + break; 1189 + case INTEL_SIP_SMC_STATUS_REJECTED: 1190 + dev_err(ctrl->dev, "Async message rejected\n"); 1191 + ret = -EBADF; 1192 + break; 1193 + default: 1194 + dev_err(ctrl->dev, 1195 + "Failed to send async message ,got status as %ld\n", 1196 + res.a0); 1197 + ret = -EIO; 1198 + } 1199 + 1200 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1201 + hash_del(&handle->next); 1202 + } 1203 + 1204 + deallocate_id: 1205 + ida_free(&achan->job_id_pool, 1206 + STRATIX10_GET_JOBID(handle->transaction_id)); 1207 + kfree(handle); 1208 + return ret; 1209 + } 1210 + EXPORT_SYMBOL_GPL(stratix10_svc_async_send); 1211 + /** 1212 + * stratix10_svc_async_poll - Polls the status of an asynchronous 1213 + * transaction. 1214 + * @chan: Pointer to the service channel structure. 1215 + * @tx_handle: Handle to the transaction being polled. 1216 + * @data: Pointer to the callback data structure. 1217 + * 1218 + * This function polls the status of an asynchronous transaction 1219 + * identified by the given transaction handle. It ensures that the 1220 + * necessary structures are initialized and valid before proceeding 1221 + * with the poll operation. The function sets up the necessary 1222 + * arguments for the SMC call, invokes the call, and prepares the 1223 + * response data if the call is successful. If the call fails, the 1224 + * function returns the error mapped to the SVC status error. 1225 + * 1226 + * Return: 0 on success, -EINVAL if any input parameter is invalid, 1227 + * -EAGAIN if the transaction is still in progress, 1228 + * -EPERM if the command is invalid, or other negative 1229 + * error codes on failure. 1230 + */ 1231 + int stratix10_svc_async_poll(struct stratix10_svc_chan *chan, 1232 + void *tx_handle, 1233 + struct stratix10_svc_cb_data *data) 1234 + { 1235 + struct stratix10_svc_async_handler *handle; 1236 + struct arm_smccc_1_2_regs args = { 0 }; 1237 + struct stratix10_svc_controller *ctrl; 1238 + struct stratix10_async_ctrl *actrl; 1239 + struct stratix10_async_chan *achan; 1240 + 1241 + if (!chan || !tx_handle || !data) 1242 + return -EINVAL; 1243 + 1244 + ctrl = chan->ctrl; 1245 + actrl = &ctrl->actrl; 1246 + achan = chan->async_chan; 1247 + 1248 + if (!achan) { 1249 + dev_err(ctrl->dev, "Async channel not allocated\n"); 1250 + return -EINVAL; 1251 + } 1252 + 1253 + handle = (struct stratix10_svc_async_handler *)tx_handle; 1254 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1255 + if (!hash_hashed(&handle->next)) { 1256 + dev_err(ctrl->dev, "Invalid transaction handler"); 1257 + return -EINVAL; 1258 + } 1259 + } 1260 + 1261 + args.a0 = INTEL_SIP_SMC_ASYNC_POLL; 1262 + args.a1 = 1263 + STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(handle->transaction_id); 1264 + 1265 + actrl->invoke_fn(actrl, &args, &handle->res); 1266 + 1267 + /*clear data for response*/ 1268 + memset(data, 0, sizeof(*data)); 1269 + 1270 + if (handle->res.a0 == INTEL_SIP_SMC_STATUS_OK) { 1271 + return 0; 1272 + } else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY) { 1273 + dev_dbg(ctrl->dev, "async message is still in progress\n"); 1274 + return -EAGAIN; 1275 + } 1276 + 1277 + dev_err(ctrl->dev, 1278 + "Failed to poll async message ,got status as %ld\n", 1279 + handle->res.a0); 1280 + return -EINVAL; 1281 + } 1282 + EXPORT_SYMBOL_GPL(stratix10_svc_async_poll); 1283 + 1284 + /** 1285 + * stratix10_svc_async_done - Completes an asynchronous transaction. 1286 + * @chan: Pointer to the service channel structure. 1287 + * @tx_handle: Handle to the transaction being completed. 1288 + * 1289 + * This function completes an asynchronous transaction identified by 1290 + * the given transaction handle. It ensures that the necessary 1291 + * structures are initialized and valid before proceeding with the 1292 + * completion operation. The function deallocates the transaction ID, 1293 + * frees the memory allocated for the handler, and removes the handler 1294 + * from the transaction list. 1295 + * 1296 + * Return: 0 on success, -EINVAL if any input parameter is invalid, 1297 + * or other negative error codes on failure. 1298 + */ 1299 + int stratix10_svc_async_done(struct stratix10_svc_chan *chan, void *tx_handle) 1300 + { 1301 + struct stratix10_svc_async_handler *handle; 1302 + struct stratix10_svc_controller *ctrl; 1303 + struct stratix10_async_chan *achan; 1304 + struct stratix10_async_ctrl *actrl; 1305 + 1306 + if (!chan || !tx_handle) 1307 + return -EINVAL; 1308 + 1309 + ctrl = chan->ctrl; 1310 + achan = chan->async_chan; 1311 + actrl = &ctrl->actrl; 1312 + 1313 + if (!achan) { 1314 + dev_err(ctrl->dev, "async channel not allocated\n"); 1315 + return -EINVAL; 1316 + } 1317 + 1318 + handle = (struct stratix10_svc_async_handler *)tx_handle; 1319 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1320 + if (!hash_hashed(&handle->next)) { 1321 + dev_err(ctrl->dev, "Invalid transaction handle"); 1322 + return -EINVAL; 1323 + } 1324 + hash_del(&handle->next); 1325 + } 1326 + ida_free(&achan->job_id_pool, 1327 + STRATIX10_GET_JOBID(handle->transaction_id)); 1328 + kfree(handle); 1329 + return 0; 1330 + } 1331 + EXPORT_SYMBOL_GPL(stratix10_svc_async_done); 1332 + 1333 + static inline void stratix10_smc_1_2(struct stratix10_async_ctrl *actrl, 1334 + const struct arm_smccc_1_2_regs *args, 1335 + struct arm_smccc_1_2_regs *res) 1336 + { 1337 + arm_smccc_1_2_smc(args, res); 1338 + } 1339 + 1340 + /** 1341 + * stratix10_svc_async_init - Initialize the Stratix10 service 1342 + * controller for asynchronous operations. 1343 + * @controller: Pointer to the Stratix10 service controller structure. 1344 + * 1345 + * This function initializes the asynchronous service controller by 1346 + * setting up the necessary data structures and initializing the 1347 + * transaction list. 1348 + * 1349 + * Return: 0 on success, -EINVAL if the controller is NULL or already 1350 + * initialized, -ENOMEM if memory allocation fails, 1351 + * -EADDRINUSE if the client ID is already reserved, or other 1352 + * negative error codes on failure. 1353 + */ 1354 + static int stratix10_svc_async_init(struct stratix10_svc_controller *controller) 1355 + { 1356 + struct stratix10_async_ctrl *actrl; 1357 + struct arm_smccc_res res; 1358 + struct device *dev; 1359 + int ret; 1360 + 1361 + if (!controller) 1362 + return -EINVAL; 1363 + 1364 + actrl = &controller->actrl; 1365 + 1366 + if (actrl->initialized) 1367 + return -EINVAL; 1368 + 1369 + dev = controller->dev; 1370 + 1371 + controller->invoke_fn(INTEL_SIP_SMC_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); 1372 + if (res.a0 != INTEL_SIP_SMC_STATUS_OK || 1373 + !(res.a1 > ASYNC_ATF_MINIMUM_MAJOR_VERSION || 1374 + (res.a1 == ASYNC_ATF_MINIMUM_MAJOR_VERSION && 1375 + res.a2 >= ASYNC_ATF_MINIMUM_MINOR_VERSION))) { 1376 + dev_err(dev, 1377 + "Intel Service Layer Driver: ATF version is not compatible for async operation\n"); 1378 + return -EINVAL; 1379 + } 1380 + 1381 + actrl->invoke_fn = stratix10_smc_1_2; 1382 + 1383 + ida_init(&actrl->async_id_pool); 1384 + 1385 + /** 1386 + * SIP_SVC_V1_CLIENT_ID is used by V1/stratix10_svc_send() clients 1387 + * for communicating with SDM synchronously. We need to restrict 1388 + * this in V3/stratix10_svc_async_send() usage to distinguish 1389 + * between V1 and V3 messages in El3 firmware. 1390 + */ 1391 + ret = ida_alloc_range(&actrl->async_id_pool, SIP_SVC_V1_CLIENT_ID, 1392 + SIP_SVC_V1_CLIENT_ID, GFP_KERNEL); 1393 + if (ret < 0) { 1394 + dev_err(dev, 1395 + "Intel Service Layer Driver: Error on reserving SIP_SVC_V1_CLIENT_ID\n"); 1396 + ida_destroy(&actrl->async_id_pool); 1397 + actrl->invoke_fn = NULL; 1398 + return -EADDRINUSE; 1399 + } 1400 + 1401 + spin_lock_init(&actrl->trx_list_lock); 1402 + hash_init(actrl->trx_list); 1403 + atomic_set(&actrl->common_achan_refcount, 0); 1404 + 1405 + actrl->initialized = true; 1406 + return 0; 1407 + } 1408 + 1409 + /** 1410 + * stratix10_svc_async_exit - Clean up and exit the asynchronous 1411 + * service controller 1412 + * @ctrl: Pointer to the stratix10_svc_controller structure 1413 + * 1414 + * This function performs the necessary cleanup for the asynchronous 1415 + * service controller. It checks if the controller is valid and if it 1416 + * has been initialized. It then locks the transaction list and safely 1417 + * removes and deallocates each handler in the list. The function also 1418 + * removes any asynchronous clients associated with the controller's 1419 + * channels and destroys the asynchronous ID pool. Finally, it resets 1420 + * the asynchronous ID pool and invoke function pointers to NULL. 1421 + * 1422 + * Return: 0 on success, -EINVAL if the controller is invalid or not 1423 + * initialized. 1424 + */ 1425 + static int stratix10_svc_async_exit(struct stratix10_svc_controller *ctrl) 1426 + { 1427 + struct stratix10_svc_async_handler *handler; 1428 + struct stratix10_async_ctrl *actrl; 1429 + struct hlist_node *tmp; 1430 + int i; 1431 + 1432 + if (!ctrl) 1433 + return -EINVAL; 1434 + 1435 + actrl = &ctrl->actrl; 1436 + 1437 + if (!actrl->initialized) 1438 + return -EINVAL; 1439 + 1440 + actrl->initialized = false; 1441 + 1442 + scoped_guard(spinlock_bh, &actrl->trx_list_lock) { 1443 + hash_for_each_safe(actrl->trx_list, i, tmp, handler, next) { 1444 + ida_free(&handler->achan->job_id_pool, 1445 + STRATIX10_GET_JOBID(handler->transaction_id)); 1446 + hash_del(&handler->next); 1447 + kfree(handler); 1448 + } 1449 + } 1450 + 1451 + for (i = 0; i < SVC_NUM_CHANNEL; i++) { 1452 + if (ctrl->chans[i].async_chan) { 1453 + stratix10_svc_remove_async_client(&ctrl->chans[i]); 1454 + ctrl->chans[i].async_chan = NULL; 1455 + } 1456 + } 1457 + 1458 + ida_destroy(&actrl->async_id_pool); 1459 + actrl->invoke_fn = NULL; 1460 + 1461 + return 0; 1462 + } 1463 + 1464 + /** 1064 1465 * stratix10_svc_free_channel() - free service channel 1065 1466 * @chan: service channel to be freed 1066 1467 * ··· 1834 1197 controller->invoke_fn = invoke_fn; 1835 1198 init_completion(&controller->complete_status); 1836 1199 1200 + ret = stratix10_svc_async_init(controller); 1201 + if (ret) { 1202 + dev_dbg(dev, "Intel Service Layer Driver: Error on stratix10_svc_async_init %d\n", 1203 + ret); 1204 + goto err_destroy_pool; 1205 + } 1206 + 1837 1207 fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO; 1838 1208 ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL); 1839 1209 if (ret) { 1840 1210 dev_err(dev, "failed to allocate FIFO\n"); 1841 - goto err_destroy_pool; 1211 + goto err_async_exit; 1842 1212 } 1843 1213 spin_lock_init(&controller->svc_fifo_lock); 1844 1214 ··· 1921 1277 platform_device_unregister(svc->stratix10_svc_rsu); 1922 1278 err_free_kfifo: 1923 1279 kfifo_free(&controller->svc_fifo); 1280 + err_async_exit: 1281 + stratix10_svc_async_exit(controller); 1924 1282 err_destroy_pool: 1925 1283 gen_pool_destroy(genpool); 1926 1284 return ret; ··· 1932 1286 { 1933 1287 struct stratix10_svc *svc = dev_get_drvdata(&pdev->dev); 1934 1288 struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev); 1289 + 1290 + stratix10_svc_async_exit(ctrl); 1935 1291 1936 1292 of_platform_depopulate(ctrl->dev); 1937 1293
+25
include/linux/firmware/intel/stratix10-smc.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 3 * Copyright (C) 2017-2018, Intel Corporation 4 + * Copyright (C) 2025, Altera Corporation 4 5 */ 5 6 6 7 #ifndef __STRATIX10_SMC_H ··· 47 46 #define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \ 48 47 ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ 49 48 ARM_SMCCC_OWNER_SIP, (func_num)) 49 + 50 + #define INTEL_SIP_SMC_ASYNC_VAL(func_name) \ 51 + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \ 52 + ARM_SMCCC_OWNER_SIP, (func_name)) 50 53 51 54 /** 52 55 * Return values in INTEL_SIP_SMC_* call ··· 659 654 #define INTEL_SIP_SMC_HWMON_READVOLT \ 660 655 INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_HWMON_READVOLT) 661 656 657 + /** 658 + * Request INTEL_SIP_SMC_ASYNC_POLL 659 + * Async call used by service driver at EL1 to query mailbox response from SDM. 660 + * 661 + * Call register usage: 662 + * a0 INTEL_SIP_SMC_ASYNC_POLL 663 + * a1 transaction job id 664 + * a2-17 will be used to return the response data 665 + * 666 + * Return status 667 + * a0 INTEL_SIP_SMC_STATUS_OK 668 + * a1-17 will contain the response values from mailbox for the previous send 669 + * transaction 670 + * Or 671 + * a0 INTEL_SIP_SMC_STATUS_NO_RESPONSE 672 + * a1-17 not used 673 + */ 674 + #define INTEL_SIP_SMC_ASYNC_FUNC_ID_POLL (0xC8) 675 + #define INTEL_SIP_SMC_ASYNC_POLL \ 676 + INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_POLL) 662 677 #endif
+88
include/linux/firmware/intel/stratix10-svc-client.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 3 * Copyright (C) 2017-2018, Intel Corporation 4 + * Copyright (C) 2025, Altera Corporation 4 5 */ 5 6 6 7 #ifndef __STRATIX10_SVC_CLIENT_H ··· 291 290 * request process. 292 291 */ 293 292 void stratix10_svc_done(struct stratix10_svc_chan *chan); 293 + 294 + /** 295 + * typedef async_callback_t - A type definition for an asynchronous callback function. 296 + * 297 + * This type defines a function pointer for an asynchronous callback. 298 + * The callback function takes a single argument, which is a pointer to 299 + * user-defined data. 300 + * 301 + * @param cb_arg A pointer to user-defined data passed to the callback function. 302 + */ 303 + typedef void (*async_callback_t)(void *cb_arg); 304 + 305 + /** 306 + * stratix10_svc_add_async_client - Add an asynchronous client to a Stratix 10 307 + * service channel. 308 + * @chan: Pointer to the Stratix 10 service channel structure. 309 + * @use_unique_clientid: Boolean flag indicating whether to use a unique client ID. 310 + * 311 + * This function registers an asynchronous client with the specified Stratix 10 312 + * service channel. If the use_unique_clientid flag is set to true, a unique client 313 + * ID will be assigned to the client. 314 + * 315 + * Return: 0 on success, or a negative error code on failure: 316 + * -EINVAL if the channel is NULL or the async controller is not initialized. 317 + * -EALREADY if the async channel is already allocated. 318 + * -ENOMEM if memory allocation fails. 319 + * Other negative values if ID allocation fails 320 + */ 321 + int stratix10_svc_add_async_client(struct stratix10_svc_chan *chan, bool use_unique_clientid); 322 + 323 + /** 324 + * stratix10_svc_remove_async_client - Remove an asynchronous client from the Stratix 10 325 + * service channel. 326 + * @chan: Pointer to the Stratix 10 service channel structure. 327 + * 328 + * This function removes an asynchronous client from the specified Stratix 10 service channel. 329 + * It is typically used to clean up and release resources associated with the client. 330 + * 331 + * Return: 0 on success, -EINVAL if the channel or asynchronous channel is invalid. 332 + */ 333 + int stratix10_svc_remove_async_client(struct stratix10_svc_chan *chan); 334 + 335 + /** 336 + * stratix10_svc_async_send - Send an asynchronous message to the SDM mailbox 337 + * in EL3 secure firmware. 338 + * @chan: Pointer to the service channel structure. 339 + * @msg: Pointer to the message to be sent. 340 + * @handler: Pointer to the handler object used by caller to track the transaction. 341 + * @cb: Callback function to be called upon completion. 342 + * @cb_arg: Argument to be passed to the callback function. 343 + * 344 + * This function sends a message asynchronously to the SDM mailbox in EL3 secure firmware. 345 + * and registers a callback function to be invoked when the operation completes. 346 + * 347 + * Return: 0 on success,and negative error codes on failure. 348 + */ 349 + int stratix10_svc_async_send(struct stratix10_svc_chan *chan, void *msg, void **handler, 350 + async_callback_t cb, void *cb_arg); 351 + 352 + /** 353 + * stratix10_svc_async_poll - Polls the status of an asynchronous service request. 354 + * @chan: Pointer to the service channel structure. 355 + * @tx_handle: Handle to the transaction being polled. 356 + * @data: Pointer to the callback data structure to be filled with the result. 357 + * 358 + * This function checks the status of an asynchronous service request 359 + * and fills the provided callback data structure with the result. 360 + * 361 + * Return: 0 on success, -EINVAL if any input parameter is invalid or if the 362 + * async controller is not initialized, -EAGAIN if the transaction is 363 + * still in progress, or other negative error codes on failure. 364 + */ 365 + int stratix10_svc_async_poll(struct stratix10_svc_chan *chan, void *tx_handle, 366 + struct stratix10_svc_cb_data *data); 367 + 368 + /** 369 + * stratix10_svc_async_done - Complete an asynchronous transaction 370 + * @chan: Pointer to the service channel structure 371 + * @tx_handle: Pointer to the transaction handle 372 + * 373 + * This function completes an asynchronous transaction by removing the 374 + * transaction from the hash table and deallocating the associated resources. 375 + * 376 + * Return: 0 on success, -EINVAL on invalid input or errors. 377 + */ 378 + int stratix10_svc_async_done(struct stratix10_svc_chan *chan, void *tx_handle); 379 + 294 380 #endif 295 381