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