1 /*
2 * Copyright (c) 2022-2023, Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * ARM SiP service shell command 'sip_svc'.
7 */
8
9 #include <zephyr/shell/shell.h>
10 #include <zephyr/sip_svc/sip_svc.h>
11 #include <zephyr/sip_svc/sip_svc_controller.h>
12 #include <stdlib.h>
13 #include <errno.h>
14
15 #define MAX_TIMEOUT_MSECS (1 * 1000UL)
16
17 struct private_data {
18 struct k_sem semaphore;
19 const struct shell *sh;
20 };
21
parse_common_args(const struct shell * sh,char ** argv,void ** ctrl)22 static int parse_common_args(const struct shell *sh, char **argv, void **ctrl)
23 {
24 *ctrl = sip_svc_get_controller(argv[1]);
25
26 if (!*ctrl) {
27 shell_error(sh, "service %s not found", argv[1]);
28 return -ENODEV;
29 }
30
31 struct sip_svc_controller *ct = (struct sip_svc_controller *)(*ctrl);
32
33 if (!ct->init) {
34 shell_error(sh, "ARM SiP services method %s not initialized", argv[1]);
35 return -ENODEV;
36 }
37 return 0;
38 }
39
cmd_reg(const struct shell * sh,size_t argc,char ** argv)40 static int cmd_reg(const struct shell *sh, size_t argc, char **argv)
41 {
42 struct sip_svc_controller *ctrl;
43 uint32_t c_token;
44 int err;
45
46 err = parse_common_args(sh, argv, (void **)&ctrl);
47 if (err < 0) {
48 return err;
49 }
50
51 c_token = sip_svc_register(ctrl, NULL);
52 if (c_token == SIP_SVC_ID_INVALID) {
53 shell_error(sh, "%s: register fail", ctrl->method);
54 err = -1;
55 } else {
56 shell_print(sh, "%s: register success: client token %08x\n", ctrl->method, c_token);
57 err = 0;
58 }
59
60 return err;
61 }
62
cmd_unreg(const struct shell * sh,size_t argc,char ** argv)63 static int cmd_unreg(const struct shell *sh, size_t argc, char **argv)
64 {
65 struct sip_svc_controller *ctrl;
66 uint32_t c_token;
67 int err;
68 char *endptr;
69
70 err = parse_common_args(sh, argv, (void **)&ctrl);
71 if (err < 0) {
72 return err;
73 }
74
75 errno = 0;
76 c_token = strtoul(argv[2], &endptr, 16);
77 if (errno == ERANGE) {
78 shell_error(sh, "Out of range value");
79 return -ERANGE;
80 } else if (errno || endptr == argv[2] || *endptr) {
81 shell_error(sh, "Invalid argument");
82 return -errno;
83 }
84
85 err = sip_svc_unregister(ctrl, (uint32_t)c_token);
86 if (err) {
87 shell_error(sh, "%s: unregister fail (%d): client token %08x", ctrl->method, err,
88 (uint32_t)c_token);
89 } else {
90 shell_print(sh, "%s: unregister success: client token %08x", ctrl->method,
91 (uint32_t)c_token);
92 }
93
94 return err;
95 }
96
cmd_open(const struct shell * sh,size_t argc,char ** argv)97 static int cmd_open(const struct shell *sh, size_t argc, char **argv)
98 {
99 struct sip_svc_controller *ctrl;
100 uint32_t c_token;
101 unsigned long mseconds = 0;
102 int err;
103 char *endptr;
104 k_timeout_t timeout = K_MSEC(MAX_TIMEOUT_MSECS);
105
106 err = parse_common_args(sh, argv, (void **)&ctrl);
107 if (err < 0) {
108 return err;
109 }
110
111 errno = 0;
112 c_token = strtoul(argv[2], &endptr, 16);
113 if (errno == ERANGE) {
114 shell_error(sh, "Out of range value");
115 return -ERANGE;
116 } else if (errno || endptr == argv[2] || *endptr) {
117 shell_error(sh, "Invalid argument");
118 return -errno;
119 }
120
121 if (argc > 3) {
122 errno = 0;
123 mseconds = strtoul(argv[3], &endptr, 10);
124 if (errno == ERANGE) {
125 shell_error(sh, "Out of range value");
126 return -ERANGE;
127 } else if (errno || endptr == argv[3] || *endptr) {
128 shell_error(sh, "Invalid Argument");
129 return -EINVAL;
130 } else if (mseconds <= MAX_TIMEOUT_MSECS) {
131 timeout = K_MSEC(mseconds);
132 } else {
133 timeout = K_MSEC(MAX_TIMEOUT_MSECS);
134 shell_error(sh, "Setting timeout value to %lu milliseconds",
135 MAX_TIMEOUT_MSECS);
136 }
137 }
138
139 err = sip_svc_open(ctrl, (uint32_t)c_token, timeout);
140 if (err) {
141 shell_error(sh, "%s: open fail (%d): client token %08x", ctrl->method, err,
142 (uint32_t)c_token);
143 } else {
144 shell_print(sh, "%s: open success: client token %08x", ctrl->method,
145 (uint32_t)c_token);
146 }
147
148 return err;
149 }
150
cmd_close(const struct shell * sh,size_t argc,char ** argv)151 static int cmd_close(const struct shell *sh, size_t argc, char **argv)
152 {
153 struct sip_svc_controller *ctrl;
154 uint32_t c_token;
155 int err;
156 char *endptr;
157
158 err = parse_common_args(sh, argv, (void **)&ctrl);
159 if (err < 0) {
160 return err;
161 }
162
163 errno = 0;
164 c_token = strtoul(argv[2], &endptr, 16);
165 if (errno == ERANGE) {
166 shell_error(sh, "Out of range value");
167 return -ERANGE;
168 } else if (errno || endptr == argv[2] || *endptr) {
169 shell_error(sh, "Invalid argument");
170 return -errno;
171 }
172
173 err = sip_svc_close(ctrl, (uint32_t)c_token, NULL);
174 if (err) {
175 shell_error(sh, "%s: close fail (%d): client token %08x", ctrl->method, err,
176 (uint32_t)c_token);
177 } else {
178 shell_print(sh, "%s: close success: client token %08x", ctrl->method,
179 (uint32_t)c_token);
180 }
181
182 return err;
183 }
184
cmd_send_callback(uint32_t c_token,struct sip_svc_response * response)185 static void cmd_send_callback(uint32_t c_token, struct sip_svc_response *response)
186 {
187 if (response == NULL) {
188 return;
189 }
190
191 struct private_data *priv = (struct private_data *)response->priv_data;
192 const struct shell *sh = priv->sh;
193
194 shell_print(sh, "\n\rsip_svc send callback response\n");
195 shell_print(sh, "\theader=%08x\n", response->header);
196 shell_print(sh, "\ta0=%016lx\n", response->a0);
197 shell_print(sh, "\ta1=%016lx\n", response->a1);
198 shell_print(sh, "\ta2=%016lx\n", response->a2);
199 shell_print(sh, "\ta3=%016lx\n", response->a3);
200
201 k_sem_give(&(priv->semaphore));
202 }
203
cmd_send(const struct shell * sh,size_t argc,char ** argv)204 static int cmd_send(const struct shell *sh, size_t argc, char **argv)
205 {
206 struct sip_svc_controller *ctrl;
207 uint32_t c_token;
208 int trans_id;
209 struct sip_svc_request request;
210 struct private_data priv;
211 char *endptr;
212 int err;
213
214 err = parse_common_args(sh, argv, (void **)&ctrl);
215 if (err < 0) {
216 return err;
217 }
218
219 errno = 0;
220 c_token = strtoul(argv[2], &endptr, 16);
221 if (errno == ERANGE) {
222 shell_error(sh, "Out of range value");
223 return -ERANGE;
224 } else if (errno || endptr == argv[2] || *endptr) {
225 shell_error(sh, "Invalid argument");
226 return -errno;
227 }
228
229 request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_SYNC, 0);
230
231 request.a0 = strtoul(argv[3], &endptr, 16);
232 if (errno == ERANGE) {
233 shell_error(sh, "Out of range value for a0");
234 return -ERANGE;
235 } else if (errno || endptr == argv[3] || *endptr) {
236 shell_error(sh, "Invalid argument for a0");
237 return -errno;
238 }
239
240 if (argc > 4) {
241 request.a1 = strtoul(argv[4], &endptr, 16);
242 if (errno == ERANGE) {
243 shell_error(sh, "Out of range value for a1");
244 return -ERANGE;
245 } else if (errno || endptr == argv[4] || *endptr) {
246 shell_error(sh, "Invalid argument for a1");
247 return -errno;
248 }
249 }
250
251 if (argc > 5) {
252 request.a2 = strtoul(argv[5], &endptr, 16);
253 if (errno == ERANGE) {
254 shell_error(sh, "Out of range value for a2");
255 return -ERANGE;
256 } else if (errno || endptr == argv[5] || *endptr) {
257 shell_error(sh, "Invalid argument for a2");
258 return -errno;
259 }
260 }
261
262 if (argc > 6) {
263 request.a3 = strtoul(argv[6], &endptr, 16);
264 if (errno == ERANGE) {
265 shell_error(sh, "Out of range value for a3");
266 return -ERANGE;
267 } else if (errno || endptr == argv[6] || *endptr) {
268 shell_error(sh, "Invalid argument for a3");
269 return -errno;
270 }
271 }
272
273 if (argc > 7) {
274 request.a4 = strtoul(argv[7], &endptr, 16);
275 if (errno == ERANGE) {
276 shell_error(sh, "Out of range value for a4");
277 return -ERANGE;
278 } else if (errno || endptr == argv[7] || *endptr) {
279 shell_error(sh, "Invalid argument for a4");
280 return -errno;
281 }
282 }
283
284 if (argc > 8) {
285 request.a5 = strtoul(argv[8], &endptr, 16);
286 if (errno == ERANGE) {
287 shell_error(sh, "Out of range value for a5");
288 return -ERANGE;
289 } else if (errno || endptr == argv[8] || *endptr) {
290 shell_error(sh, "Invalid argument for a5");
291 return -errno;
292 }
293 }
294
295 if (argc > 9) {
296 request.a6 = strtoul(argv[9], &endptr, 16);
297 if (errno == ERANGE) {
298 shell_error(sh, "Out of range value for a6");
299 return -ERANGE;
300 } else if (errno || endptr == argv[9] || *endptr) {
301 shell_error(sh, "Invalid argument for a6");
302 return -errno;
303 }
304 }
305
306 if (argc > 10) {
307 request.a7 = strtoul(argv[10], &endptr, 16);
308 if (errno == ERANGE) {
309 shell_error(sh, "Out of range value for a7");
310 return -ERANGE;
311 } else if (errno || endptr == argv[10] || *endptr) {
312 shell_error(sh, "Invalid argument for a7");
313 return -errno;
314 }
315 }
316
317 k_sem_init(&(priv.semaphore), 0, 1);
318 priv.sh = sh;
319
320 request.resp_data_addr = 0;
321 request.resp_data_size = 0;
322 request.priv_data = (void *)&priv;
323
324 trans_id = sip_svc_send(ctrl, (uint32_t)c_token, &request, cmd_send_callback);
325
326 if (trans_id < 0) {
327 shell_error(sh, "%s: send fail: client token %08x", ctrl->method,
328 (uint32_t)c_token);
329 err = trans_id;
330 } else {
331 /*wait for callback*/
332 k_sem_take(&(priv.semaphore), K_FOREVER);
333
334 shell_print(sh, "%s: send success: client token %08x, trans_id %d", ctrl->method,
335 (uint32_t)c_token, trans_id);
336 err = 0;
337 }
338 return err;
339 }
340
cmd_info(const struct shell * sh,size_t argc,char ** argv)341 static int cmd_info(const struct shell *sh, size_t argc, char **argv)
342 {
343 struct sip_svc_controller *ctrl;
344 int err;
345 uint32_t i;
346 static const char *const state_str_list[] = {"INVALID", "IDLE", "OPEN", "ABORT"};
347 const char *state_str = "UNKNOWN";
348
349 err = parse_common_args(sh, argv, (void **)&ctrl);
350 if (err < 0) {
351 return err;
352 }
353
354 shell_print(sh, "---------------------------------------\n");
355 shell_print(sh, "sip_svc service information\n");
356 shell_print(sh, "---------------------------------------\n");
357
358 shell_print(sh, "active job cnt %d\n", ctrl->active_job_cnt);
359 shell_print(sh, "active async job cnt %d\n", ctrl->active_async_job_cnt);
360
361 shell_print(sh, "---------------------------------------\n");
362 shell_print(sh, "Client Token\tState\tTrans Cnt\n");
363 shell_print(sh, "---------------------------------------\n");
364 for (i = 0; i < ctrl->num_clients; i++) {
365 if (ctrl->clients[i].id != SIP_SVC_ID_INVALID) {
366 if (ctrl->clients[i].state <= SIP_SVC_CLIENT_ST_ABORT) {
367 state_str = state_str_list[ctrl->clients[i].state];
368 }
369
370 shell_print(sh, "%08x \t%-10s\t%-9d\n", ctrl->clients[i].token,
371 state_str, ctrl->clients[i].active_trans_cnt);
372 }
373 }
374 return err;
375 }
376
377 SHELL_STATIC_SUBCMD_SET_CREATE(
378 sub_sip_svc, SHELL_CMD_ARG(reg, NULL, "<method>", cmd_reg, 2, 0),
379 SHELL_CMD_ARG(unreg, NULL, "<method> <token>", cmd_unreg, 3, 0),
380 SHELL_CMD_ARG(open, NULL, "<method> <token> <[timeout_msec]>", cmd_open, 3, 1),
381 SHELL_CMD_ARG(close, NULL, "<method> <token>", cmd_close, 3, 0),
382 SHELL_CMD_ARG(send, NULL, "<method> <token> <a0> [<a1> <a2> ... <a7>]", cmd_send, 4, 7),
383 SHELL_CMD_ARG(info, NULL, "<method>", cmd_info, 2, 0), SHELL_SUBCMD_SET_END);
384
385 SHELL_CMD_REGISTER(sip_svc, &sub_sip_svc, "ARM SiP services commands", NULL);
386