xref: /optee_os/core/arch/riscv/kernel/sbi_mpxy_rpmi.c (revision 26e3e52d2b5fb28265a9873c147a868fcdadbe45)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2025 NXP
4  */
5 
6 #include <riscv.h>
7 #include <rpmi.h>
8 #include <sbi.h>
9 #include <sbi_mpxy.h>
10 #include <sbi_mpxy_rpmi.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 struct sbi_mpxy_rpmi_context *sbi_mpxy_rpmi_ctx;
15 
16 /**
17  * @brief Probes available MPXY channels supporting the RPMI protocol.
18  *
19  * This function initializes the global RPMI context by identifying available
20  * MPXY channels with the RPMI protocol, reading their attributes, and
21  * allocating memory for handling notifications. The result is stored in a
22  * global context (sbi_mpxy_rpmi_ctx). If probing fails, the context is set to
23  * NULL.
24  */
sbi_mpxy_rpmi_probe_channels(void)25 void sbi_mpxy_rpmi_probe_channels(void)
26 {
27 	struct sbi_mpxy_rpmi_channel *channel = NULL;
28 	uint32_t *channel_ids = NULL;
29 	unsigned long mpxy_shmem_size = 0;
30 	uint32_t valid_channels = 0;
31 	uint32_t i = 0;
32 	int ret = 0;
33 	uint32_t channel_id = 0;
34 
35 	if (sbi_mpxy_rpmi_ctx) {
36 		EMSG("RPMI/MPXY context already initialized");
37 		return;
38 	}
39 
40 	ret = sbi_mpxy_get_shmem_size(&mpxy_shmem_size);
41 	if (ret) {
42 		EMSG("Failed to get MPXY shared memory size (ret=%d)", ret);
43 		goto error;
44 	}
45 
46 	sbi_mpxy_rpmi_ctx = calloc(1, sizeof(*sbi_mpxy_rpmi_ctx));
47 	if (!sbi_mpxy_rpmi_ctx) {
48 		EMSG("Out of memory for RPMI context");
49 		goto error;
50 	}
51 
52 	ret = sbi_mpxy_get_channel_count(&sbi_mpxy_rpmi_ctx->channel_count);
53 	if (ret || !sbi_mpxy_rpmi_ctx->channel_count) {
54 		EMSG("Failed to get MPXY channel count (ret=%d)", ret);
55 		goto error;
56 	}
57 
58 	channel_ids =
59 		calloc(sbi_mpxy_rpmi_ctx->channel_count, sizeof(*channel_ids));
60 	if (!channel_ids) {
61 		EMSG("Failed to allocate channel ID list");
62 		goto error;
63 	}
64 
65 	ret = sbi_mpxy_get_channel_ids(sbi_mpxy_rpmi_ctx->channel_count,
66 				       channel_ids);
67 	if (ret) {
68 		EMSG("Failed to fetch channel IDs (ret=%d)", ret);
69 		goto error;
70 	}
71 
72 	sbi_mpxy_rpmi_ctx->channels =
73 		calloc(sbi_mpxy_rpmi_ctx->channel_count,
74 		       sizeof(*sbi_mpxy_rpmi_ctx->channels));
75 	if (!sbi_mpxy_rpmi_ctx->channels) {
76 		EMSG("Failed to allocate channel table");
77 		goto error;
78 	}
79 
80 	for (i = 0; i < sbi_mpxy_rpmi_ctx->channel_count; i++) {
81 		channel_id = channel_ids[i];
82 		channel = &sbi_mpxy_rpmi_ctx->channels[valid_channels];
83 		channel->channel_id = channel_id;
84 
85 		ret = sbi_mpxy_read_attributes(channel_id,
86 					       SBI_MPXY_ATTR_MSG_PROT_ID,
87 					       sizeof(channel->attrs) /
88 						       sizeof(uint32_t),
89 					       &channel->attrs);
90 		if (ret) {
91 			EMSG("Failed to read MPXY attributes for channel %u",
92 			     channel_id);
93 			continue;
94 		}
95 
96 		if (channel->attrs.msg_proto_id != SBI_MPXY_MSGPROTO_RPMI_ID) {
97 			DMSG("Channel %u is not RPMI (proto_id=%u), skipping",
98 			     channel_id, channel->attrs.msg_proto_id);
99 			continue;
100 		}
101 
102 		ret = sbi_mpxy_rpmi_read_attributes(channel);
103 		if (ret) {
104 			EMSG("Failed to read RPMI attributes for channel %u",
105 			     channel_id);
106 			continue;
107 		}
108 
109 		channel->notif = malloc(mpxy_shmem_size);
110 		if (!channel->notif) {
111 			EMSG("No memory for channel %u notif buffer",
112 			     channel_id);
113 			goto error;
114 		}
115 
116 		memset(channel->notif, 0, mpxy_shmem_size);
117 		valid_channels++;
118 	}
119 
120 	free(channel_ids);
121 	channel_ids = NULL;
122 
123 	if (!valid_channels) {
124 		EMSG("No usable RPMI channels found");
125 		goto error;
126 	}
127 
128 	sbi_mpxy_rpmi_ctx->channel_count = valid_channels;
129 	return;
130 
131 error:
132 	if (channel_ids)
133 		free(channel_ids);
134 
135 	if (sbi_mpxy_rpmi_ctx) {
136 		if (sbi_mpxy_rpmi_ctx->channels) {
137 			for (i = 0; i < valid_channels; i++)
138 				free(sbi_mpxy_rpmi_ctx->channels[i].notif);
139 			free(sbi_mpxy_rpmi_ctx->channels);
140 		}
141 		free(sbi_mpxy_rpmi_ctx);
142 		sbi_mpxy_rpmi_ctx = NULL;
143 	}
144 }
145 
146 /**
147  * @brief Reads RPMI-specific attributes from a given MPXY channel.
148  *
149  * This function queries and fills the RPMI-specific attribute structure
150  * (rpmi_attrs) for the specified channel using the SBI MPXY interface.
151  *
152  * @param channel Pointer to the RPMI channel instance to query.
153  *
154  * @return 0 on success, or a negative SBI error code on failure.
155  */
sbi_mpxy_rpmi_read_attributes(struct sbi_mpxy_rpmi_channel * channel)156 int sbi_mpxy_rpmi_read_attributes(struct sbi_mpxy_rpmi_channel *channel)
157 {
158 	return sbi_mpxy_read_attributes(channel->channel_id,
159 					SBI_MPXY_ATTR_MSGPROTO_ATTR_START,
160 					sizeof(channel->rpmi_attrs) /
161 						sizeof(uint32_t),
162 					&channel->rpmi_attrs);
163 }
164 
165 /**
166  * @brief Sends a raw RPMI message over an MPXY channel.
167  *
168  * This function transmits a message to the associated platform microcontroller
169  * (PuC) using the given RPMI-enabled MPXY channel.
170  *
171  * @param channel Pointer to the RPMI channel used for transmission.
172  * @param data Pointer to the message payload to send. It must be a
173  *             properly initialized RPMI message structure.
174  *
175  * @return 0 on success, or a negative RPMI or SBI error code on failure.
176  */
sbi_mpxy_rpmi_send_data(struct sbi_mpxy_rpmi_channel * channel,void * data)177 int sbi_mpxy_rpmi_send_data(struct sbi_mpxy_rpmi_channel *channel, void *data)
178 {
179 	struct sbi_mpxy_rpmi_message *message = data;
180 	int ret = 0;
181 
182 	if (channel->attrs.msg_proto_id != SBI_MPXY_MSGPROTO_RPMI_ID)
183 		return RPMI_ERR_NOTSUPP;
184 
185 	switch (message->type) {
186 	case SBI_MPXY_RPMI_MSG_TYPE_GET_ATTRIBUTE:
187 		switch (message->attribute.id) {
188 		case SBI_MPXY_RPMI_ATTR_SERVICEGROUP_ID:
189 			message->attribute.value =
190 				channel->rpmi_attrs.servicegroup_id;
191 			break;
192 		case SBI_MPXY_RPMI_ATTR_SERVICEGROUP_VERSION:
193 			message->attribute.value =
194 				channel->rpmi_attrs.servicegroup_version;
195 			break;
196 		case SBI_MPXY_RPMI_ATTR_IMPLEMENTATION_ID:
197 			message->attribute.value =
198 				channel->rpmi_attrs.implementation_id;
199 			break;
200 		case SBI_MPXY_RPMI_ATTR_IMPLEMENTATION_VERSION:
201 			message->attribute.value =
202 				channel->rpmi_attrs.implementation_version;
203 			break;
204 		default:
205 			ret = RPMI_ERR_NOTSUPP;
206 			break;
207 		}
208 		break;
209 	case SBI_MPXY_RPMI_MSG_TYPE_SET_ATTRIBUTE:
210 		/*
211 		 * All RPMI Message Protocol Attributes of an SBI MPXY Channel
212 		 * are RO.
213 		 */
214 		ret = RPMI_ERR_NOTSUPP;
215 		break;
216 	case SBI_MPXY_RPMI_MSG_TYPE_SEND_WITH_RESPONSE:
217 		if ((!message->data.request && message->data.request_len) ||
218 		    (!message->data.response &&
219 		     message->data.max_response_len)) {
220 			ret = RPMI_ERR_INVALID_PARAM;
221 			break;
222 		}
223 		if (!(channel->attrs.capability &
224 		      SBI_MPXY_CHAN_CAP_SEND_WITH_RESP)) {
225 			ret = RPMI_ERR_IO;
226 			break;
227 		}
228 		ret = sbi_mpxy_send_message_with_response(channel->channel_id
229 		      , message->data.service_id, message->data.request,
230 		      message->data.request_len, message->data.response,
231 		      message->data.max_response_len,
232 		      &message->data.response_len);
233 		break;
234 	case SBI_MPXY_RPMI_MSG_TYPE_SEND_WITHOUT_RESPONSE:
235 		if (!message->data.request && message->data.request_len) {
236 			ret = RPMI_ERR_INVALID_PARAM;
237 			break;
238 		}
239 		if (!(channel->attrs.capability &
240 		      SBI_MPXY_CHAN_CAP_SEND_WITHOUT_RESP)) {
241 			ret = RPMI_ERR_IO;
242 			break;
243 		}
244 		ret = sbi_mpxy_send_message_without_response(channel->channel_id
245 		      , message->data.service_id, message->data.request,
246 		      message->data.request_len);
247 		break;
248 	default:
249 		ret = RPMI_ERR_NOTSUPP;
250 		break;
251 	}
252 
253 	message->error = ret;
254 
255 	return RPMI_SUCCESS;
256 }
257