xref: /rk3399_ARM-atf/drivers/arm/rse/rse_comms.c (revision e249e56954ed81924d53b47eb068f61182c8ed1d)
195511698STamas Ban /*
295511698STamas Ban  * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
395511698STamas Ban  *
495511698STamas Ban  * SPDX-License-Identifier: BSD-3-Clause
595511698STamas Ban  */
695511698STamas Ban 
795511698STamas Ban #include <stdint.h>
895511698STamas Ban #include <string.h>
995511698STamas Ban 
1095511698STamas Ban #include <common/debug.h>
1195511698STamas Ban #include <drivers/arm/mhu.h>
12*e249e569STamas Ban #include <drivers/arm/rse_comms.h>
1395511698STamas Ban #include <psa/client.h>
14*e249e569STamas Ban #include <rse_comms_protocol.h>
1595511698STamas Ban 
1695511698STamas Ban /* Union as message space and reply space are never used at the same time, and this saves space as
1795511698STamas Ban  * we can overlap them.
1895511698STamas Ban  */
19*e249e569STamas Ban union __packed __attribute__((aligned(4))) rse_comms_io_buffer_t {
20*e249e569STamas Ban 	struct serialized_rse_comms_msg_t msg;
21*e249e569STamas Ban 	struct serialized_rse_comms_reply_t reply;
2295511698STamas Ban };
2395511698STamas Ban 
2495511698STamas Ban static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
2595511698STamas Ban 				       const psa_outvec *out_vec, size_t out_len)
2695511698STamas Ban {
2795511698STamas Ban 	size_t comms_mhu_msg_size;
2895511698STamas Ban 	size_t comms_embed_msg_min_size;
2995511698STamas Ban 	size_t comms_embed_reply_min_size;
3095511698STamas Ban 	size_t in_size_total = 0;
3195511698STamas Ban 	size_t out_size_total = 0;
3295511698STamas Ban 	size_t i;
3395511698STamas Ban 
3495511698STamas Ban 	for (i = 0U; i < in_len; ++i) {
3595511698STamas Ban 		in_size_total += in_vec[i].len;
3695511698STamas Ban 	}
3795511698STamas Ban 	for (i = 0U; i < out_len; ++i) {
3895511698STamas Ban 		out_size_total += out_vec[i].len;
3995511698STamas Ban 	}
4095511698STamas Ban 
4195511698STamas Ban 	comms_mhu_msg_size = mhu_get_max_message_size();
4295511698STamas Ban 
43*e249e569STamas Ban 	comms_embed_msg_min_size = sizeof(struct serialized_rse_comms_header_t) +
44*e249e569STamas Ban 				   sizeof(struct rse_embed_msg_t) -
45*e249e569STamas Ban 				   PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE;
4695511698STamas Ban 
47*e249e569STamas Ban 	comms_embed_reply_min_size = sizeof(struct serialized_rse_comms_header_t) +
48*e249e569STamas Ban 				     sizeof(struct rse_embed_reply_t) -
49*e249e569STamas Ban 				     PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE;
5095511698STamas Ban 
5195511698STamas Ban 	/* Use embed if we can pack into one message and reply, else use
5295511698STamas Ban 	 * pointer_access. The underlying MHU transport protocol uses a
5395511698STamas Ban 	 * single uint32_t to track the length, so the amount of data that
5495511698STamas Ban 	 * can be in a message is 4 bytes less than mhu_get_max_message_size
5595511698STamas Ban 	 * reports.
5695511698STamas Ban 	 *
5795511698STamas Ban 	 * TODO tune this with real performance numbers, it's possible a
5895511698STamas Ban 	 * pointer_access message is less performant than multiple embed
5995511698STamas Ban 	 * messages due to ATU configuration costs to allow access to the
6095511698STamas Ban 	 * pointers.
6195511698STamas Ban 	 */
6295511698STamas Ban 	if ((comms_embed_msg_min_size + in_size_total >
6395511698STamas Ban 	     comms_mhu_msg_size - sizeof(uint32_t)) ||
6495511698STamas Ban 	    (comms_embed_reply_min_size + out_size_total >
6595511698STamas Ban 	     comms_mhu_msg_size - sizeof(uint32_t))) {
66*e249e569STamas Ban 		return RSE_COMMS_PROTOCOL_POINTER_ACCESS;
6795511698STamas Ban 	} else {
68*e249e569STamas Ban 		return RSE_COMMS_PROTOCOL_EMBED;
6995511698STamas Ban 	}
7095511698STamas Ban }
7195511698STamas Ban 
7295511698STamas Ban psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
7395511698STamas Ban 		      psa_outvec *out_vec, size_t out_len)
7495511698STamas Ban {
7595511698STamas Ban 	/* Declared statically to avoid using huge amounts of stack space. Maybe revisit if
7695511698STamas Ban 	 * functions not being reentrant becomes a problem.
7795511698STamas Ban 	 */
78*e249e569STamas Ban 	static union rse_comms_io_buffer_t io_buf;
7995511698STamas Ban 	enum mhu_error_t err;
8095511698STamas Ban 	psa_status_t status;
8195511698STamas Ban 	static uint8_t seq_num = 1U;
8295511698STamas Ban 	size_t msg_size;
8395511698STamas Ban 	size_t reply_size = sizeof(io_buf.reply);
8495511698STamas Ban 	psa_status_t return_val;
8595511698STamas Ban 	size_t idx;
8695511698STamas Ban 
8795511698STamas Ban 	if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN ||
8895511698STamas Ban 	    in_len > PSA_MAX_IOVEC   || out_len > PSA_MAX_IOVEC) {
8995511698STamas Ban 		return PSA_ERROR_INVALID_ARGUMENT;
9095511698STamas Ban 	}
9195511698STamas Ban 
9295511698STamas Ban 	io_buf.msg.header.seq_num = seq_num,
9395511698STamas Ban 	/* No need to distinguish callers (currently concurrent calls are not supported). */
9495511698STamas Ban 	io_buf.msg.header.client_id = 1U,
9595511698STamas Ban 	io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
9695511698STamas Ban 
97*e249e569STamas Ban 	status = rse_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec,
9895511698STamas Ban 					    out_len, &io_buf.msg, &msg_size);
9995511698STamas Ban 	if (status != PSA_SUCCESS) {
10095511698STamas Ban 		return status;
10195511698STamas Ban 	}
10295511698STamas Ban 
103*e249e569STamas Ban 	VERBOSE("[RSE-COMMS] Sending message\n");
10495511698STamas Ban 	VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver);
10595511698STamas Ban 	VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num);
10695511698STamas Ban 	VERBOSE("client_id=%u\n", io_buf.msg.header.client_id);
10795511698STamas Ban 	for (idx = 0; idx < in_len; idx++) {
10895511698STamas Ban 		VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
10995511698STamas Ban 		VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
11095511698STamas Ban 	}
11195511698STamas Ban 
11295511698STamas Ban 	err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size);
11395511698STamas Ban 	if (err != MHU_ERR_NONE) {
11495511698STamas Ban 		return PSA_ERROR_COMMUNICATION_FAILURE;
11595511698STamas Ban 	}
11695511698STamas Ban 
11795511698STamas Ban #if DEBUG
11895511698STamas Ban 	/*
11995511698STamas Ban 	 * Poisoning the message buffer (with a known pattern).
120*e249e569STamas Ban 	 * Helps in detecting hypothetical RSE communication bugs.
12195511698STamas Ban 	 */
12295511698STamas Ban 	memset(&io_buf.msg, 0xA5, msg_size);
12395511698STamas Ban #endif
12495511698STamas Ban 
12595511698STamas Ban 	err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size);
12695511698STamas Ban 	if (err != MHU_ERR_NONE) {
12795511698STamas Ban 		return PSA_ERROR_COMMUNICATION_FAILURE;
12895511698STamas Ban 	}
12995511698STamas Ban 
130*e249e569STamas Ban 	VERBOSE("[RSE-COMMS] Received reply\n");
13195511698STamas Ban 	VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver);
13295511698STamas Ban 	VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num);
13395511698STamas Ban 	VERBOSE("client_id=%u\n", io_buf.reply.header.client_id);
13495511698STamas Ban 
135*e249e569STamas Ban 	status = rse_protocol_deserialize_reply(out_vec, out_len, &return_val,
13695511698STamas Ban 						&io_buf.reply, reply_size);
13795511698STamas Ban 	if (status != PSA_SUCCESS) {
13895511698STamas Ban 		return status;
13995511698STamas Ban 	}
14095511698STamas Ban 
14195511698STamas Ban 	VERBOSE("return_val=%d\n", return_val);
14295511698STamas Ban 	for (idx = 0U; idx < out_len; idx++) {
14395511698STamas Ban 		VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
14495511698STamas Ban 		VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
14595511698STamas Ban 	}
14695511698STamas Ban 
14795511698STamas Ban 	/* Clear the MHU message buffer to remove assets from memory */
14895511698STamas Ban 	memset(&io_buf, 0x0, sizeof(io_buf));
14995511698STamas Ban 
15095511698STamas Ban 	seq_num++;
15195511698STamas Ban 
15295511698STamas Ban 	return return_val;
15395511698STamas Ban }
15495511698STamas Ban 
155*e249e569STamas Ban int rse_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
15695511698STamas Ban {
15795511698STamas Ban 	enum mhu_error_t err;
15895511698STamas Ban 
15995511698STamas Ban 	err = mhu_init_sender(mhu_sender_base);
16095511698STamas Ban 	if (err != MHU_ERR_NONE) {
16195511698STamas Ban 		if (err == MHU_ERR_ALREADY_INIT) {
162*e249e569STamas Ban 			INFO("[RSE-COMMS] Host to RSE MHU driver already initialized\n");
16395511698STamas Ban 		} else {
164*e249e569STamas Ban 			ERROR("[RSE-COMMS] Host to RSE MHU driver initialization failed: %d\n", err);
16595511698STamas Ban 			return -1;
16695511698STamas Ban 		}
16795511698STamas Ban 	}
16895511698STamas Ban 
16995511698STamas Ban 	err = mhu_init_receiver(mhu_receiver_base);
17095511698STamas Ban 	if (err != MHU_ERR_NONE) {
17195511698STamas Ban 		if (err == MHU_ERR_ALREADY_INIT) {
172*e249e569STamas Ban 			INFO("[RSE-COMMS] RSE to Host MHU driver already initialized\n");
17395511698STamas Ban 		} else {
174*e249e569STamas Ban 			ERROR("[RSE-COMMS] RSE to Host MHU driver initialization failed: %d\n", err);
17595511698STamas Ban 			return -1;
17695511698STamas Ban 		}
17795511698STamas Ban 	}
17895511698STamas Ban 
17995511698STamas Ban 	return 0;
18095511698STamas Ban }
181