1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <debug.h>
9
10 #include <mod_debug.h>
11
12 #include <fwk_assert.h>
13 #include <fwk_core.h>
14 #include <fwk_id.h>
15 #include <fwk_macros.h>
16 #include <fwk_mm.h>
17 #include <fwk_module.h>
18 #include <fwk_module_idx.h>
19 #include <fwk_status.h>
20
21 #include <stdbool.h>
22
23 static struct debug_dev_ctx *ctx_table;
24
mark_user(fwk_id_t id,bool enable,enum scp_debug_user user_id)25 static inline void mark_user(fwk_id_t id,
26 bool enable,
27 enum scp_debug_user user_id)
28 {
29 uint32_t user_mask = (1 << user_id);
30 struct debug_dev_ctx *ctx = &ctx_table[fwk_id_get_element_idx(id)];
31
32 if (enable) {
33 /* Add user to the list of users that is enabling this element */
34 ctx->debug_users_mask |= user_mask;
35 } else {
36 /* Remove current user */
37 ctx->debug_users_mask &= ~user_mask;
38 }
39 }
40
41 /*
42 * APIs
43 */
44
45 /*
46 * This function can be called by the USER_AP as part of processing a request
47 * coming (usually) from scmi_power_domain.
48 * It can also be called from this module when processing an event that was
49 * generated by the driver (USER_DAP). In this case, there is no need to submit
50 * an event as per 'deferred_response_architecture', because the
51 * driver does not require any response.
52 */
set_enabled(fwk_id_t id,bool enable,enum scp_debug_user user_id)53 static int set_enabled(fwk_id_t id, bool enable, enum scp_debug_user user_id)
54 {
55 uint32_t user_mask;
56 struct debug_dev_ctx *ctx;
57 struct fwk_event req;
58 int status;
59 struct mod_debug_request_params *req_params;
60
61 if (!fwk_expect(user_id < SCP_DEBUG_USER_COUNT)) {
62 return FWK_E_PARAM;
63 }
64
65 ctx = &ctx_table[fwk_id_get_element_idx(id)];
66
67 if (ctx->state != DEBUG_IDLE) {
68 return FWK_E_BUSY;
69 }
70
71 user_mask = (1 << user_id);
72
73 /*
74 * Ensure that the user attempting to enable the element had not already
75 * enabled it.
76 */
77 if ((enable && (ctx->debug_users_mask & user_mask)) ||
78 (!enable && (!(ctx->debug_users_mask & user_mask)))) {
79 return FWK_E_ACCESS;
80 }
81
82 status = ctx->driver_api->set_enabled(ctx->config->driver_id,
83 enable, user_id);
84 if (status == FWK_PENDING) {
85 if (user_id == SCP_DEBUG_USER_DAP) {
86 /*
87 * In case the request comes from the driver, we won't respond so
88 * we don't even need to put an event
89 */
90 ctx->requester = user_id;
91 ctx->state = DEBUG_SET;
92 return FWK_PENDING;
93 }
94
95 req = (struct fwk_event) {
96 .target_id = id,
97 .id = mod_debug_event_id_req_enable_set,
98 .response_requested = true,
99 };
100
101 req_params = (struct mod_debug_request_params *)&req.params;
102 req_params->user_id = user_id;
103 req_params->enable = enable;
104
105 status = fwk_put_event(&req);
106 if (status == FWK_SUCCESS) {
107 ctx->state = DEBUG_SET;
108 return FWK_PENDING;
109 }
110
111 return status;
112 } else if (status != FWK_SUCCESS) {
113 return status;
114 }
115
116 mark_user(id, enable, user_id);
117
118 return FWK_SUCCESS;
119 }
120
get_enabled(fwk_id_t id,bool * enable,enum scp_debug_user user_id)121 static int get_enabled(fwk_id_t id, bool *enable, enum scp_debug_user user_id)
122 {
123 struct debug_dev_ctx *ctx;
124 struct fwk_event req;
125 int status;
126 struct mod_debug_request_params *req_params;
127
128 if ((enable == NULL) || !fwk_expect(user_id < SCP_DEBUG_USER_COUNT)) {
129 return FWK_E_PARAM;
130 }
131
132 ctx = &ctx_table[fwk_id_get_element_idx(id)];
133
134 if (ctx->state != DEBUG_IDLE) {
135 return FWK_E_BUSY;
136 }
137
138 status = ctx->driver_api->get_enabled(ctx->config->driver_id,
139 enable, user_id);
140 if (status == FWK_PENDING) {
141 req = (struct fwk_event) {
142 .target_id = id,
143 .id = mod_debug_event_id_req_enable_get,
144 .response_requested = true,
145 };
146
147 req_params = (struct mod_debug_request_params *)&req.params;
148 req_params->user_id = user_id;
149
150 status = fwk_put_event(&req);
151 if (status == FWK_SUCCESS) {
152 ctx->state = DEBUG_GET;
153 return FWK_PENDING;
154 }
155
156 return status;
157 }
158
159 return status;
160 }
161
debug_reset(fwk_id_t id)162 static int debug_reset(fwk_id_t id)
163 {
164 return FWK_E_SUPPORT;
165 }
166
debug_end(fwk_id_t id)167 static int debug_end(fwk_id_t id)
168 {
169 return FWK_E_SUPPORT;
170 }
171
172 static const struct mod_debug_api debug_api = {
173 .set_enabled = set_enabled,
174 .get_enabled = get_enabled,
175 .reset = debug_reset,
176 .end = debug_end,
177 };
178
179 /*
180 * Driver Input API
181 */
182
enable_request(fwk_id_t id,bool enable,enum scp_debug_user user_id)183 static int enable_request(fwk_id_t id,
184 bool enable,
185 enum scp_debug_user user_id)
186 {
187 struct fwk_event req;
188 struct mod_debug_request_params *req_params;
189 struct debug_dev_ctx *ctx;
190
191 ctx = &ctx_table[fwk_id_get_element_idx(id)];
192
193 fwk_assert(user_id == SCP_DEBUG_USER_DAP);
194
195 req = (struct fwk_event) {
196 .target_id = id,
197 .source_id = ctx->config->driver_id,
198 .id = mod_debug_event_id_req_drv,
199 };
200
201 req_params = (struct mod_debug_request_params *)&req.params;
202 req_params->user_id = user_id;
203 req_params->enable = enable;
204
205 return fwk_put_event(&req);
206 }
207
208 /*
209 * Driver Response API
210 */
211
request_complete(fwk_id_t id,struct mod_debug_response_params * response)212 static void request_complete(fwk_id_t id,
213 struct mod_debug_response_params *response)
214 {
215 int status;
216 struct fwk_event event;
217 struct debug_dev_ctx *ctx;
218 struct mod_debug_response_params *resp_params =
219 (struct mod_debug_response_params *)event.params;
220
221 fwk_assert(response != NULL);
222
223 ctx = &ctx_table[fwk_id_get_element_idx(id)];
224
225 if (ctx->requester == SCP_DEBUG_USER_DAP) {
226 mark_user(id, response->enabled, ctx->requester);
227 ctx->state = DEBUG_IDLE;
228 return;
229 }
230
231 event = (struct fwk_event) {
232 .source_id = ctx->config->driver_id,
233 .target_id = id,
234 };
235
236 if (ctx->state == DEBUG_GET) {
237 event.id = mod_debug_event_id_get_complete;
238 } else {
239 event.id = mod_debug_event_id_set_complete;
240 }
241
242 resp_params->status = response->status;
243 resp_params->enabled = response->enabled;
244
245 status = fwk_put_event(&event);
246 fwk_assert(status == FWK_SUCCESS);
247 }
248
249 static const struct mod_debug_driver_input_api driver_input_api = {
250 .enable = enable_request,
251 .request_complete = request_complete,
252 };
253
254 /*
255 * Framework handlers
256 */
mod_debug_init(fwk_id_t module_id,unsigned int element_count,const void * unused)257 static int mod_debug_init(
258 fwk_id_t module_id,
259 unsigned int element_count,
260 const void *unused)
261 {
262 fwk_assert(element_count > 0);
263
264 ctx_table = fwk_mm_calloc(element_count, sizeof(struct debug_dev_ctx));
265 if (ctx_table == NULL) {
266 return FWK_E_NOMEM;
267 }
268
269 return FWK_SUCCESS;
270 }
271
mod_debug_dev_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)272 static int mod_debug_dev_init(
273 fwk_id_t element_id,
274 unsigned int sub_element_count,
275 const void *data)
276 {
277 struct debug_dev_ctx *ctx;
278 struct mod_debug_dev_config *config;
279
280 ctx = &ctx_table[fwk_id_get_element_idx(element_id)];
281 config = (struct mod_debug_dev_config*)data;
282
283 fwk_assert(config != NULL);
284 ctx->config = config;
285
286 return FWK_SUCCESS;
287 }
288
mod_debug_bind(fwk_id_t id,unsigned int round)289 static int mod_debug_bind(fwk_id_t id, unsigned int round)
290 {
291 int status;
292 struct mod_debug_driver_api *driver_api = NULL;
293 struct debug_dev_ctx *ctx;
294 struct mod_debug_dev_config *dev_cfg;
295
296 if ((round > 0) || fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
297 return FWK_SUCCESS;
298 }
299
300 ctx = &ctx_table[fwk_id_get_element_idx(id)];
301 dev_cfg = ctx->config;
302
303 /* Bind to debug driver */
304 status = fwk_module_bind(
305 dev_cfg->driver_id,
306 dev_cfg->driver_api_id,
307 &driver_api);
308 if (status != FWK_SUCCESS) {
309 return status;
310 }
311
312 /* Validate driver API */
313 if ((driver_api->set_enabled == NULL) ||
314 (driver_api->get_enabled == NULL)) {
315 return FWK_E_DATA;
316 }
317
318 ctx->driver_api = driver_api;
319
320 return FWK_SUCCESS;
321 }
322
mod_debug_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)323 static int mod_debug_process_bind_request(
324 fwk_id_t source_id,
325 fwk_id_t target_id,
326 fwk_id_t api_id,
327 const void **api)
328 {
329 struct debug_dev_ctx *ctx;
330 unsigned int api_idx;
331
332 api_idx = fwk_id_get_api_idx(api_id);
333
334 /* Only binding to elements is allowed */
335 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
336 return FWK_E_ACCESS;
337 }
338
339 ctx = &ctx_table[fwk_id_get_element_idx(target_id)];
340
341 switch (api_idx) {
342 case MOD_DEBUG_API_IDX_HAL:
343 *api = &debug_api;
344
345 return FWK_SUCCESS;
346
347 case MOD_DEBUG_API_IDX_DRIVER_INPUT:
348 if (fwk_id_is_equal(source_id, ctx->config->driver_id)) {
349 *api = &driver_input_api;
350 }
351
352 return FWK_SUCCESS;
353
354 default:
355 return FWK_E_PARAM;
356 }
357 }
358
respond(const struct fwk_event * event)359 static int respond(const struct fwk_event *event)
360 {
361 int status;
362 struct fwk_event response;
363 struct mod_debug_response_params *resp_params =
364 (struct mod_debug_response_params *)response.params;
365 struct mod_debug_response_params *req_result =
366 (struct mod_debug_response_params *)event->params;
367 struct debug_dev_ctx *ctx =
368 &ctx_table[fwk_id_get_element_idx(event->target_id)];
369
370 ctx->state = DEBUG_IDLE;
371
372 status = fwk_get_delayed_response(event->target_id, ctx->cookie, &response);
373 if (status != FWK_SUCCESS) {
374 return status;
375 }
376
377 resp_params->status = req_result->status;
378 resp_params->enabled = req_result->enabled;
379 return fwk_put_event(&response);
380 }
381
mod_debug_process_event(const struct fwk_event * event,struct fwk_event * resp_event)382 static int mod_debug_process_event(const struct fwk_event *event,
383 struct fwk_event *resp_event)
384 {
385 int status;
386 struct debug_dev_ctx *ctx;
387 struct mod_debug_request_params *req_params;
388 struct mod_debug_response_params *req_result;
389
390 ctx = &ctx_table[fwk_id_get_element_idx(event->target_id)];
391
392 switch (fwk_id_get_event_idx(event->id)) {
393 case MOD_DEBUG_PUBLIC_EVENT_IDX_REQ_ENABLE_GET:
394 case MOD_DEBUG_PUBLIC_EVENT_IDX_REQ_ENABLE_SET:
395 case MOD_DEBUG_EVENT_IDX_REQ_DRV:
396 req_params = (struct mod_debug_request_params *)event->params;
397 ctx->requester = req_params->user_id;
398
399 /* Request from USER_AP we will need to respond */
400 if (resp_event->response_requested) {
401 ctx->cookie = event->cookie;
402 resp_event->is_delayed_response = true;
403 return FWK_SUCCESS;
404 }
405
406 /*
407 * When there is no response requested, we are processing an event
408 * generated by the driver (MOD_DEBUG_EVENT_IDX_REQ_DRV)
409 */
410 status = set_enabled(ctx->config->driver_id, req_params->enable,
411 req_params->user_id);
412 if (status == FWK_PENDING) {
413 break;
414 }
415 if (status != FWK_SUCCESS) {
416 return FWK_E_DEVICE;
417 }
418
419 break;
420
421 case MOD_DEBUG_EVENT_IDX_SET_COMPLETE:
422 req_result = (struct mod_debug_response_params *)event->params;
423
424 if (req_result->status == FWK_SUCCESS) {
425 mark_user(event->target_id, req_result->enabled, ctx->requester);
426 }
427
428 return respond(event);
429
430 case MOD_DEBUG_EVENT_IDX_GET_COMPLETE:
431 return respond(event);
432
433 default:
434 return FWK_E_PARAM;
435
436 }
437
438 return FWK_SUCCESS;
439 }
440
441 const struct fwk_module module_debug = {
442 .api_count = MOD_DEBUG_API_IDX_COUNT,
443 .event_count = MOD_DEBUG_EVENT_COUNT,
444 .type = FWK_MODULE_TYPE_HAL,
445 .init = mod_debug_init,
446 .element_init = mod_debug_dev_init,
447 .bind = mod_debug_bind,
448 .process_bind_request = mod_debug_process_bind_request,
449 .process_event = mod_debug_process_event,
450 };
451