diff --git a/common/service/cci/cci.c b/common/service/cci/cci.c new file mode 100644 index 0000000000..4941349c46 --- /dev/null +++ b/common/service/cci/cci.c @@ -0,0 +1,310 @@ +#include "cci.h" +#include "mctp.h" +#include +#include +#include +#include +#include +#include +#include +#include "libutil.h" +#include "sensor.h" +#include "plat_def.h" + +#ifdef ENABLE_CCI + +LOG_MODULE_REGISTER(cci); + +#define DEFAULT_WAIT_TO_MS 3000 +#define RESP_MSG_PROC_MUTEX_WAIT_TO_MS 1000 +#define TO_CHK_INTERVAL_MS 1000 +#define CCI_MSG_MAX_RETRY 3 +#define CCI_MSG_TIMEOUT_MS 3000 +#define CCI_READ_EVENT_SUCCESS BIT(0) +#define CCI_READ_EVENT_TIMEOUT BIT(1) + +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 mctp_cci_msg_timeout_check(sys_slist_t *list, struct k_mutex *mutex) +{ + CHECK_NULL_ARG_WITH_RETURN(list, MCTP_ERROR); + CHECK_NULL_ARG_WITH_RETURN(mutex, MCTP_ERROR); + + if (k_mutex_lock(mutex, K_MSEC(RESP_MSG_PROC_MUTEX_WAIT_TO_MS))) { + LOG_WRN("cci 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 cci msg timeout!!\n"); + sys_slist_remove(list, pre_node, node); + + if (p->msg.timeout_cb_fn) + p->msg.timeout_cb_fn(p->msg.timeout_cb_fn_args); + + SAFE_FREE(p); + } else { + pre_node = node; + } + } + + k_mutex_unlock(mutex); + return MCTP_SUCCESS; +} + +static void mctp_cci_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_cci_msg_timeout_check(&wait_recv_resp_list, &wait_recv_resp_mutex); + } +} + +static void cci_read_timeout_handler(void *args) +{ + CHECK_NULL_ARG(args); + struct k_msgq *msgq = (struct k_msgq *)args; + uint8_t status = CCI_READ_EVENT_TIMEOUT; + k_msgq_put(msgq, &status, K_NO_WAIT); +} + +static uint8_t mctp_cci_cmd_resp_process(mctp *mctp_inst, uint8_t *buf, uint32_t len, + mctp_ext_params ext_params) +{ + CHECK_NULL_ARG_WITH_RETURN(mctp_inst, MCTP_ERROR); + CHECK_NULL_ARG_WITH_RETURN(buf, MCTP_ERROR); + + mctp_cci_hdr *cci_hdr = (mctp_cci_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(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; + } + 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->mctp_inst == mctp_inst) && (p->msg.hdr.msg_tag == cci_hdr->msg_tag) && + (p->msg.hdr.op == cci_hdr->op)) { + 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), + cci_hdr->ret); /* remove mctp cci header for handler */ + SAFE_FREE(p); + } + + return MCTP_SUCCESS; +} + +uint8_t mctp_cci_send_msg(void *mctp_p, mctp_cci_msg *msg) +{ + CHECK_NULL_ARG_WITH_RETURN(mctp_p, CCI_ERROR); + CHECK_NULL_ARG_WITH_RETURN(msg, CCI_ERROR); + + mctp *mctp_inst = (mctp *)mctp_p; + + if (!msg->hdr.cci_msg_req_resp) { + msg->hdr.msg_tag = mctp_inst->cci_msg_tag++; + msg->hdr.msg_type = MCTP_MSG_TYPE_CCI; + msg->ext_params.tag_owner = 1; + } + + uint16_t len = sizeof(msg->hdr) + msg->hdr.pl_len; + uint8_t buf[len]; + + memcpy(buf, &msg->hdr, sizeof(msg->hdr)); + if (msg->hdr.pl_len) { + memcpy(buf + sizeof(msg->hdr), msg->pl_data, msg->hdr.pl_len); + } + LOG_HEXDUMP_DBG(buf, len, __func__); + + uint8_t rc = mctp_send_msg(mctp_inst, buf, len, msg->ext_params); + + if (rc == CCI_ERROR) { + LOG_WRN("mctp_send_msg error!!"); + return CCI_ERROR; + } + if (!msg->hdr.cci_msg_req_resp) { + wait_msg *p = (wait_msg *)malloc(sizeof(*p)); + if (!p) { + LOG_WRN("wait_msg alloc failed!"); + return CCI_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 CCI_SUCCESS; +} + +void cci_read_resp_handler(void *args, uint8_t *rbuf, uint16_t rlen, uint16_t ret_code) +{ + CHECK_NULL_ARG(args); + CHECK_NULL_ARG(rbuf); + uint8_t status = 0; + cci_recv_resp_arg *recv_arg = (cci_recv_resp_arg *)args; + + if (rlen > recv_arg->rbuf_len) { + LOG_WRN("[%s] response length(%d) is greater than buffer length(%d)!", __func__, + rlen, recv_arg->rbuf_len); + recv_arg->return_len = recv_arg->rbuf_len; + } else { + recv_arg->return_len = rlen; + } + memcpy(recv_arg->rbuf, rbuf, recv_arg->return_len); + if (ret_code == CCI_CC_SUCCESS) { + status = CCI_READ_EVENT_SUCCESS; + } else { + LOG_ERR("[%s] Return code status(0x%04x)!\n", __func__, ret_code); + } + k_msgq_put(recv_arg->msgq, &status, K_NO_WAIT); +} + +uint16_t mctp_cci_read(void *mctp_p, mctp_cci_msg *msg, uint8_t *rbuf, uint16_t rbuf_len) +{ + CHECK_NULL_ARG_WITH_RETURN(mctp_p, 0); + CHECK_NULL_ARG_WITH_RETURN(msg, 0); + CHECK_NULL_ARG_WITH_RETURN(rbuf, 0); + + uint8_t event_msgq_buffer[1]; + struct k_msgq *event_msgq_p = (struct k_msgq *)malloc(sizeof(struct k_msgq)); + if (!event_msgq_p) { + LOG_WRN("event_msgq_p alloc failed!"); + return CCI_ERROR; + } + uint16_t ret_len = 0; + + k_msgq_init(event_msgq_p, event_msgq_buffer, sizeof(uint8_t), 1); + + cci_recv_resp_arg *recv_arg_p = (cci_recv_resp_arg *)malloc(sizeof(cci_recv_resp_arg)); + if (!recv_arg_p) { + SAFE_FREE(event_msgq_p); + LOG_WRN("recv_arg_p alloc failed!"); + return CCI_ERROR; + } + recv_arg_p->msgq = event_msgq_p; + recv_arg_p->rbuf = rbuf; + recv_arg_p->rbuf_len = rbuf_len; + recv_arg_p->return_len = 0; + + msg->recv_resp_cb_fn = cci_read_resp_handler; + msg->recv_resp_cb_args = (void *)recv_arg_p; + msg->timeout_cb_fn = cci_read_timeout_handler; + msg->timeout_cb_fn_args = (void *)event_msgq_p; + msg->timeout_ms = CCI_MSG_TIMEOUT_MS; + + for (uint8_t retry_count = 0; retry_count < CCI_MSG_MAX_RETRY; retry_count++) { + uint8_t event = 0; + if (mctp_cci_send_msg(mctp_p, msg) == CCI_ERROR) { + LOG_WRN("[%s] send msg failed!", __func__); + continue; + } + if (k_msgq_get(event_msgq_p, &event, K_MSEC(CCI_MSG_TIMEOUT_MS + 1000))) { + LOG_WRN("[%s] Failed to get status from msgq!", __func__); + continue; + } + if (event == CCI_READ_EVENT_SUCCESS) { + ret_len = recv_arg_p->return_len; + SAFE_FREE(recv_arg_p); + SAFE_FREE(event_msgq_p); + return ret_len; + } + } + SAFE_FREE(recv_arg_p); + SAFE_FREE(event_msgq_p); + LOG_WRN("[%s] retry reach max!", __func__); + return 0; +} + +uint8_t mctp_cci_cmd_handler(void *mctp_p, uint8_t *buf, uint32_t len, mctp_ext_params ext_params) +{ + CHECK_NULL_ARG_WITH_RETURN(mctp_p, MCTP_ERROR); + CHECK_NULL_ARG_WITH_RETURN(buf, MCTP_ERROR); + + mctp *mctp_inst = (mctp *)mctp_p; + mctp_cci_hdr *cci_hdr = (mctp_cci_hdr *)buf; + + uint8_t mctp_msg_type = cci_hdr->msg_type; + uint8_t cci_msg_resp = cci_hdr->cci_msg_req_resp; + + if (mctp_msg_type != MCTP_MSG_TYPE_CCI) { + return CCI_INVALID_TYPE; + } + + if (cci_msg_resp) { + mctp_cci_cmd_resp_process(mctp_inst, buf, len, ext_params); + return CCI_CC_SUCCESS; + } + + /*TODO : request handler*/ + + return CCI_CC_SUCCESS; +} + +bool cci_get_chip_temp(void *mctp_p, mctp_ext_params ext_params, int16_t *chip_temp) +{ + CHECK_NULL_ARG_WITH_RETURN(mctp_p, false); + CHECK_NULL_ARG_WITH_RETURN(chip_temp, false); + + mctp_cci_msg msg = { 0 }; + memcpy(&msg.ext_params, &ext_params, sizeof(msg.ext_params)); + + msg.hdr.op = CCI_GET_HEALTH_INFO; + msg.hdr.pl_len = HEALTH_INFO_REQ_PL_LEN; + + int resp_len = sizeof(cci_health_info_resp); + uint8_t rbuf[resp_len]; + + if (mctp_cci_read(mctp_p, &msg, rbuf, resp_len) != resp_len) { + LOG_ERR("[%s] mctp_cci_read fail", __func__); + return false; + } + + cci_health_info_resp *resp_p = (cci_health_info_resp *)rbuf; + *chip_temp = resp_p->dev_temp; + + return true; +} + +K_THREAD_DEFINE(monitor_cci_msg, 1024, mctp_cci_msg_timeout_monitor, NULL, NULL, NULL, 7, 0, 0); + +#endif \ No newline at end of file diff --git a/common/service/cci/cci.h b/common/service/cci/cci.h new file mode 100644 index 0000000000..9b0930b513 --- /dev/null +++ b/common/service/cci/cci.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CCI_H +#define _CCI_H +#include "mctp.h" + +typedef enum { + CCI_GET_HEALTH_INFO = 0x4200, + CCI_GET_FW_INFO = 0x0200, +} CCI_CMD; + +/*CCI Request paypload length */ +#define HEALTH_INFO_REQ_PL_LEN 0 /*Size Bytes*/ +#define GET_FW_INFO_REQ_PL_LEN 0 + +/*CCI Response paypload length */ +#define HEALTH_INFO_RESP_PL_LEN 18 /*Size Bytes*/ +#define GET_FW_INFO_RESP_PL_LEN 80 + +struct _cci_handler_query_entry { + CCI_CMD type; + void (*handler_query)(uint8_t *, uint16_t); +}; + +typedef struct _cci_recv_resp_arg { + struct k_msgq *msgq; + uint8_t *rbuf; + uint16_t rbuf_len; + uint16_t return_len; +} cci_recv_resp_arg; + +typedef struct __attribute__((packed)) { + uint8_t msg_type : 7; + uint8_t ic : 1; + uint8_t cci_msg_req_resp; /* 0h = Request, 1h = Response*/ + uint8_t msg_tag; + uint8_t cci_rsv; + uint16_t op; + int pl_len : 21; + uint8_t rsv : 2; + uint8_t BO : 1; + uint16_t ret; + uint16_t stat; +} mctp_cci_hdr; + +typedef struct { + mctp_cci_hdr hdr; + uint8_t *pl_data; + mctp_ext_params ext_params; + void (*recv_resp_cb_fn)(void *, uint8_t *, uint16_t, uint16_t); + void *recv_resp_cb_args; + uint16_t timeout_ms; + void (*timeout_cb_fn)(void *); + void *timeout_cb_fn_args; +} mctp_cci_msg; + +typedef uint8_t (*mctp_cci_cmd_fn)(void *, uint8_t *, uint16_t, uint8_t *, uint16_t *, void *); +typedef uint8_t (*cci_cmd_proc_fn)(void *, uint8_t *, uint16_t, uint8_t *, uint16_t *, void *); + +typedef struct _mctp_cci_cmd_handler { + uint8_t cmd_code; + mctp_cci_cmd_fn fn; +} mctp_cci_cmd_handler_t; + +#define DEV_TEMP_OFFSET 16 +#define CCI_CC_INVALID_INPUT 0x0002 + +/* + * CCI Return Codes + */ +#define CCI_CC_SUCCESS 0x0000 +#define CCI_CC_INVALID_INPUT 0x0002 +#define CCI_CC_PAYLOAD_INVALID_LEN 0x0016 + +/* + * CCI Return Codes + */ +#define CCI_SUCCESS 0x0000 +#define CCI_ERROR 0x0001 +#define CCI_INVALID_TYPE 0x0002 + +typedef struct _wait_msg { + sys_snode_t node; + mctp *mctp_inst; + int64_t exp_to_ms; + mctp_cci_msg msg; +} wait_msg; + +/*CCI command handler */ +uint8_t mctp_cci_cmd_handler(void *mctp_p, uint8_t *buf, uint32_t len, mctp_ext_params ext_params); +void cci_read_resp_handler(void *args, uint8_t *rbuf, uint16_t rlen, uint16_t ret_code); +bool cci_get_chip_temp(void *mctp_p, mctp_ext_params ext_params, int16_t *chip_temp); + +/* send CCI command message through mctp */ +uint8_t mctp_cci_send_msg(void *mctp_p, mctp_cci_msg *msg); + +uint16_t mctp_cci_read(void *mctp_p, mctp_cci_msg *msg, uint8_t *rbuf, uint16_t rbuf_len); + +typedef struct __attribute__((__packed__)) { + uint8_t health_status; + uint8_t media_status; + uint8_t additional_status; + uint8_t life_used; + int16_t dev_temp; + uint32_t shutdown_cnt; + uint32_t volatile_mem_err_cnt; + uint32_t persistent_mem_err_cnt; +} cci_health_info_resp; + +#endif /* _CCI_H */ \ No newline at end of file diff --git a/common/service/mctp/mctp.c b/common/service/mctp/mctp.c index a1eeb32bdb..5776cca915 100644 --- a/common/service/mctp/mctp.c +++ b/common/service/mctp/mctp.c @@ -596,3 +596,16 @@ uint8_t mctp_reg_msg_rx_func(mctp *mctp_inst, mctp_fn_cb rx_cb) mctp_inst->rx_cb = rx_cb; return MCTP_SUCCESS; } + +__weak uint8_t get_mctp_info(uint8_t dest_endpoint, mctp **mctp_inst, mctp_ext_params *ext_params) +{ + return MCTP_ERROR; +} + +bool get_mctp_info_by_eid(uint8_t port, mctp **mctp_inst, mctp_ext_params *ext_params) +{ + if (!mctp_inst || !ext_params) { + return false; + } + return (get_mctp_info(port, mctp_inst, ext_params) == MCTP_SUCCESS) ? true : false; +} diff --git a/common/service/mctp/mctp.h b/common/service/mctp/mctp.h index 80e966721b..fe751fe769 100644 --- a/common/service/mctp/mctp.h +++ b/common/service/mctp/mctp.h @@ -61,6 +61,7 @@ typedef enum { MCTP_MSG_TYPE_NCSI, MCTP_MSG_TYPE_ETH, MCTP_MSG_TYPE_NVME, + MCTP_MSG_TYPE_CCI = 0x08, MCTP_MSG_TYPE_VEN_DEF_PCI = 0x7E, MCTP_MSG_TYPE_VEN_DEF_IANA = 0x7F } MCTP_MSG_TYPE; @@ -177,6 +178,8 @@ typedef struct _mctp { /* for pldm instance id */ uint8_t pldm_inst_id; + /* for cci_msg_tag */ + uint8_t cci_msg_tag; } mctp; /* public function */ @@ -212,6 +215,9 @@ uint8_t mctp_i3c_deinit(mctp *mctp_instance); /* register endpoint resolve function */ uint8_t mctp_reg_endpoint_resolve_func(mctp *mctp_inst, endpoint_resolve resolve_fn); +bool get_mctp_info_by_eid(uint8_t port, mctp **mctp_inst, mctp_ext_params *ext_params); +uint8_t get_mctp_info(uint8_t dest_endpoint, mctp **mctp_inst, mctp_ext_params *ext_params); + /* register callback function when the mctp message is received */ uint8_t mctp_reg_msg_rx_func(mctp *mctp_inst, mctp_fn_cb rx_cb);