common/mctp/mctp_smbus.c (133 lines of code) (raw):

#include "mctp.h" #include "hal_i2c_slave.h" #include <logging/log.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <sys/crc.h> #include <sys/printk.h> #include <zephyr.h> LOG_MODULE_DECLARE(mctp, LOG_LEVEL_DBG); #define MCTP_SMBUS_PEC_SIZE 1 #define MCTP_SMBUS_CMD_CODE 0x0F typedef struct __attribute__((packed)) { uint8_t cmd_code; uint8_t byte_count; uint8_t src_addr; } smbus_hdr; static uint8_t cal_pec(uint8_t dest_addr, uint8_t *buf, uint32_t len, uint8_t *pec) { if (!buf || !len || !pec) return MCTP_ERROR; uint8_t pec_buf[len]; pec_buf[0] = dest_addr; memcpy(pec_buf + 1, buf, len - 1); LOG_HEXDUMP_DBG(pec_buf, sizeof(pec_buf), "cal_pec"); *pec = crc8(pec_buf, sizeof(pec_buf), 0x07, 0x00, false); return MCTP_SUCCESS; } static bool is_pec_vaild(uint8_t dest_addr, uint8_t *buf, uint32_t len) { if (!buf || !len) return false; uint8_t pec = 0; if (cal_pec(dest_addr, buf, len, &pec) == MCTP_ERROR) return false; uint8_t exp_pec = buf[len - 1]; if (pec != exp_pec) { LOG_WRN("pec error dest_addr %x, cal = %x, exp = %x", dest_addr, pec, exp_pec); LOG_HEXDUMP_WRN(buf, sizeof(len), "is_pec_vaild"); } return (pec == exp_pec) ? true : false; } static uint8_t make_send_buf(mctp *mctp_inst, uint8_t *send_buf, uint32_t send_len, uint8_t *mctp_data, uint32_t mctp_data_len, mctp_ext_params extra_data) { if (!mctp_inst || !send_buf || !send_len || !mctp_data || !mctp_data_len) return MCTP_ERROR; smbus_hdr *hdr = (smbus_hdr *)send_buf; hdr->cmd_code = MCTP_SMBUS_CMD_CODE; /* bit 0 always set */ hdr->src_addr = mctp_inst->medium_conf.smbus_conf.addr + 1; /* extend 1 byte src addr */ hdr->byte_count = 1 + mctp_data_len; memcpy(send_buf + sizeof(*hdr), mctp_data, mctp_data_len); uint8_t pec = 0; if (cal_pec(extra_data.smbus_ext_params.addr, send_buf, send_len, &pec) == MCTP_ERROR) return MCTP_ERROR; send_buf[send_len - 1] = pec; return MCTP_SUCCESS; } static uint16_t mctp_smbus_read(void *mctp_p, uint8_t *buf, uint32_t len, mctp_ext_params *extra_data) { if (!mctp_p || !buf || !len || !extra_data) return 0; mctp *mctp_inst = (mctp *)mctp_p; uint8_t rdata[256] = { 0 }; uint16_t rlen = 0; /* TODO: read data from smbus */ uint8_t ret = 0; ret = i2c_slave_read(mctp_inst->medium_conf.smbus_conf.bus, rdata, 256, &rlen); if (ret) { LOG_ERR("i2c_slave_read fail, ret %d\n", ret); return 0; } smbus_hdr *hdr = (smbus_hdr *)rdata; /* *Does read data include pec? *rlen = 1(mctp cmd code 0x0F) + * 1(byte count) + N(byte count) + 1(*pec, if exist) *so if rlen is equal N + 3, the pec is existing */ const uint8_t is_pec_exist = ((hdr->byte_count + 3) == rlen) ? 1 : 0; if (is_pec_exist) { if (is_pec_vaild(mctp_inst->medium_conf.smbus_conf.addr, rdata, rlen) == false) return 0; } if (hdr->cmd_code != MCTP_SMBUS_CMD_CODE) return 0; extra_data->type = MCTP_MEDIUM_TYPE_SMBUS; extra_data->smbus_ext_params.addr = hdr->src_addr - 1; uint8_t rt_size = rlen - sizeof(smbus_hdr) - is_pec_exist; memcpy(buf, rdata + sizeof(smbus_hdr), rt_size); return rt_size; } static uint16_t mctp_smbus_write(void *mctp_p, uint8_t *buf, uint32_t len, mctp_ext_params extra_data) { if (!mctp_p || !buf || !len) return 0; mctp *mctp_inst = (mctp *)mctp_p; if (extra_data.type != MCTP_MEDIUM_TYPE_SMBUS) return 0; LOG_HEXDUMP_DBG(buf, len, "mctp_smbus_write receive data"); /* send len = 1(mctp cmd code 0x0F) + 1(byte count) + 1(src addr) + len(mctp data) + 1(*pec, if exist) */ uint32_t send_len = len + 4; uint8_t send_buf[send_len]; uint8_t rc = make_send_buf(mctp_inst, send_buf, send_len, buf, len, extra_data); if (rc == MCTP_ERROR) { LOG_WRN("make send buf failed!!"); return 0; } LOG_DBG("smbus_ext_params addr = %x", extra_data.smbus_ext_params.addr); LOG_HEXDUMP_DBG(send_buf, send_len, "mctp_smbus_write make header"); /* TODO: write data to smbus */ int status; I2C_MSG i2c_msg; i2c_msg.bus = mctp_inst->medium_conf.smbus_conf.bus; i2c_msg.slave_addr = extra_data.smbus_ext_params.addr >> 1; i2c_msg.tx_len = send_len; memcpy(&i2c_msg.data[0], send_buf, send_len); status = i2c_master_write(&i2c_msg, 5); if (status) LOG_ERR("i2c_master_write failt, ret %d", status); /* TODO: return the actually write data len */ return 1; } uint8_t mctp_smbus_init(mctp *mctp_inst, mctp_medium_conf medium_conf) { if (!mctp_inst) return MCTP_ERROR; mctp_inst->medium_conf = medium_conf; mctp_inst->read_data = mctp_smbus_read; mctp_inst->write_data = mctp_smbus_write; return MCTP_SUCCESS; } uint8_t mctp_smbus_deinit(mctp *mctp_inst) { if (!mctp_inst) return MCTP_ERROR; mctp_inst->read_data = NULL; mctp_inst->write_data = NULL; memset(&mctp_inst->medium_conf, 0, sizeof(mctp_inst->medium_conf)); return MCTP_SUCCESS; }