blob: c0d64495206ef56cbf4621cc3758d4078a29d71a [file] [log] [blame]
/*
* Copyright (c) 2022-2023, Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*
* ARM SiP service shell command 'sip_svc'.
*/
#include <zephyr/shell/shell.h>
#include <zephyr/sip_svc/sip_svc.h>
#include <zephyr/sip_svc/sip_svc_controller.h>
#include <stdlib.h>
#include <errno.h>
#define MAX_TIMEOUT_MSECS (1 * 1000UL)
struct private_data {
struct k_sem semaphore;
const struct shell *sh;
};
static int parse_common_args(const struct shell *sh, char **argv, void **ctrl)
{
*ctrl = sip_svc_get_controller(argv[1]);
if (!*ctrl) {
shell_error(sh, "service %s not found", argv[1]);
return -ENODEV;
}
struct sip_svc_controller *ct = (struct sip_svc_controller *)(*ctrl);
if (!ct->init) {
shell_error(sh, "ARM SiP services method %s not initialized", argv[1]);
return -ENODEV;
}
return 0;
}
static int cmd_reg(const struct shell *sh, size_t argc, char **argv)
{
struct sip_svc_controller *ctrl;
uint32_t c_token;
int err;
err = parse_common_args(sh, argv, (void **)&ctrl);
if (err < 0) {
return err;
}
c_token = sip_svc_register(ctrl, NULL);
if (c_token == SIP_SVC_ID_INVALID) {
shell_error(sh, "%s: register fail", ctrl->method);
err = -1;
} else {
shell_print(sh, "%s: register success: client token %08x\n", ctrl->method, c_token);
err = 0;
}
return err;
}
static int cmd_unreg(const struct shell *sh, size_t argc, char **argv)
{
struct sip_svc_controller *ctrl;
uint32_t c_token;
int err;
char *endptr;
err = parse_common_args(sh, argv, (void **)&ctrl);
if (err < 0) {
return err;
}
errno = 0;
c_token = strtoul(argv[2], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value");
return -ERANGE;
} else if (errno || endptr == argv[2] || *endptr) {
shell_error(sh, "Invalid argument");
return -errno;
}
err = sip_svc_unregister(ctrl, (uint32_t)c_token);
if (err) {
shell_error(sh, "%s: unregister fail (%d): client token %08x", ctrl->method, err,
(uint32_t)c_token);
} else {
shell_print(sh, "%s: unregister success: client token %08x", ctrl->method,
(uint32_t)c_token);
}
return err;
}
static int cmd_open(const struct shell *sh, size_t argc, char **argv)
{
struct sip_svc_controller *ctrl;
uint32_t c_token;
unsigned long mseconds = 0;
int err;
char *endptr;
k_timeout_t timeout = K_MSEC(MAX_TIMEOUT_MSECS);
err = parse_common_args(sh, argv, (void **)&ctrl);
if (err < 0) {
return err;
}
errno = 0;
c_token = strtoul(argv[2], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value");
return -ERANGE;
} else if (errno || endptr == argv[2] || *endptr) {
shell_error(sh, "Invalid argument");
return -errno;
}
if (argc > 3) {
errno = 0;
mseconds = strtoul(argv[3], &endptr, 10);
if (errno == ERANGE) {
shell_error(sh, "Out of range value");
return -ERANGE;
} else if (errno || endptr == argv[3] || *endptr) {
shell_error(sh, "Invalid Argument");
return -EINVAL;
} else if (mseconds <= MAX_TIMEOUT_MSECS) {
timeout = K_MSEC(mseconds);
} else {
timeout = K_MSEC(MAX_TIMEOUT_MSECS);
shell_error(sh, "Setting timeout value to %lu milliseconds",
MAX_TIMEOUT_MSECS);
}
}
err = sip_svc_open(ctrl, (uint32_t)c_token, timeout);
if (err) {
shell_error(sh, "%s: open fail (%d): client token %08x", ctrl->method, err,
(uint32_t)c_token);
} else {
shell_print(sh, "%s: open success: client token %08x", ctrl->method,
(uint32_t)c_token);
}
return err;
}
static int cmd_close(const struct shell *sh, size_t argc, char **argv)
{
struct sip_svc_controller *ctrl;
uint32_t c_token;
int err;
char *endptr;
err = parse_common_args(sh, argv, (void **)&ctrl);
if (err < 0) {
return err;
}
errno = 0;
c_token = strtoul(argv[2], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value");
return -ERANGE;
} else if (errno || endptr == argv[2] || *endptr) {
shell_error(sh, "Invalid argument");
return -errno;
}
err = sip_svc_close(ctrl, (uint32_t)c_token, NULL);
if (err) {
shell_error(sh, "%s: close fail (%d): client token %08x", ctrl->method, err,
(uint32_t)c_token);
} else {
shell_print(sh, "%s: close success: client token %08x", ctrl->method,
(uint32_t)c_token);
}
return err;
}
static void cmd_send_callback(uint32_t c_token, struct sip_svc_response *response)
{
if (response == NULL) {
return;
}
struct private_data *priv = (struct private_data *)response->priv_data;
const struct shell *sh = priv->sh;
shell_print(sh, "\n\rsip_svc send callback response\n");
shell_print(sh, "\theader=%08x\n", response->header);
shell_print(sh, "\ta0=%016lx\n", response->a0);
shell_print(sh, "\ta1=%016lx\n", response->a1);
shell_print(sh, "\ta2=%016lx\n", response->a2);
shell_print(sh, "\ta3=%016lx\n", response->a3);
k_sem_give(&(priv->semaphore));
}
static int cmd_send(const struct shell *sh, size_t argc, char **argv)
{
struct sip_svc_controller *ctrl;
uint32_t c_token;
int trans_id;
struct sip_svc_request request;
struct private_data priv;
char *endptr;
int err;
err = parse_common_args(sh, argv, (void **)&ctrl);
if (err < 0) {
return err;
}
errno = 0;
c_token = strtoul(argv[2], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value");
return -ERANGE;
} else if (errno || endptr == argv[2] || *endptr) {
shell_error(sh, "Invalid argument");
return -errno;
}
request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_SYNC, 0);
request.a0 = strtoul(argv[3], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a0");
return -ERANGE;
} else if (errno || endptr == argv[3] || *endptr) {
shell_error(sh, "Invalid argument for a0");
return -errno;
}
if (argc > 4) {
request.a1 = strtoul(argv[4], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a1");
return -ERANGE;
} else if (errno || endptr == argv[4] || *endptr) {
shell_error(sh, "Invalid argument for a1");
return -errno;
}
}
if (argc > 5) {
request.a2 = strtoul(argv[5], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a2");
return -ERANGE;
} else if (errno || endptr == argv[5] || *endptr) {
shell_error(sh, "Invalid argument for a2");
return -errno;
}
}
if (argc > 6) {
request.a3 = strtoul(argv[6], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a3");
return -ERANGE;
} else if (errno || endptr == argv[6] || *endptr) {
shell_error(sh, "Invalid argument for a3");
return -errno;
}
}
if (argc > 7) {
request.a4 = strtoul(argv[7], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a4");
return -ERANGE;
} else if (errno || endptr == argv[7] || *endptr) {
shell_error(sh, "Invalid argument for a4");
return -errno;
}
}
if (argc > 8) {
request.a5 = strtoul(argv[8], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a5");
return -ERANGE;
} else if (errno || endptr == argv[8] || *endptr) {
shell_error(sh, "Invalid argument for a5");
return -errno;
}
}
if (argc > 9) {
request.a6 = strtoul(argv[9], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a6");
return -ERANGE;
} else if (errno || endptr == argv[9] || *endptr) {
shell_error(sh, "Invalid argument for a6");
return -errno;
}
}
if (argc > 10) {
request.a7 = strtoul(argv[10], &endptr, 16);
if (errno == ERANGE) {
shell_error(sh, "Out of range value for a7");
return -ERANGE;
} else if (errno || endptr == argv[10] || *endptr) {
shell_error(sh, "Invalid argument for a7");
return -errno;
}
}
k_sem_init(&(priv.semaphore), 0, 1);
priv.sh = sh;
request.resp_data_addr = 0;
request.resp_data_size = 0;
request.priv_data = (void *)&priv;
trans_id = sip_svc_send(ctrl, (uint32_t)c_token, &request, cmd_send_callback);
if (trans_id < 0) {
shell_error(sh, "%s: send fail: client token %08x", ctrl->method,
(uint32_t)c_token);
err = trans_id;
} else {
/*wait for callback*/
k_sem_take(&(priv.semaphore), K_FOREVER);
shell_print(sh, "%s: send success: client token %08x, trans_id %d", ctrl->method,
(uint32_t)c_token, trans_id);
err = 0;
}
return err;
}
static int cmd_info(const struct shell *sh, size_t argc, char **argv)
{
struct sip_svc_controller *ctrl;
int err;
uint32_t i;
static const char *const state_str_list[] = {"INVALID", "IDLE", "OPEN", "ABORT"};
const char *state_str = "UNKNOWN";
err = parse_common_args(sh, argv, (void **)&ctrl);
if (err < 0) {
return err;
}
shell_print(sh, "---------------------------------------\n");
shell_print(sh, "sip_svc service information\n");
shell_print(sh, "---------------------------------------\n");
shell_print(sh, "active job cnt %d\n", ctrl->active_job_cnt);
shell_print(sh, "active async job cnt %d\n", ctrl->active_async_job_cnt);
shell_print(sh, "---------------------------------------\n");
shell_print(sh, "Client Token\tState\tTrans Cnt\n");
shell_print(sh, "---------------------------------------\n");
for (i = 0; i < ctrl->num_clients; i++) {
if (ctrl->clients[i].id != SIP_SVC_ID_INVALID) {
if (ctrl->clients[i].state <= SIP_SVC_CLIENT_ST_ABORT) {
state_str = state_str_list[ctrl->clients[i].state];
}
shell_print(sh, "%08x \t%-10s\t%-9d\n", ctrl->clients[i].token,
state_str, ctrl->clients[i].active_trans_cnt);
}
}
return err;
}
SHELL_STATIC_SUBCMD_SET_CREATE(
sub_sip_svc, SHELL_CMD_ARG(reg, NULL, "<method>", cmd_reg, 2, 0),
SHELL_CMD_ARG(unreg, NULL, "<method> <token>", cmd_unreg, 3, 0),
SHELL_CMD_ARG(open, NULL, "<method> <token> <[timeout_msec]>", cmd_open, 3, 1),
SHELL_CMD_ARG(close, NULL, "<method> <token>", cmd_close, 3, 0),
SHELL_CMD_ARG(send, NULL, "<method> <token> <a0> [<a1> <a2> ... <a7>]", cmd_send, 4, 7),
SHELL_CMD_ARG(info, NULL, "<method>", cmd_info, 2, 0), SHELL_SUBCMD_SET_END);
SHELL_CMD_REGISTER(sip_svc, &sub_sip_svc, "ARM SiP services commands", NULL);