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