1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. 4 * Copyright (c) 2019-2022, Linaro Limited 5 */ 6 #include <assert.h> 7 #include <drivers/scmi-msg.h> 8 #include <drivers/scmi.h> 9 #include <io.h> 10 #include <stdbool.h> 11 #include <stdint.h> 12 #include <trace.h> 13 #include <util.h> 14 15 #include "common.h" 16 17 /** 18 * struct smt_header - SMT formatted header for SMT base shared memory transfer 19 * 20 * @status: Bit flags, see SMT_STATUS_* 21 * @flags: Bit flags, see SMT_FLAG_* 22 * @length: Byte size of message payload (variable) + ::message_header (32bit) 23 * payload: SCMI message payload data 24 */ 25 struct smt_header { 26 uint32_t reserved0; 27 uint32_t status; 28 uint64_t reserved1; 29 uint32_t flags; 30 uint32_t length; /* message_header + payload */ 31 uint32_t message_header; 32 uint32_t payload[]; 33 }; 34 35 /* Flag set in smt_header::status when SMT does not contain pending message */ 36 #define SMT_STATUS_FREE BIT(0) 37 /* Flag set in smt_header::status when SMT reports an error */ 38 #define SMT_STATUS_ERROR BIT(1) 39 40 /* Flag set in smt_header::flags when SMT uses interrupts */ 41 #define SMT_FLAG_INTR_ENABLED BIT(1) 42 43 /* Bit fields packed in smt_header::message_header */ 44 #define SMT_MSG_ID_MASK GENMASK_32(7, 0) 45 #define SMT_HDR_MSG_ID(_hdr) ((_hdr) & SMT_MSG_ID_MASK) 46 47 #define SMT_MSG_TYPE_MASK GENMASK_32(9, 8) 48 #define SMT_HDR_TYPE_ID(_hdr) (((_hdr) & SMT_MSG_TYPE_MASK) >> 8) 49 50 #define SMT_MSG_PROT_ID_MASK GENMASK_32(17, 10) 51 #define SMT_HDR_PROT_ID(_hdr) (((_hdr) & SMT_MSG_PROT_ID_MASK) >> 10) 52 53 static struct smt_header *channel_to_smt_hdr(struct scmi_msg_channel *channel) 54 { 55 if (!channel) 56 return NULL; 57 58 return (struct smt_header *)io_pa_or_va(&channel->shm_addr, 59 sizeof(struct smt_header)); 60 } 61 62 /* 63 * Creates a SCMI message instance in secure memory and push it in the SCMI 64 * message drivers. Message structure contains SCMI protocol meta-data and 65 * references to input payload in secure memory and output message buffer 66 * in shared memory. 67 */ 68 void scmi_entry_smt(unsigned int channel_id, uint32_t *payload_buf) 69 { 70 struct scmi_msg_channel *channel = NULL; 71 struct smt_header *smt_hdr = NULL; 72 size_t in_payload_size = 0; 73 uint32_t smt_status = 0; 74 struct scmi_msg msg = { }; 75 bool error = true; 76 77 channel = plat_scmi_get_channel(channel_id); 78 if (!channel) { 79 DMSG("Invalid channel ID %u", channel_id); 80 return; 81 } 82 83 smt_hdr = channel_to_smt_hdr(channel); 84 if (!smt_hdr) { 85 DMSG("No shared buffer for channel ID %u", channel_id); 86 return; 87 } 88 89 if (!scmi_msg_claim_channel(channel)) { 90 DMSG("SCMI channel %u busy", channel_id); 91 goto out; 92 } 93 94 smt_status = READ_ONCE(smt_hdr->status); 95 96 in_payload_size = READ_ONCE(smt_hdr->length) - 97 sizeof(smt_hdr->message_header); 98 99 if (in_payload_size > SCMI_SEC_PAYLOAD_SIZE) { 100 DMSG("SCMI payload too big %u", in_payload_size); 101 goto out; 102 } 103 104 if (smt_status & (SMT_STATUS_ERROR | SMT_STATUS_FREE)) { 105 DMSG("SCMI channel bad status 0x%x", 106 smt_hdr->status & (SMT_STATUS_ERROR | SMT_STATUS_FREE)); 107 goto out; 108 } 109 110 /* Fill message */ 111 msg.in = (char *)payload_buf; 112 msg.in_size = in_payload_size; 113 msg.out = (char *)smt_hdr->payload; 114 msg.out_size = channel->shm_size - sizeof(*smt_hdr); 115 116 assert(msg.out && msg.out_size >= sizeof(int32_t)); 117 118 /* Here the payload is copied in secure memory */ 119 memcpy(msg.in, smt_hdr->payload, in_payload_size); 120 121 msg.protocol_id = SMT_HDR_PROT_ID(smt_hdr->message_header); 122 msg.message_id = SMT_HDR_MSG_ID(smt_hdr->message_header); 123 msg.channel_id = channel_id; 124 125 scmi_process_message(&msg); 126 127 /* Update message length with the length of the response message */ 128 smt_hdr->length = msg.out_size_out + sizeof(smt_hdr->message_header); 129 130 scmi_msg_release_channel(channel); 131 error = false; 132 133 out: 134 if (error) { 135 DMSG("SCMI error"); 136 smt_hdr->status |= SMT_STATUS_ERROR | SMT_STATUS_FREE; 137 } else { 138 smt_hdr->status |= SMT_STATUS_FREE; 139 } 140 } 141 142 /* Init a SMT header for a shared memory buffer: state it a free/no-error */ 143 void scmi_smt_init_agent_channel(struct scmi_msg_channel *channel) 144 { 145 struct smt_header *smt_header = channel_to_smt_hdr(channel); 146 147 static_assert(SCMI_SEC_PAYLOAD_SIZE + sizeof(struct smt_header) <= 148 SMT_BUF_SLOT_SIZE && 149 IS_ALIGNED(SCMI_SEC_PAYLOAD_SIZE, sizeof(uint32_t))); 150 assert(smt_header); 151 152 memset(smt_header, 0, sizeof(*smt_header)); 153 smt_header->status = SMT_STATUS_FREE; 154 } 155 156 void scmi_smt_set_shared_buffer(struct scmi_msg_channel *channel, void *base) 157 { 158 paddr_t p_base = 0; 159 160 if (base) { 161 assert(!channel->shm_addr.va && !channel->shm_addr.pa); 162 p_base = virt_to_phys(base); 163 assert(p_base); 164 } 165 166 channel->shm_addr.va = (vaddr_t)base; 167 channel->shm_addr.pa = p_base; 168 } 169