1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. 4 * Copyright (c) 2019-2020, Linaro Limited 5 */ 6 #include <assert.h> 7 #include <drivers/scmi-msg.h> 8 #include <drivers/scmi.h> 9 #include <io.h> 10 #include <kernel/misc.h> 11 #include <kernel/panic.h> 12 #include <kernel/spinlock.h> 13 #include <stdbool.h> 14 #include <stdint.h> 15 #include <string.h> 16 #include <trace.h> 17 #include <util.h> 18 19 #include "common.h" 20 21 /* Legacy SMT/SCMI messages are 128 bytes at most including SMT header */ 22 #define SCMI_PLAYLOAD_MAX 92 23 #define SCMI_PLAYLOAD_U32_MAX (SCMI_PLAYLOAD_MAX / sizeof(uint32_t)) 24 25 /** 26 * struct smt_header - SMT formatted header for SMT base shared memory transfer 27 * 28 * @status: Bit flags, see SMT_STATUS_* 29 * @flags: Bit flags, see SMT_FLAG_* 30 * @length: Byte size of message payload (variable) + ::message_header (32bit) 31 * payload: SCMI message payload data 32 */ 33 struct smt_header { 34 uint32_t reserved0; 35 uint32_t status; 36 uint64_t reserved1; 37 uint32_t flags; 38 uint32_t length; /* message_header + payload */ 39 uint32_t message_header; 40 uint32_t payload[]; 41 }; 42 43 /* Flag set in smt_header::status when SMT does not contain pending message */ 44 #define SMT_STATUS_FREE BIT(0) 45 /* Flag set in smt_header::status when SMT reports an error */ 46 #define SMT_STATUS_ERROR BIT(1) 47 48 /* Flag set in smt_header::flags when SMT uses interrupts */ 49 #define SMT_FLAG_INTR_ENABLED BIT(1) 50 51 /* Bit fields packed in smt_header::message_header */ 52 #define SMT_MSG_ID_MASK GENMASK_32(7, 0) 53 #define SMT_HDR_MSG_ID(_hdr) ((_hdr) & SMT_MSG_ID_MASK) 54 55 #define SMT_MSG_TYPE_MASK GENMASK_32(9, 8) 56 #define SMT_HDR_TYPE_ID(_hdr) (((_hdr) & SMT_MSG_TYPE_MASK) >> 8) 57 58 #define SMT_MSG_PROT_ID_MASK GENMASK_32(17, 10) 59 #define SMT_HDR_PROT_ID(_hdr) (((_hdr) & SMT_MSG_PROT_ID_MASK) >> 10) 60 61 /* SMP protection on channel access */ 62 static unsigned int smt_channels_lock; 63 64 /* If channel is not busy, set busy and return true, otherwise return false */ 65 static bool channel_set_busy(struct scmi_msg_channel *chan) 66 { 67 uint32_t exceptions = cpu_spin_lock_xsave(&smt_channels_lock); 68 bool channel_is_busy = chan->busy; 69 70 if (!channel_is_busy) 71 chan->busy = true; 72 73 cpu_spin_unlock_xrestore(&smt_channels_lock, exceptions); 74 75 return !channel_is_busy; 76 } 77 78 static void channel_release_busy(struct scmi_msg_channel *chan) 79 { 80 chan->busy = false; 81 } 82 83 static struct smt_header *channel_to_smt_hdr(struct scmi_msg_channel *chan) 84 { 85 return (struct smt_header *)io_pa_or_va(&chan->shm_addr, 86 sizeof(struct smt_header)); 87 } 88 89 /* 90 * Creates a SCMI message instance in secure memory and push it in the SCMI 91 * message drivers. Message structure contains SCMI protocol meta-data and 92 * references to input payload in secure memory and output message buffer 93 * in shared memory. 94 */ 95 static void scmi_process_smt(unsigned int channel_id, uint32_t *payload_buf) 96 { 97 struct scmi_msg_channel *chan = NULL; 98 struct smt_header *smt_hdr = NULL; 99 size_t in_payload_size = 0; 100 uint32_t smt_status = 0; 101 struct scmi_msg msg = { }; 102 bool error = true; 103 104 chan = plat_scmi_get_channel(channel_id); 105 if (!chan) 106 return; 107 108 smt_hdr = channel_to_smt_hdr(chan); 109 assert(smt_hdr); 110 111 smt_status = READ_ONCE(smt_hdr->status); 112 113 if (!channel_set_busy(chan)) { 114 DMSG("SCMI channel %u busy", channel_id); 115 goto out; 116 } 117 118 in_payload_size = READ_ONCE(smt_hdr->length) - 119 sizeof(smt_hdr->message_header); 120 121 if (in_payload_size > SCMI_PLAYLOAD_MAX) { 122 DMSG("SCMI payload too big %u", in_payload_size); 123 goto out; 124 } 125 126 if (smt_status & (SMT_STATUS_ERROR | SMT_STATUS_FREE)) { 127 DMSG("SCMI channel bad status 0x%x", 128 smt_hdr->status & (SMT_STATUS_ERROR | SMT_STATUS_FREE)); 129 goto out; 130 } 131 132 /* Fill message */ 133 msg.in = (char *)payload_buf; 134 msg.in_size = in_payload_size; 135 msg.out = (char *)smt_hdr->payload; 136 msg.out_size = chan->shm_size - sizeof(*smt_hdr); 137 138 assert(msg.out && msg.out_size >= sizeof(int32_t)); 139 140 /* Here the payload is copied in secure memory */ 141 memcpy(msg.in, smt_hdr->payload, in_payload_size); 142 143 msg.protocol_id = SMT_HDR_PROT_ID(smt_hdr->message_header); 144 msg.message_id = SMT_HDR_MSG_ID(smt_hdr->message_header); 145 msg.channel_id = channel_id; 146 147 scmi_process_message(&msg); 148 149 /* Update message length with the length of the response message */ 150 smt_hdr->length = msg.out_size_out + sizeof(smt_hdr->message_header); 151 152 channel_release_busy(chan); 153 error = false; 154 155 out: 156 if (error) { 157 DMSG("SCMI error"); 158 smt_hdr->status |= SMT_STATUS_ERROR | SMT_STATUS_FREE; 159 } else { 160 smt_hdr->status |= SMT_STATUS_FREE; 161 } 162 } 163 164 #ifdef CFG_SCMI_MSG_SMT_FASTCALL_ENTRY 165 /* Provision input message payload buffers for fastcall SMC context entries */ 166 static uint32_t fast_smc_payload[CFG_TEE_CORE_NB_CORE][SCMI_PLAYLOAD_U32_MAX]; 167 168 void scmi_smt_fastcall_smc_entry(unsigned int channel_id) 169 { 170 scmi_process_smt(channel_id, fast_smc_payload[get_core_pos()]); 171 } 172 #endif 173 174 #ifdef CFG_SCMI_MSG_SMT_INTERRUPT_ENTRY 175 /* Provision input message payload buffers for fastcall SMC context entries */ 176 static uint32_t interrupt_payload[CFG_TEE_CORE_NB_CORE][SCMI_PLAYLOAD_U32_MAX]; 177 178 void scmi_smt_interrupt_entry(unsigned int channel_id) 179 { 180 scmi_process_smt(channel_id, interrupt_payload[get_core_pos()]); 181 } 182 #endif 183 184 #ifdef CFG_SCMI_MSG_SMT_THREAD_ENTRY 185 /* Provision input message payload buffers for fastcall SMC context entries */ 186 static uint32_t threaded_payload[CFG_NUM_THREADS][SCMI_PLAYLOAD_U32_MAX]; 187 188 void scmi_smt_threaded_entry(unsigned int channel_id) 189 { 190 assert(plat_scmi_get_channel(channel_id)->threaded); 191 192 scmi_process_smt(channel_id, threaded_payload[thread_get_id()]); 193 } 194 #endif 195 196 /* Init a SMT header for a shared memory buffer: state it a free/no-error */ 197 void scmi_smt_init_agent_channel(struct scmi_msg_channel *chan) 198 { 199 COMPILE_TIME_ASSERT(SCMI_PLAYLOAD_MAX + sizeof(struct smt_header) <= 200 SMT_BUF_SLOT_SIZE); 201 202 if (chan) { 203 struct smt_header *smt_header = channel_to_smt_hdr(chan); 204 205 if (smt_header) { 206 memset(smt_header, 0, sizeof(*smt_header)); 207 smt_header->status = SMT_STATUS_FREE; 208 209 return; 210 } 211 } 212 213 panic(); 214 } 215 216 void scmi_smt_set_shared_buffer(struct scmi_msg_channel *channel, void *base) 217 { 218 paddr_t p_base = 0; 219 220 if (base) { 221 assert(!channel->shm_addr.va && !channel->shm_addr.pa); 222 p_base = virt_to_phys(base); 223 assert(p_base); 224 } 225 226 channel->shm_addr.va = (vaddr_t)base; 227 channel->shm_addr.pa = p_base; 228 } 229