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

#include "pldm.h" #include "mctp.h" #include <logging/log.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/printk.h> #include <sys/slist.h> #include <zephyr.h> LOG_MODULE_REGISTER(pldm); #define PLDM_HDR_INST_ID_MASK 0x1F #define PLDM_MSG_CHECK_PER_MS 1000 #define PLDM_MSG_TIMEOUT_MS 5000 #define PLDM_RESP_MSG_PROC_MUTEX_TIMEOUT_MS 500 #define PLDM_TASK_NAME_MAX_SIZE 32 typedef struct _wait_msg { sys_snode_t node; mctp *mctp_inst; int64_t exp_to_ms; pldm_msg msg; } wait_msg; struct _pldm_handler_query_entry { PLDM_TYPE type; uint8_t (*handler_query)(uint8_t, void **); }; static struct _pldm_handler_query_entry query_tbl[] = { { PLDM_TYPE_BASE, pldm_base_handler_query }, { PLDM_TYPE_OEM, pldm_oem_handler_query } }; static K_MUTEX_DEFINE(wait_recv_resp_mutex); static sys_slist_t wait_recv_resp_list = SYS_SLIST_STATIC_INIT(&wait_recv_resp_list); static uint8_t pldm_msg_timeout_check(sys_slist_t *list, struct k_mutex *mutex) { if (!list || !mutex) return MCTP_ERROR; if (k_mutex_lock(mutex, K_MSEC(PLDM_RESP_MSG_PROC_MUTEX_TIMEOUT_MS))) { LOG_WRN("pldm mutex is locked over %d ms!!", PLDM_RESP_MSG_PROC_MUTEX_TIMEOUT_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("pldm 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 pldm_msg_timeout_monitor(void *dummy0, void *dummy1, void *dummy2) { ARG_UNUSED(dummy0); ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); while (1) { k_msleep(PLDM_MSG_CHECK_PER_MS); pldm_msg_timeout_check(&wait_recv_resp_list, &wait_recv_resp_mutex); } } static uint8_t pldm_resp_msg_process(mctp *mctp_inst, uint8_t *buf, uint32_t len, mctp_ext_params ext_params) { if (!mctp_inst || !buf || !len) return PLDM_ERROR; pldm_hdr *hdr = (pldm_hdr *)buf; sys_snode_t *node; sys_snode_t *s_node; sys_snode_t *pre_node = NULL; sys_snode_t *found_node = NULL; if (k_mutex_lock(&wait_recv_resp_mutex, K_MSEC(PLDM_RESP_MSG_PROC_MUTEX_TIMEOUT_MS))) { LOG_WRN("pldm mutex is locked over %d ms!!", PLDM_RESP_MSG_PROC_MUTEX_TIMEOUT_MS); return PLDM_ERROR; } 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->msg.hdr.pldm_type == hdr->pldm_type) && (p->msg.hdr.cmd == hdr->cmd) && (p->mctp_inst == mctp_inst)) { 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) /* remove pldm header for handler */ p->msg.recv_resp_cb_fn(p->msg.recv_resp_cb_args, buf + sizeof(p->msg.hdr), len - sizeof(p->msg.hdr)); free(p); } return PLDM_SUCCESS; } uint8_t mctp_pldm_cmd_handler(void *mctp_p, uint8_t *buf, uint32_t len, mctp_ext_params ext_params) { if (!mctp_p || !buf || !len) return PLDM_ERROR; mctp *mctp_inst = (mctp *)mctp_p; pldm_hdr *hdr = (pldm_hdr *)buf; LOG_DBG("msg_type = %d", hdr->msg_type); LOG_DBG("req_d_id = 0x%x", hdr->req_d_id); LOG_DBG("pldm_type = 0x%x", hdr->pldm_type); LOG_DBG("cmd = 0x%x", hdr->cmd); /* * The message is a response, check if any callback function should be * invoked */ if (!hdr->rq) return pldm_resp_msg_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[PLDM_MAX_DATA_SIZE] = { 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 = resp_buf + sizeof(*hdr); pldm_cmd_proc_fn handler = NULL; uint8_t (*handler_query)(uint8_t, void **) = NULL; uint8_t i; for (i = 0; i < ARRAY_SIZE(query_tbl); i++) { if (hdr->pldm_type == query_tbl[i].type) { handler_query = query_tbl[i].handler_query; break; } } if (!handler_query) { *comp = PLDM_BASE_CODES_ERROR_UNSUPPORT_PLDM_TYPE; goto send_msg; } uint8_t rc = PLDM_ERROR; /* found the proper cmd handler in the pldm_type_cmd table */ rc = handler_query(hdr->cmd, (void **)&handler); if (rc == PLDM_ERROR || !handler) { *comp = PLDM_BASE_CODES_ERROR_UNSUPPORT_PLDM_CMD; goto send_msg; } /* invoke the cmd handler to process */ rc = handler(mctp_inst, buf + sizeof(*hdr), len - sizeof(*hdr), resp_buf + sizeof(*hdr), &resp_len, &ext_params); if (rc == PLDM_LATER_RESP) return PLDM_SUCCESS; send_msg: /* send the pldm response data */ resp_len = sizeof(*hdr) + resp_len; return mctp_send_msg(mctp_inst, resp_buf, resp_len, ext_params); } uint8_t mctp_pldm_send_msg(void *mctp_p, pldm_msg *msg) { if (!mctp_p || !msg) return PLDM_ERROR; mctp *mctp_inst = (mctp *)mctp_p; /* * The request should be set inst_id/msg_type/mctp_tag_owner in the * header */ if (msg->hdr.rq) { /* set pldm header */ msg->hdr.inst_id = (mctp_inst->pldm_inst_id++) & PLDM_HDR_INST_ID_MASK; msg->hdr.msg_type = MCTP_MSG_TYPE_PLDM; /* set mctp extra parameters */ msg->ext_params.tag_owner = 1; } uint16_t len = sizeof(msg->hdr) + msg->len; uint8_t buf[len]; memcpy(buf, &msg->hdr, sizeof(msg->hdr)); memcpy(buf + sizeof(msg->hdr), msg->buf, msg->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 PLDM_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 : PLDM_MSG_TIMEOUT_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 PLDM_SUCCESS; } K_THREAD_DEFINE(pldm_wait_resp_to, 1024, pldm_msg_timeout_monitor, NULL, NULL, NULL, 7, 0, 0);