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