@@ -3,7 +3,8 @@
sources = [
'sssnic_hw.c',
- 'sssnic_eventq.c'
+ 'sssnic_eventq.c',
+ 'sssnic_msg.c',
]
c_args = cflags
@@ -14,6 +14,7 @@
#include "../sssnic_log.h"
#include "sssnic_hw.h"
#include "sssnic_reg.h"
+#include "sssnic_msg.h"
#include "sssnic_eventq.h"
#define SSSNIC_EVENTQ_DEF_DEPTH 64
@@ -184,6 +185,32 @@ sssnic_eventq_ci_update(struct sssnic_eventq *eq, int informed)
sssnic_eventq_reg_write(eq, SSSNIC_EVENTQ_CI_CTRL_REG, reg.u32);
}
+static int
+sssnic_event_default_handler_func(struct sssnic_eventq *eq,
+ struct sssnic_event *ev, __rte_unused void *data)
+{
+ struct sssnic_hw *hw;
+ int ret;
+
+ hw = eq->hw;
+ ret = sssnic_msg_rx_handle(hw, (struct sssnic_msg_hdr *)(ev->data));
+ if (ret != SSSNIC_MSG_DONE)
+ return -1;
+
+ return SSSNIC_EVENT_DONE;
+}
+
+static void
+sssnic_eventq_handlers_init(struct sssnic_eventq *eq)
+{
+ int i;
+
+ for (i = SSSNIC_EVENT_CODE_MIN; i <= SSSNIC_EVENT_CODE_MAX; i++) {
+ eq->handlers[i].func = sssnic_event_default_handler_func;
+ eq->handlers[i].data = NULL;
+ }
+}
+
static int
sssnic_eventq_init(struct sssnic_hw *hw, struct sssnic_eventq *eq, uint16_t qid)
{
@@ -230,6 +257,8 @@ sssnic_eventq_init(struct sssnic_hw *hw, struct sssnic_eventq *eq, uint16_t qid)
PMD_DRV_LOG(ERR, "Failed to setup eventq pages!");
return ret;
}
+
+ sssnic_eventq_handlers_init(eq);
sssnic_eventq_ctrl_setup(eq);
sssnic_eventq_ci_update(eq, 1);
if (qid == 0)
@@ -10,6 +10,7 @@
#include "sssnic_hw.h"
#include "sssnic_reg.h"
#include "sssnic_eventq.h"
+#include "sssnic_msg.h"
static int
wait_for_sssnic_hw_ready(struct sssnic_hw *hw)
@@ -197,18 +198,30 @@ sssnic_hw_init(struct sssnic_hw *hw)
return ret;
}
+ ret = sssnic_msg_inbox_init(hw);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to initialize message inbox.");
+ return ret;
+ }
+
ret = sssnic_eventq_all_init(hw);
if (ret != 0) {
PMD_DRV_LOG(ERR, "Failed to initialize event queues");
- return ret;
+ goto eventq_init_fail;
}
return -EINVAL;
+
+eventq_init_fail:
+ sssnic_msg_inbox_shutdown(hw);
+ return ret;
}
void
sssnic_hw_shutdown(struct sssnic_hw *hw)
{
PMD_INIT_FUNC_TRACE();
+
sssnic_eventq_all_shutdown(hw);
+ sssnic_msg_inbox_shutdown(hw);
}
@@ -52,11 +52,13 @@ struct sssnic_hw {
uint8_t *db_mem_len;
struct sssnic_hw_attr attr;
struct sssnic_eventq *eventqs;
+ struct sssnic_msg_inbox *msg_inbox;
uint8_t num_eventqs;
uint16_t eth_port_id;
};
#define SSSNIC_ETH_PORT_ID(hw) ((hw)->eth_port_id)
+#define SSSNIC_MPU_FUNC_IDX 0x1fff
int sssnic_hw_init(struct sssnic_hw *hw);
void sssnic_hw_shutdown(struct sssnic_hw *hw);
new file mode 100644
@@ -0,0 +1,255 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.
+ */
+
+#include <error.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+
+#include "../sssnic_log.h"
+#include "sssnic_hw.h"
+#include "sssnic_msg.h"
+
+/* Receive message segment based on message header
+ * @param msghdr
+ * message header
+ * @param msg
+ * message where segment store
+ * @return
+ * SSSNIC_MSG_REJECT - Message segment was not received because of bad
+ * parameter of message header.
+ * SSSNIC_MSG_ACCEPT - Message segment was received.
+ * SSSNIC_MSG_DONE - The last message segment was received.
+ */
+static int
+sssnic_msg_rx_seg(struct sssnic_msg_hdr *msghdr, struct sssnic_msg *msg)
+{
+ if (msghdr->seg_id > SSSNIC_MSG_MAX_SEG_ID ||
+ msghdr->seg_len > SSSNIC_MSG_MAX_SEG_SIZE) {
+ PMD_DRV_LOG(ERR,
+ "Bad segment id or segment size of message header");
+ return SSSNIC_MSG_REJECT;
+ }
+
+ if (msghdr->seg_id == 0) {
+ msg->command = msghdr->command;
+ msg->type = msghdr->type;
+ msg->module = msghdr->module;
+ msg->id = msghdr->id;
+ } else {
+ if (msghdr->seg_id != (msg->seg + 1) || msghdr->id != msg->id ||
+ msghdr->module != msg->module ||
+ msghdr->command != msg->command) {
+ PMD_DRV_LOG(ERR, "Bad parameters of message header");
+ return SSSNIC_MSG_REJECT;
+ }
+ }
+ rte_memcpy(msg->data_buf + (SSSNIC_MSG_MAX_SEG_SIZE * msghdr->seg_id),
+ SSSNIC_MSG_DATA(msghdr), msghdr->seg_len);
+
+ if (!msghdr->last_seg) {
+ msg->seg = msghdr->seg_id;
+ return SSSNIC_MSG_ACCEPT;
+ }
+
+ msg->ack = !msghdr->no_response;
+ msg->status = msghdr->status;
+ msg->data_len = msghdr->length;
+ msg->func = msghdr->function;
+ msg->seg = SSSNIC_MSG_MAX_SEG_ID;
+
+ return SSSNIC_MSG_DONE;
+}
+
+static int
+sssnic_msg_buf_alloc(struct sssnic_msg *msg, size_t size)
+{
+ msg->data_buf = rte_zmalloc("sssnic_msg_data", size, 1);
+ if (msg->data_buf == NULL) {
+ PMD_DRV_LOG(ERR, "Could not all message data buffer!");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+sssnic_msg_buf_free(struct sssnic_msg *msg)
+{
+ rte_free(msg->data_buf);
+}
+
+int
+sssnic_msg_rx_handle(struct sssnic_hw *hw, struct sssnic_msg_hdr *msghdr)
+{
+ struct sssnic_msg *msg;
+ struct sssnic_msg_handler *msg_handler;
+ int msg_src;
+ int msg_chan;
+ int msg_type;
+ int ret;
+
+ msg_src = SSSNIC_MSG_SRC(msghdr->function);
+ msg_chan = msghdr->channel;
+ msg_type = msghdr->type;
+ msg = SSSNIC_MSG_LOCATE(hw, msg_chan, msg_type, msg_src);
+
+ ret = sssnic_msg_rx_seg(msghdr, msg);
+ if (ret != SSSNIC_MSG_DONE)
+ return ret;
+
+ msg_handler = SSSNIC_MSG_HANDLER(hw, msg_chan, msg_type);
+ if (msg_handler->func == NULL) {
+ PMD_DRV_LOG(NOTICE,
+ "No message handler, message channel:%d, type:%d.",
+ msg_chan, msg_type);
+ return SSSNIC_MSG_REJECT;
+ }
+ ret = msg_handler->func(msg, msg_chan, msg_handler->priv);
+
+ return ret;
+}
+
+int
+sssnic_msg_rx_handler_register(struct sssnic_hw *hw,
+ enum sssnic_msg_chann_id chann_id, enum sssnic_msg_type msg_type,
+ sssnic_msg_handler_func_t *func, void *priv)
+{
+ struct sssnic_msg_handler *msg_handler;
+
+ if (chann_id >= SSSNIC_MSG_CHAN_COUNT ||
+ msg_type >= SSSNIC_MSG_TYPE_CONUT || func == NULL) {
+ PMD_DRV_LOG(ERR,
+ "Bad parameters for register rx message handler.");
+ return -EINVAL;
+ }
+
+ msg_handler = SSSNIC_MSG_HANDLER(hw, chann_id, msg_type);
+ if (msg_handler->func != NULL)
+ PMD_DRV_LOG(WARNING,
+ "RX message handler has existed, chann_id:%u, msg_type:%u",
+ chann_id, msg_type);
+
+ msg_handler->func = func;
+ msg_handler->priv = priv;
+
+ return 0;
+}
+
+static int
+sssnic_msg_channel_init(struct sssnic_hw *hw, struct sssnic_msg_channel *chan)
+{
+ struct sssnic_msg *msg;
+ int i;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ for (i = 0; i < SSSNIC_MSG_TYPE_CONUT; i++) {
+ msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+ ret = sssnic_msg_buf_alloc(msg, SSSNIC_MSG_BUF_SIZE);
+ if (ret) {
+ PMD_DRV_LOG(ERR,
+ "Could not alloc MPU message buf for message inbox channel %d of sssnic%u.",
+ SSSNIC_ETH_PORT_ID(hw), chan->id);
+ goto msg_buf_alloc_fail;
+ }
+ msg = &chan->msg[i][SSSNIC_MSG_SRC_PF];
+ ret = sssnic_msg_buf_alloc(msg, SSSNIC_MSG_BUF_SIZE);
+ if (ret) {
+ PMD_DRV_LOG(ERR,
+ "Could not alloc PF message buf for message inbox channel %d of sssnic%u.",
+ SSSNIC_ETH_PORT_ID(hw), chan->id);
+ msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+ sssnic_msg_buf_free(msg);
+ goto msg_buf_alloc_fail;
+ }
+ }
+
+ return 0;
+
+msg_buf_alloc_fail:
+ while (i--) {
+ msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+ sssnic_msg_buf_free(msg);
+ msg = &chan->msg[i][SSSNIC_MSG_SRC_PF];
+ sssnic_msg_buf_free(msg);
+ }
+ return ret;
+}
+
+static void
+sssnic_msg_channel_shutdown(__rte_unused struct sssnic_hw *hw,
+ struct sssnic_msg_channel *chan)
+{
+ struct sssnic_msg *msg;
+ int i;
+
+ PMD_INIT_FUNC_TRACE();
+
+ for (i = 0; i < SSSNIC_MSG_TYPE_CONUT; i++) {
+ msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+ sssnic_msg_buf_free(msg);
+ msg = &chan->msg[i][SSSNIC_MSG_SRC_PF];
+ sssnic_msg_buf_free(msg);
+ }
+}
+
+int
+sssnic_msg_inbox_init(struct sssnic_hw *hw)
+{
+ struct sssnic_msg_inbox *inbox;
+ struct sssnic_msg_channel *chan;
+ int i;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ inbox = rte_zmalloc(NULL, sizeof(struct sssnic_msg_inbox), 1);
+ if (inbox == NULL) {
+ PMD_DRV_LOG(ERR, "Could not alloc memory for message inbox");
+ return -ENOMEM;
+ }
+
+ inbox->hw = hw;
+ hw->msg_inbox = inbox;
+
+ for (i = 0; i < SSSNIC_MSG_CHAN_COUNT; i++) {
+ chan = &inbox->channel[i];
+ ret = sssnic_msg_channel_init(hw, chan);
+ if (ret) {
+ PMD_DRV_LOG(ERR,
+ "Failed to initialize channel%u of message inbox",
+ i);
+ goto init_msg_channel_fail;
+ }
+ chan->id = i;
+ }
+
+ return 0;
+
+init_msg_channel_fail:
+ while (i--) {
+ chan = &inbox->channel[i];
+ sssnic_msg_channel_shutdown(hw, chan);
+ }
+ rte_free(inbox);
+ return ret;
+}
+
+void
+sssnic_msg_inbox_shutdown(struct sssnic_hw *hw)
+{
+ struct sssnic_msg_channel *chan;
+ int i;
+
+ PMD_INIT_FUNC_TRACE();
+
+ for (i = 0; i < SSSNIC_MSG_CHAN_COUNT; i++) {
+ chan = &hw->msg_inbox->channel[i];
+ sssnic_msg_channel_shutdown(hw, chan);
+ }
+ rte_free(hw->msg_inbox);
+}
new file mode 100644
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.
+ */
+
+#ifndef _SSSNIC_MSG_H_
+#define _SSSNIC_MSG_H_
+
+#include <string.h>
+
+enum sssnic_msg_chann_id {
+ SSSNIC_MSG_CHAN_MPU = 0, /* Message comes from MPU directly */
+ SSSNIC_MSG_CHAN_MBOX = 1, /* Message comes from MBOX */
+ SSSNIC_MSG_CHAN_COUNT = 2,
+};
+
+enum sssnic_msg_src {
+ SSSNIC_MSG_SRC_MPU, /* mbox message from MPU */
+ SSSNIC_MSG_SRC_PF, /* mbox message from PF */
+ SSSNIC_MSG_SRC_COUNT,
+};
+
+#define SSSNIC_MSG_SRC(func_id) \
+ (((func_id) == SSSNIC_MPU_FUNC_IDX) ? SSSNIC_MSG_SRC_MPU : \
+ SSSNIC_MSG_SRC_PF)
+
+enum sssnic_msg_type {
+ SSSNIC_MSG_TYPE_REQ, /* Request message*/
+ SSSNIC_MSG_TYPE_RESP, /* Response message */
+ SSSNIC_MSG_TYPE_CONUT,
+};
+
+#define SSSNIC_MSG_TRANS_MODE_DMA 1
+#define SSSNIC_MSG_TRANS_MODE_INLINE 0
+
+/* hardware format of sssnic message header */
+struct sssnic_msg_hdr {
+ union {
+ uint64_t u64;
+ struct {
+ uint32_t dw0;
+ uint32_t dw1;
+ };
+ struct {
+ /* Id of the function the message comes from or send to */
+ uint64_t function : 13;
+ /* indicate the result of command */
+ uint64_t status : 2;
+ /* Mbox channel that message receive from or send to */
+ uint64_t channel : 1;
+ /* ID of the EventQ that response message is informed by */
+ uint64_t eventq : 2;
+ /* Message ID */
+ uint64_t id : 4;
+ /* Command ID of the message */
+ uint64_t command : 10;
+ /* total length of message data */
+ uint64_t length : 11;
+ /* Module of message comes from or send to */
+ uint64_t module : 5;
+ /* Length of this data segment */
+ uint64_t seg_len : 6;
+ /* needless response indication */
+ uint64_t no_response : 1;
+ /* Message data transmission mode, 0: inline 1:dma */
+ uint64_t trans_mode : 1;
+ /* Segment sequence of message data */
+ uint64_t seg_id : 6;
+ /* Last data segment indication, 1: Last segment */
+ uint64_t last_seg : 1;
+ /* Message type, see sssnic_mbox_msg_type */
+ uint64_t type : 1;
+ };
+ };
+};
+#define SSSNIC_MSG_HDR_SIZE sizeof(struct sssnic_msg_hdr)
+#define SSSNIC_MSG_DATA(hdr) (((uint8_t *)hdr) + SSSNIC_MSG_HDR_SIZE)
+
+#define SSSNIC_MSG_BUF_SIZE 2048UL
+#define SSSNIC_MSG_MAX_SEG_SIZE 48
+#define SSSNIC_MSG_MIN_SGE_ID 0
+#define SSSNIC_MSG_MAX_SEG_ID 42
+#define SSSNIC_MSG_MAX_DATA_SIZE (SSSNIC_MSG_BUF_SIZE - SSSNIC_MSG_HDR_SIZE)
+
+struct sssnic_msg {
+ /* message command ID */
+ uint16_t command;
+ /* function id of that message send to or receive from */
+ uint16_t func;
+ /* module id of that message send to or receive from */
+ uint32_t module;
+ /* message is request or response*/
+ enum sssnic_msg_type type;
+ /* message data */
+ uint8_t *data_buf;
+ /* data length */
+ uint32_t data_len;
+ /* need response indication */
+ uint8_t ack;
+ /* the id of last received segment*/
+ uint8_t seg;
+ /* indicate the result of request in response message, request failed if not 0 */
+ uint8_t status;
+ /* generated by sender if dir == SSSNIC_MSG_TYPE_REQ */
+ uint8_t id;
+};
+
+#define SSSNIC_MSG_REJECT -1
+#define SSSNIC_MSG_ACCEPT 0
+#define SSSNIC_MSG_DONE 1
+
+/* sssnic message handler function
+ * @return
+ * SSSNIC_MSG_REJECT - Message failed to handle
+ * SSSNIC_MSG_DONE - Message succeed to handle
+ */
+typedef int sssnic_msg_handler_func_t(struct sssnic_msg *msg,
+ enum sssnic_msg_chann_id chan_id, void *priv);
+
+struct sssnic_msg_handler {
+ sssnic_msg_handler_func_t *func;
+ void *priv;
+};
+
+struct sssnic_msg_channel {
+ enum sssnic_msg_chann_id id;
+ struct sssnic_msg msg[SSSNIC_MSG_TYPE_CONUT][SSSNIC_MSG_SRC_COUNT];
+ struct sssnic_msg_handler handler[SSSNIC_MSG_TYPE_CONUT];
+};
+
+struct sssnic_msg_inbox {
+ struct sssnic_hw *hw;
+ struct sssnic_msg_channel channel[SSSNIC_MSG_CHAN_COUNT];
+};
+
+#define SSSNIC_MSG_INBOX(hw) ((hw)->msg_inbox)
+#define SSSNIC_MSG_CHANNEL(hw, chann_id) \
+ (&(SSSNIC_MSG_INBOX(hw)->channel[chann_id]))
+#define SSSNIC_MSG_LOCATE(hw, chann_id, type, src) \
+ (&SSSNIC_MSG_CHANNEL(hw, chann_id)->msg[type][src])
+#define SSSNIC_MSG_HANDLER(hw, chann_id, type) \
+ (&SSSNIC_MSG_CHANNEL(hw, chann_id)->handler[type])
+
+static inline void
+sssnic_msg_init(struct sssnic_msg *msg, uint8_t *data, uint32_t data_len,
+ uint16_t command, uint16_t func, uint32_t module,
+ enum sssnic_msg_type type)
+{
+ memset(msg, 0, sizeof(struct sssnic_msg));
+ msg->data_buf = data;
+ msg->data_len = data_len;
+ msg->command = command;
+ msg->module = module;
+ msg->func = func;
+ msg->type = type;
+}
+
+int sssnic_msg_rx_handler_register(struct sssnic_hw *hw,
+ enum sssnic_msg_chann_id chann_id, enum sssnic_msg_type msg_type,
+ sssnic_msg_handler_func_t *func, void *priv);
+int sssnic_msg_rx_handle(struct sssnic_hw *hw, struct sssnic_msg_hdr *msghdr);
+int sssnic_msg_inbox_init(struct sssnic_hw *hw);
+void sssnic_msg_inbox_shutdown(struct sssnic_hw *hw);
+int sssnic_msg_rx(struct sssnic_msg_hdr *msghdr, uint16_t max_seg_len,
+ uint16_t max_seg_id, struct sssnic_msg *msg);
+
+#endif /* _SSSNIC_MSG_H_ */