common/mctp/mctp_ctrl.c (185 lines of code) (raw):

#include "mctp.h" #include "mctp_ctrl.h" #include <logging/log.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/printk.h> #include <zephyr.h> LOG_MODULE_DECLARE(mctp); #define DEFAULT_WAIT_TO_MS 3000 #define RESP_MSG_PROC_MUTEX_WAIT_TO_MS 1000 #define TO_CHK_INTERVAL_MS 1000 #define MCTP_CTRL_INST_ID_MASK 0x3F typedef struct _wait_msg { sys_snode_t node; mctp *mctp_inst; int64_t exp_to_ms; mctp_ctrl_msg msg; } wait_msg; static K_MUTEX_DEFINE(wait_recv_resp_mutex); static sys_slist_t wait_recv_resp_list = SYS_SLIST_STATIC_INIT(&wait_recv_resp_list); uint8_t mctp_ctrl_cmd_get_endpoint_id(void *mctp_inst, uint8_t *buf, uint16_t len, uint8_t *resp, uint16_t *resp_len, void *ext_params) { if (!mctp_inst || !buf || !resp || !resp_len) return MCTP_ERROR; struct _get_eid_resp *p = (struct _get_eid_resp *)resp; p->eid = MCTP_DEFAULT_ENDPOINT; p->eid_type = STATIC_EID; p->endpoint_type = BRIDGE; /* Not support fairness arbitration */ p->medium_specific_info = 0x00; p->completion_code = (len != 0) ? MCTP_CTRL_CC_ERROR_INVALID_LENGTH : MCTP_CTRL_CC_SUCCESS; *resp_len = (p->completion_code == MCTP_CTRL_CC_SUCCESS) ? sizeof(*p) : 1; return MCTP_SUCCESS; } static uint8_t mctp_ctrl_msg_timeout_check(sys_slist_t *list, struct k_mutex *mutex) { if (!list || !mutex) return MCTP_ERROR; if (k_mutex_lock(mutex, K_MSEC(RESP_MSG_PROC_MUTEX_WAIT_TO_MS))) { LOG_WRN("pldm mutex is locked over %d ms!!", RESP_MSG_PROC_MUTEX_WAIT_TO_MS); return MCTP_ERROR; } sys_snode_t *node; sys_snode_t *s_node; sys_snode_t *pre_node = NULL; int64_t cur_uptime = k_uptime_get(); SYS_SLIST_FOR_EACH_NODE_SAFE (list, node, s_node) { wait_msg *p = (wait_msg *)node; if ((p->exp_to_ms <= cur_uptime)) { printk("mctp ctrl msg timeout!!\n"); printk("cmd %x, inst_id %x\n", p->msg.hdr.cmd, p->msg.hdr.inst_id); sys_slist_remove(list, pre_node, node); if (p->msg.timeout_cb_fn) p->msg.timeout_cb_fn(p->msg.timeout_cb_fn_args); free(p); } else { pre_node = node; } } k_mutex_unlock(mutex); return MCTP_SUCCESS; } static void mctp_ctrl_msg_timeout_monitor(void *dummy0, void *dummy1, void *dummy2) { ARG_UNUSED(dummy0); ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); while (1) { k_msleep(TO_CHK_INTERVAL_MS); mctp_ctrl_msg_timeout_check(&wait_recv_resp_list, &wait_recv_resp_mutex); } } static uint8_t mctp_ctrl_cmd_resp_process(mctp *mctp_inst, uint8_t *buf, uint32_t len, mctp_ext_params ext_params) { if (!mctp_inst || !buf || !len) return MCTP_ERROR; if (k_mutex_lock(&wait_recv_resp_mutex, K_MSEC(RESP_MSG_PROC_MUTEX_WAIT_TO_MS))) { LOG_WRN("mutex is locked over %d ms!", RESP_MSG_PROC_MUTEX_WAIT_TO_MS); return MCTP_ERROR; } mctp_ctrl_hdr *hdr = (mctp_ctrl_hdr *)buf; sys_snode_t *node; sys_snode_t *s_node; sys_snode_t *pre_node = NULL; sys_snode_t *found_node = NULL; SYS_SLIST_FOR_EACH_NODE_SAFE (&wait_recv_resp_list, node, s_node) { wait_msg *p = (wait_msg *)node; /* found the proper handler */ if ((p->msg.hdr.inst_id == hdr->inst_id) && (p->mctp_inst == mctp_inst) && (p->msg.hdr.cmd == hdr->cmd)) { found_node = node; sys_slist_remove(&wait_recv_resp_list, pre_node, node); break; } else { pre_node = node; } } k_mutex_unlock(&wait_recv_resp_mutex); if (found_node) { /* invoke resp handler */ wait_msg *p = (wait_msg *)found_node; if (p->msg.recv_resp_cb_fn) p->msg.recv_resp_cb_fn( p->msg.recv_resp_cb_args, buf + sizeof(p->msg.hdr), len - sizeof(p->msg.hdr)); /* remove mctp ctrl header for handler */ free(p); } return MCTP_SUCCESS; } static mctp_ctrl_cmd_handler_t mctp_ctrl_cmd_tbl[] = { { MCTP_CTRL_CMD_GET_ENDPOINT_ID, mctp_ctrl_cmd_get_endpoint_id }, }; uint8_t mctp_ctrl_cmd_handler(void *mctp_p, uint8_t *buf, uint32_t len, mctp_ext_params ext_params) { if (!mctp_p || !buf || !len) return MCTP_ERROR; mctp *mctp_inst = (mctp *)mctp_p; mctp_ctrl_hdr *hdr = (mctp_ctrl_hdr *)buf; /* * The message is a response, check if any callback function should be * invoked */ if (!hdr->rq) return mctp_ctrl_cmd_resp_process(mctp_inst, buf, len, ext_params); /* The message is a request, find the proper handler to handle it */ /* Initial response data */ uint8_t resp_buf[MCTP_BASE_LINE_UNIT] = { 0 }; /* * Default without header length, the header length will be added before * sending */ uint16_t resp_len = 1; /* Make response header */ hdr->rq = 0; memcpy(resp_buf, hdr, sizeof(*hdr)); /* Default one byte response data - completion code */ uint8_t *comp_code = resp_buf + sizeof(*hdr); mctp_ctrl_cmd_fn cmd_func = NULL; for (uint8_t i = 0; i < ARRAY_SIZE(mctp_ctrl_cmd_tbl); i++) { if (hdr->cmd == mctp_ctrl_cmd_tbl[i].cmd_code) { cmd_func = mctp_ctrl_cmd_tbl[i].fn; break; } } if (!cmd_func) { *comp_code = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD; goto send_msg; } uint8_t rc = MCTP_ERROR; rc = cmd_func(mctp_inst, buf + sizeof(*hdr), len - sizeof(*hdr), resp_buf + sizeof(*hdr), &resp_len, &ext_params); /* * If return MCTP_ERROR means it has an error in using the function internally * by code, like using a NULL pointer or zero response length by argument. */ if (rc == MCTP_ERROR) *comp_code = MCTP_CTRL_CC_ERROR; send_msg: /* Send the mctp control response data */ resp_len = sizeof(*hdr) + resp_len; return mctp_send_msg(mctp_inst, resp_buf, resp_len, ext_params); } uint8_t mctp_ctrl_send_msg(void *mctp_p, mctp_ctrl_msg *msg) { if (!mctp_p || !msg || !msg->cmd_data) return MCTP_ERROR; mctp *mctp_inst = (mctp *)mctp_p; if (msg->hdr.rq) { static uint8_t inst_id; msg->hdr.inst_id = (inst_id++) & MCTP_CTRL_INST_ID_MASK; msg->hdr.msg_type = MCTP_MSG_TYPE_CTRL; msg->ext_params.tag_owner = 1; } uint16_t len = sizeof(msg->hdr) + msg->cmd_data_len; uint8_t buf[len]; memcpy(buf, &msg->hdr, sizeof(msg->hdr)); memcpy(buf + sizeof(msg->hdr), msg->cmd_data, msg->cmd_data_len); LOG_HEXDUMP_DBG(buf, len, __func__); uint8_t rc = mctp_send_msg(mctp_inst, buf, len, msg->ext_params); if (rc == MCTP_ERROR) { LOG_WRN("mctp_send_msg error!!"); return MCTP_ERROR; } if (msg->hdr.rq) { wait_msg *p = (wait_msg *)malloc(sizeof(*p)); if (!p) { LOG_WRN("wait_msg alloc failed!"); return MCTP_ERROR; } memset(p, 0, sizeof(*p)); p->mctp_inst = mctp_inst; p->msg = *msg; p->exp_to_ms = k_uptime_get() + (msg->timeout_ms ? msg->timeout_ms : DEFAULT_WAIT_TO_MS); k_mutex_lock(&wait_recv_resp_mutex, K_FOREVER); sys_slist_append(&wait_recv_resp_list, &p->node); k_mutex_unlock(&wait_recv_resp_mutex); } return MCTP_SUCCESS; } K_THREAD_DEFINE(monitor_tid, 1024, mctp_ctrl_msg_timeout_monitor, NULL, NULL, NULL, 7, 0, 0);