xref: /rk3399_ARM-atf/drivers/arm/sfcp/sfcp_psa/sfcp_psa_call/sfcp_psa_call.c (revision 2801427972c4b0d4c0165edb509f21186103f21f)
1 /*
2  * Copyright (c) 2026, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <common/debug.h>
9 #include <drivers/arm/sfcp.h>
10 #include "psa/client.h"
11 #include "sfcp_psa_protocol.h"
12 
13 /* These are specific to the server to which we are sending PSA
14  * requests. We need the node ID for the remote node and the
15  * application ID of the PSA service
16  */
17 #define SFCP_PSA_SERVER_NODE_ID (0)
18 #define SFCP_PSA_SERVER_APPLICATION_ID (0)
19 
20 /* TODO: Tune this value. Initially aim to only make use of embed message
21  * protocol if it can fit in a single MHU transfer (assuming a standard
22  * number of channels of 16 with 1 channel for message length and 1
23  * channel for signalling). This will need to be tuned per platform
24  */
25 #define SFCP_MHU_MAX_TRANSFER_SIZE ((16 - 2) * sizeof(uint32_t))
26 
27 /* Use for both the message and reply, define to the larger of
28  * the two
29  *
30  * TODO: This needs to be reconsidered if reentrancy is required
31  */
32 static __aligned(4) uint8_t
33 	psa_payload_buf[SFCP_BUFFER_MINIMUM_SIZE +
34 			(sizeof(struct serialized_psa_msg_t) >
35 					 sizeof(struct serialized_psa_reply_t) ?
36 				 sizeof(struct serialized_psa_msg_t) :
37 				 sizeof(struct serialized_psa_reply_t))];
38 
39 static enum sfcp_protocol_version_t
select_protocol_version(const psa_invec * in_vec,size_t in_len,const psa_outvec * out_vec,size_t out_len)40 select_protocol_version(const psa_invec *in_vec, size_t in_len,
41 			const psa_outvec *out_vec, size_t out_len)
42 {
43 	size_t comms_embed_msg_min_size;
44 	size_t comms_embed_reply_min_size;
45 	size_t in_size_total = 0;
46 	size_t out_size_total = 0;
47 	size_t i;
48 
49 	for (i = 0U; i < in_len; ++i) {
50 		in_size_total += in_vec[i].len;
51 	}
52 	for (i = 0U; i < out_len; ++i) {
53 		out_size_total += out_vec[i].len;
54 	}
55 
56 	comms_embed_msg_min_size =
57 		sizeof(struct serialized_sfcp_header_t) +
58 		sizeof(struct sfcp_embed_msg_t) -
59 		sizeof(((struct sfcp_embed_msg_t *)0)->payload);
60 
61 	comms_embed_reply_min_size =
62 		sizeof(struct serialized_sfcp_header_t) +
63 		sizeof(struct sfcp_embed_reply_t) -
64 		sizeof(((struct sfcp_embed_reply_t *)0)->payload);
65 
66 	if ((comms_embed_msg_min_size + in_size_total >
67 	     SFCP_MHU_MAX_TRANSFER_SIZE) ||
68 	    (comms_embed_reply_min_size + out_size_total >
69 	     SFCP_MHU_MAX_TRANSFER_SIZE)) {
70 		return SFCP_PROTOCOL_POINTER_ACCESS;
71 	} else {
72 		return SFCP_PROTOCOL_EMBED;
73 	}
74 }
75 
select_client_id(void)76 static uint16_t select_client_id(void)
77 {
78 	/* Client ID value of 0 is reserved
79 	 *
80 	 * TODO: This needs to be reconsidered if reentrancy becomes a problem.
81 	 * In this case, we need to dynamically allocate a client ID to each
82 	 * caller
83 	 */
84 	return 1;
85 }
86 
psa_call(psa_handle_t handle,int32_t type,const psa_invec * in_vec,size_t in_len,psa_outvec * out_vec,size_t out_len)87 psa_status_t psa_call(psa_handle_t handle, int32_t type,
88 		      const psa_invec *in_vec, size_t in_len,
89 		      psa_outvec *out_vec, size_t out_len)
90 {
91 	psa_status_t status;
92 	enum sfcp_error_t sfcp_err;
93 	struct serialized_psa_msg_t *psa_msg;
94 	struct serialized_psa_reply_t *psa_reply = NULL;
95 	size_t psa_msg_len;
96 	size_t payload_len;
97 	struct sfcp_packet_t *msg;
98 	size_t msg_size;
99 	struct sfcp_reply_metadata_t metadata;
100 	psa_status_t return_val;
101 	const uint16_t client_id = select_client_id();
102 
103 	if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN ||
104 	    in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
105 		return PSA_ERROR_INVALID_ARGUMENT;
106 	}
107 
108 	sfcp_err = sfcp_init_msg(psa_payload_buf, sizeof(psa_payload_buf),
109 				 SFCP_PSA_SERVER_NODE_ID,
110 				 SFCP_PSA_SERVER_APPLICATION_ID, client_id,
111 				 true, false, 0, (uint8_t **)&psa_msg,
112 				 &payload_len, &msg, &msg_size, &metadata);
113 	if (sfcp_err != SFCP_ERROR_SUCCESS) {
114 		return PSA_ERROR_COMMUNICATION_FAILURE;
115 	}
116 
117 	if (payload_len < sizeof(struct serialized_psa_msg_t)) {
118 		return PSA_ERROR_INSUFFICIENT_STORAGE;
119 	}
120 
121 	psa_msg->header.protocol_ver =
122 		select_protocol_version(in_vec, in_len, out_vec, out_len);
123 
124 	VERBOSE("[SFCP] Sending message\n");
125 	VERBOSE("protocol_ver=%u\n", psa_msg->header.protocol_ver);
126 	for (size_t idx = 0; idx < in_len; idx++) {
127 		VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
128 		VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
129 	}
130 
131 	status = sfcp_protocol_serialize_msg(handle, type, in_vec, in_len,
132 					     out_vec, out_len, psa_msg,
133 					     &psa_msg_len);
134 	if (status != PSA_SUCCESS) {
135 		return status;
136 	}
137 
138 	sfcp_err = sfcp_send_msg(msg, msg_size, psa_msg_len);
139 	if (sfcp_err != SFCP_ERROR_SUCCESS) {
140 		return PSA_ERROR_COMMUNICATION_FAILURE;
141 	}
142 
143 	do {
144 		sfcp_err = sfcp_receive_reply(psa_payload_buf,
145 					      sizeof(psa_payload_buf), metadata,
146 					      (uint8_t **)&psa_reply,
147 					      &payload_len);
148 	} while (sfcp_err == SFCP_ERROR_NO_REPLY_AVAILABLE);
149 	if (sfcp_err != SFCP_ERROR_SUCCESS) {
150 		return PSA_ERROR_COMMUNICATION_FAILURE;
151 	}
152 
153 	VERBOSE("[SFCP] Received reply\n");
154 	VERBOSE("protocol_ver=%u\n", psa_reply->header.protocol_ver);
155 
156 	status = sfcp_protocol_deserialize_reply(out_vec, out_len, &return_val,
157 						 psa_reply, payload_len);
158 	if (status != PSA_SUCCESS) {
159 		return status;
160 	}
161 
162 	VERBOSE("return_val=%d\n", return_val);
163 	for (size_t idx = 0U; idx < out_len; idx++) {
164 		VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
165 		VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
166 	}
167 
168 	return return_val;
169 }
170