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