xref: /arm-trusted-firmware/drivers/arm/rss/rss_comms.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2022, Arm Limited. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <stdint.h>
8*91f16700Schasinglulu #include <string.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <common/debug.h>
11*91f16700Schasinglulu #include <drivers/arm/mhu.h>
12*91f16700Schasinglulu #include <drivers/arm/rss_comms.h>
13*91f16700Schasinglulu #include <psa/client.h>
14*91f16700Schasinglulu #include <rss_comms_protocol.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu /* Union as message space and reply space are never used at the same time, and this saves space as
17*91f16700Schasinglulu  * we can overlap them.
18*91f16700Schasinglulu  */
19*91f16700Schasinglulu union __packed __attribute__((aligned(4))) rss_comms_io_buffer_t {
20*91f16700Schasinglulu 	struct serialized_rss_comms_msg_t msg;
21*91f16700Schasinglulu 	struct serialized_rss_comms_reply_t reply;
22*91f16700Schasinglulu };
23*91f16700Schasinglulu 
24*91f16700Schasinglulu static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
25*91f16700Schasinglulu 				       const psa_outvec *out_vec, size_t out_len)
26*91f16700Schasinglulu {
27*91f16700Schasinglulu 	size_t comms_mhu_msg_size;
28*91f16700Schasinglulu 	size_t comms_embed_msg_min_size;
29*91f16700Schasinglulu 	size_t comms_embed_reply_min_size;
30*91f16700Schasinglulu 	size_t in_size_total = 0;
31*91f16700Schasinglulu 	size_t out_size_total = 0;
32*91f16700Schasinglulu 	size_t i;
33*91f16700Schasinglulu 
34*91f16700Schasinglulu 	for (i = 0U; i < in_len; ++i) {
35*91f16700Schasinglulu 		in_size_total += in_vec[i].len;
36*91f16700Schasinglulu 	}
37*91f16700Schasinglulu 	for (i = 0U; i < out_len; ++i) {
38*91f16700Schasinglulu 		out_size_total += out_vec[i].len;
39*91f16700Schasinglulu 	}
40*91f16700Schasinglulu 
41*91f16700Schasinglulu 	comms_mhu_msg_size = mhu_get_max_message_size();
42*91f16700Schasinglulu 
43*91f16700Schasinglulu 	comms_embed_msg_min_size = sizeof(struct serialized_rss_comms_header_t) +
44*91f16700Schasinglulu 				   sizeof(struct rss_embed_msg_t) -
45*91f16700Schasinglulu 				   PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
46*91f16700Schasinglulu 
47*91f16700Schasinglulu 	comms_embed_reply_min_size = sizeof(struct serialized_rss_comms_header_t) +
48*91f16700Schasinglulu 				     sizeof(struct rss_embed_reply_t) -
49*91f16700Schasinglulu 				     PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
50*91f16700Schasinglulu 
51*91f16700Schasinglulu 	/* Use embed if we can pack into one message and reply, else use
52*91f16700Schasinglulu 	 * pointer_access. The underlying MHU transport protocol uses a
53*91f16700Schasinglulu 	 * single uint32_t to track the length, so the amount of data that
54*91f16700Schasinglulu 	 * can be in a message is 4 bytes less than mhu_get_max_message_size
55*91f16700Schasinglulu 	 * reports.
56*91f16700Schasinglulu 	 *
57*91f16700Schasinglulu 	 * TODO tune this with real performance numbers, it's possible a
58*91f16700Schasinglulu 	 * pointer_access message is less performant than multiple embed
59*91f16700Schasinglulu 	 * messages due to ATU configuration costs to allow access to the
60*91f16700Schasinglulu 	 * pointers.
61*91f16700Schasinglulu 	 */
62*91f16700Schasinglulu 	if ((comms_embed_msg_min_size + in_size_total > comms_mhu_msg_size - sizeof(uint32_t))
63*91f16700Schasinglulu 	 || (comms_embed_reply_min_size + out_size_total > comms_mhu_msg_size) - sizeof(uint32_t)) {
64*91f16700Schasinglulu 		return RSS_COMMS_PROTOCOL_POINTER_ACCESS;
65*91f16700Schasinglulu 	} else {
66*91f16700Schasinglulu 		return RSS_COMMS_PROTOCOL_EMBED;
67*91f16700Schasinglulu 	}
68*91f16700Schasinglulu }
69*91f16700Schasinglulu 
70*91f16700Schasinglulu psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
71*91f16700Schasinglulu 		      psa_outvec *out_vec, size_t out_len)
72*91f16700Schasinglulu {
73*91f16700Schasinglulu 	/* Declared statically to avoid using huge amounts of stack space. Maybe revisit if
74*91f16700Schasinglulu 	 * functions not being reentrant becomes a problem.
75*91f16700Schasinglulu 	 */
76*91f16700Schasinglulu 	static union rss_comms_io_buffer_t io_buf;
77*91f16700Schasinglulu 	enum mhu_error_t err;
78*91f16700Schasinglulu 	psa_status_t status;
79*91f16700Schasinglulu 	static uint8_t seq_num = 1U;
80*91f16700Schasinglulu 	size_t msg_size;
81*91f16700Schasinglulu 	size_t reply_size = sizeof(io_buf.reply);
82*91f16700Schasinglulu 	psa_status_t return_val;
83*91f16700Schasinglulu 	size_t idx;
84*91f16700Schasinglulu 
85*91f16700Schasinglulu 	if (type > INT16_MAX || type < INT16_MIN || in_len > PSA_MAX_IOVEC
86*91f16700Schasinglulu 	    || out_len > PSA_MAX_IOVEC) {
87*91f16700Schasinglulu 		return PSA_ERROR_INVALID_ARGUMENT;
88*91f16700Schasinglulu 	}
89*91f16700Schasinglulu 
90*91f16700Schasinglulu 	io_buf.msg.header.seq_num = seq_num,
91*91f16700Schasinglulu 	/* No need to distinguish callers (currently concurrent calls are not supported). */
92*91f16700Schasinglulu 	io_buf.msg.header.client_id = 1U,
93*91f16700Schasinglulu 	io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 	status = rss_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec,
96*91f16700Schasinglulu 					    out_len, &io_buf.msg, &msg_size);
97*91f16700Schasinglulu 	if (status != PSA_SUCCESS) {
98*91f16700Schasinglulu 		return status;
99*91f16700Schasinglulu 	}
100*91f16700Schasinglulu 
101*91f16700Schasinglulu 	VERBOSE("[RSS-COMMS] Sending message\n");
102*91f16700Schasinglulu 	VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver);
103*91f16700Schasinglulu 	VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num);
104*91f16700Schasinglulu 	VERBOSE("client_id=%u\n", io_buf.msg.header.client_id);
105*91f16700Schasinglulu 	for (idx = 0; idx < in_len; idx++) {
106*91f16700Schasinglulu 		VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
107*91f16700Schasinglulu 		VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
108*91f16700Schasinglulu 	}
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 	err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size);
111*91f16700Schasinglulu 	if (err != MHU_ERR_NONE) {
112*91f16700Schasinglulu 		return PSA_ERROR_COMMUNICATION_FAILURE;
113*91f16700Schasinglulu 	}
114*91f16700Schasinglulu 
115*91f16700Schasinglulu #if DEBUG
116*91f16700Schasinglulu 	/*
117*91f16700Schasinglulu 	 * Poisoning the message buffer (with a known pattern).
118*91f16700Schasinglulu 	 * Helps in detecting hypothetical RSS communication bugs.
119*91f16700Schasinglulu 	 */
120*91f16700Schasinglulu 	memset(&io_buf.msg, 0xA5, msg_size);
121*91f16700Schasinglulu #endif
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 	err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size);
124*91f16700Schasinglulu 	if (err != MHU_ERR_NONE) {
125*91f16700Schasinglulu 		return PSA_ERROR_COMMUNICATION_FAILURE;
126*91f16700Schasinglulu 	}
127*91f16700Schasinglulu 
128*91f16700Schasinglulu 	VERBOSE("[RSS-COMMS] Received reply\n");
129*91f16700Schasinglulu 	VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver);
130*91f16700Schasinglulu 	VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num);
131*91f16700Schasinglulu 	VERBOSE("client_id=%u\n", io_buf.reply.header.client_id);
132*91f16700Schasinglulu 
133*91f16700Schasinglulu 	status = rss_protocol_deserialize_reply(out_vec, out_len, &return_val,
134*91f16700Schasinglulu 						&io_buf.reply, reply_size);
135*91f16700Schasinglulu 	if (status != PSA_SUCCESS) {
136*91f16700Schasinglulu 		return status;
137*91f16700Schasinglulu 	}
138*91f16700Schasinglulu 
139*91f16700Schasinglulu 	VERBOSE("return_val=%d\n", return_val);
140*91f16700Schasinglulu 	for (idx = 0U; idx < out_len; idx++) {
141*91f16700Schasinglulu 		VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
142*91f16700Schasinglulu 		VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
143*91f16700Schasinglulu 	}
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 	/* Clear the MHU message buffer to remove assets from memory */
146*91f16700Schasinglulu 	memset(&io_buf, 0x0, sizeof(io_buf));
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	seq_num++;
149*91f16700Schasinglulu 
150*91f16700Schasinglulu 	return return_val;
151*91f16700Schasinglulu }
152*91f16700Schasinglulu 
153*91f16700Schasinglulu int rss_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
154*91f16700Schasinglulu {
155*91f16700Schasinglulu 	enum mhu_error_t err;
156*91f16700Schasinglulu 
157*91f16700Schasinglulu 	err = mhu_init_sender(mhu_sender_base);
158*91f16700Schasinglulu 	if (err != MHU_ERR_NONE) {
159*91f16700Schasinglulu 		if (err == MHU_ERR_ALREADY_INIT) {
160*91f16700Schasinglulu 			INFO("[RSS-COMMS] Host to RSS MHU driver already initialized\n");
161*91f16700Schasinglulu 		} else {
162*91f16700Schasinglulu 			ERROR("[RSS-COMMS] Host to RSS MHU driver initialization failed: %d\n", err);
163*91f16700Schasinglulu 			return -1;
164*91f16700Schasinglulu 		}
165*91f16700Schasinglulu 	}
166*91f16700Schasinglulu 
167*91f16700Schasinglulu 	err = mhu_init_receiver(mhu_receiver_base);
168*91f16700Schasinglulu 	if (err != MHU_ERR_NONE) {
169*91f16700Schasinglulu 		if (err == MHU_ERR_ALREADY_INIT) {
170*91f16700Schasinglulu 			INFO("[RSS-COMMS] RSS to Host MHU driver already initialized\n");
171*91f16700Schasinglulu 		} else {
172*91f16700Schasinglulu 			ERROR("[RSS-COMMS] RSS to Host MHU driver initialization failed: %d\n", err);
173*91f16700Schasinglulu 			return -1;
174*91f16700Schasinglulu 		}
175*91f16700Schasinglulu 	}
176*91f16700Schasinglulu 
177*91f16700Schasinglulu 	return 0;
178*91f16700Schasinglulu }
179