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 
channel_to_smt_hdr(struct scmi_msg_channel * channel)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  */
scmi_entry_smt(unsigned int channel_id,uint32_t * payload_buf)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 */
scmi_smt_init_agent_channel(struct scmi_msg_channel * channel)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 
scmi_smt_set_shared_buffer(struct scmi_msg_channel * channel,void * base)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