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