On Sun, Aug 30, 2026 at 10:02 PM Vamsi Krishna <[email protected]> wrote: > > From: Vamsi Attunuru <[email protected]> > > Introduce CN20K mailbox, ring setup, and TX & RX handling > in the octeon_ep driver, with PCI probe and ethdev integration > for O20 endpoint hardware. > > Signed-off-by: Vamsi Attunuru <[email protected]>
1) Please update the release notes 2) Please update doc/guides/nics/octeon_ep.rst 3) Fix the genunine issues mentioned in https://mails.dpdk.org/archives/test-report/2026-August/1037042.html 4) Use C11 rte_atomic APIs instead of rte_smp_rmb() > --- > drivers/net/octeon_ep/cn20k_ep_mbox.c | 825 ++++++++++++++++++++++++ > drivers/net/octeon_ep/cn20k_ep_mbox.h | 133 ++++ > drivers/net/octeon_ep/cn20k_ep_vf.c | 425 ++++++++++++ > drivers/net/octeon_ep/cn20k_ep_vf.h | 175 +++++ > drivers/net/octeon_ep/cnxk_ep_rx.c | 90 ++- > drivers/net/octeon_ep/cnxk_ep_rx.h | 29 +- > drivers/net/octeon_ep/cnxk_ep_rx_avx.c | 38 +- > drivers/net/octeon_ep/cnxk_ep_rx_neon.c | 71 +- > drivers/net/octeon_ep/cnxk_ep_rx_sse.c | 29 +- > drivers/net/octeon_ep/meson.build | 2 + > drivers/net/octeon_ep/otx_ep_common.h | 9 + > drivers/net/octeon_ep/otx_ep_ethdev.c | 88 ++- > drivers/net/octeon_ep/otx_ep_mbox.c | 16 +- > drivers/net/octeon_ep/otx_ep_rxtx.c | 3 + > 14 files changed, 1850 insertions(+), 83 deletions(-) > > diff --git a/drivers/net/octeon_ep/cn20k_ep_mbox.c > b/drivers/net/octeon_ep/cn20k_ep_mbox.c > new file mode 100644 > index 0000000000..625f807ca2 > --- /dev/null > +++ b/drivers/net/octeon_ep/cn20k_ep_mbox.c > @@ -0,0 +1,825 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2026 Marvell. > + */ > + > +#include <errno.h> > +#include <string.h> > + > +#include <rte_common.h> > +#include <rte_cycles.h> > +#include <rte_malloc.h> > + > +#include "otx_ep_common.h" > +#include "otx2_ep_vf.h" > +#include "cn20k_ep_vf.h" > +#include "cn20k_ep_mbox.h" > + > +#define MBOX_RSP_TIMEOUT_MS 10000 > +#define MBOX_CMD_TIMEOUT_US 1000000 > + > +#define CN20K_MBOX_MSGS_OFFSET RTE_ALIGN(sizeof(struct cn20k_mbox_hdr), > MBOX_MSG_ALIGN) > + > +static int > +cn20k_mbox_wait_wr_cmd_out(struct otx_ep_device *otx_ep, uint16_t offset) > +{ > + uint64_t timeout = (MBOX_CMD_TIMEOUT_US * rte_get_timer_hz()) / > 1000000; > + uint64_t start = rte_get_timer_cycles(); > + > + while (oct_ep_read64(otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_WR_CMD_CTL) & > + CN20K_MBOX_WR_CMD_OUT) { > + if (rte_get_timer_cycles() - start >= timeout) { > + otx_ep_err("Mbox write timeout waiting for CMD_OUT > clear (offset %u)", > + offset); > + return -ETIMEDOUT; > + } > + rte_pause(); > + } > + > + return 0; > +} > + > +static int > +cn20k_mbox_wait_rd_cmd_out(struct otx_ep_device *otx_ep, uint16_t offset) > +{ > + uint64_t timeout = (MBOX_CMD_TIMEOUT_US * rte_get_timer_hz()) / > 1000000; > + uint64_t start = rte_get_timer_cycles(); > + > + while (oct_ep_read64(otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RD_CMD_CTL) & > + CN20K_MBOX_RD_CMD_OUT) { > + if (rte_get_timer_cycles() - start >= timeout) { > + otx_ep_err("Mbox read timeout waiting for CMD_OUT > clear (offset %u)", > + offset); > + return -ETIMEDOUT; > + } > + rte_pause(); > + } > + > + return 0; > +} > + > +static int > +otx_ep_cn20k_mbox_write(struct otx_ep_device *otx_ep, uint16_t offset, void > *buf, size_t len) > +{ > + uint64_t *data = (uint64_t *)buf; > + size_t num_words = (len + 7) / 8; > + uint64_t ctl; > + size_t i; > + int ret; > + > + otx_ep_dbg("CN20K: mbox_write called: offset=%u, len=%zu", offset, > len); > + > + if (offset & 0x7) { > + otx_ep_err("Mailbox offset 0x%x not 8-byte aligned", offset); > + return -EINVAL; > + } > + > + ret = cn20k_mbox_wait_wr_cmd_out(otx_ep, offset); > + if (ret) > + return ret; > + > + oct_ep_write64(offset, otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_WR_CMD_OFFSET); > + > + for (i = 0; i < num_words; i++) { > + uint64_t timeout = (MBOX_CMD_TIMEOUT_US * rte_get_timer_hz()) > / 1000000; > + uint64_t start = rte_get_timer_cycles(); > + > + oct_ep_write64(data[i], otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_WR_CMD_DATA); > + > + do { > + ctl = oct_ep_read64(otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_WR_CMD_CTL); > + if (rte_get_timer_cycles() - start >= timeout) { > + otx_ep_err("Mbox write timeout waiting for > CMD_DONE"); > + return -ETIMEDOUT; > + } > + rte_pause(); > + } while (!(ctl & CN20K_MBOX_WR_CMD_DONE)); > + > + if (ctl & CN20K_MBOX_WR_CMD_ERR) { > + otx_ep_err("Mbox write error at offset %u", offset + > (uint16_t)(i * 8)); > + oct_ep_write64(CN20K_MBOX_WR_CMD_ERR, > + otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_WR_CMD_CTL); > + return -EIO; > + } > + > + if (ctl & CN20K_MBOX_WR_DROP) { > + otx_ep_err("Mbox write dropped at offset %u", offset > + (uint16_t)(i * 8)); > + oct_ep_write64(CN20K_MBOX_WR_DROP, > + otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_WR_CMD_CTL); > + return -EIO; > + } > + } > + > + return 0; > +} > + > +static int > +otx_ep_cn20k_mbox_read(struct otx_ep_device *otx_ep, uint16_t offset, void > *buf, size_t len) > +{ > + size_t i, num_words = (len + 7) / 8; > + uint64_t *data = (uint64_t *)buf; > + uint64_t ctl; > + int ret; > + > + otx_ep_dbg("CN20K: mbox_read called: offset=%u, len=%zu", offset, > len); > + > + if (offset & 0x7) { > + otx_ep_err("Mailbox offset 0x%x not 8-byte aligned", offset); > + return -EINVAL; > + } > + > + ret = cn20k_mbox_wait_rd_cmd_out(otx_ep, offset); > + if (ret) > + return ret; > + > + oct_ep_write64(offset, otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RD_CMD_OFFSET); > + > + for (i = 0; i < num_words; i++) { > + uint64_t start = rte_get_timer_cycles(); > + uint64_t timeout = (MBOX_CMD_TIMEOUT_US * rte_get_timer_hz()) > / 1000000; > + > + rte_smp_wmb(); > + if (i == 0) { > + /* Dummy write, loads Offset = 0 data into CSR. Value > doesn't matter, > + * it gets ignored by hardware. > + */ > + oct_ep_write64(0, otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RD_CMD_DATA); > + rte_smp_wmb(); > + do { > + ctl = oct_ep_read64(otx_ep->hw_addr + > + > CN20K_SDP_RMT_VFX_MBOX_RD_CMD_CTL); > + if (rte_get_timer_cycles() - start >= > timeout) { > + otx_ep_err("Mbox read timeout waiting > for CMD_DONE"); > + return -ETIMEDOUT; > + } > + rte_pause(); > + } while (!(ctl & CN20K_MBOX_RD_CMD_DONE)); > + } > + > + data[i] = oct_ep_read64(otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RD_CMD_DATA); > + > + do { > + ctl = oct_ep_read64(otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RD_CMD_CTL); > + if (rte_get_timer_cycles() - start >= timeout) { > + otx_ep_err("Mbox read timeout waiting for > CMD_DONE"); > + return -ETIMEDOUT; > + } > + rte_pause(); > + } while (!(ctl & CN20K_MBOX_RD_CMD_DONE)); > + > + if (ctl & CN20K_MBOX_RD_CMD_ERR) { > + otx_ep_err("Mbox read error at offset %u", offset + > (uint16_t)(i * 8)); > + oct_ep_write64(CN20K_MBOX_RD_CMD_ERR, > + otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RD_CMD_CTL); > + data[i] = 0; > + return -EIO; > + } > + } > + > + ret = cn20k_mbox_wait_rd_cmd_out(otx_ep, offset); > + > + return 0; > +} > + > +static int > +otx_ep_cn20k_mbox_msg_send(struct otx_ep_cn20k_mbox_priv *mbox) > +{ > + struct otx_ep_device *otx_ep = mbox->otx_ep; > + struct cn20k_mbox_hdr tx_hdr, rx_hdr_zero = {0}; > + int ret = 0; > + > + tx_hdr.msg_size = mbox->msg_size; > + tx_hdr.num_msgs = mbox->num_msgs; > + tx_hdr.sig = OCTEP_CN20K_MBOX_REQ_SIG; > + > + rte_smp_wmb(); > + > + if (mbox->mbase != mbox->hwbase) { > + ret = otx_ep_cn20k_mbox_write(otx_ep, > (uint16_t)mbox->tx_start, &tx_hdr, > + sizeof(tx_hdr)); > + if (ret) { > + otx_ep_err("Failed to write TX header"); > + goto err; > + } > + > + rte_smp_wmb(); > + ret = otx_ep_cn20k_mbox_write(otx_ep, > + (uint16_t)(mbox->tx_start + > CN20K_MBOX_MSGS_OFFSET), > + (uint8_t *)mbox->mbase + > mbox->tx_start + > + CN20K_MBOX_MSGS_OFFSET, > mbox->msg_size); > + if (ret) { > + otx_ep_err("Failed to write message payload"); > + goto err; > + } > + > + rte_smp_wmb(); > + ret = otx_ep_cn20k_mbox_write(otx_ep, > (uint16_t)mbox->rx_start, &rx_hdr_zero, > + sizeof(rx_hdr_zero)); > + if (ret) { > + otx_ep_err("Failed to clear RX header"); > + goto err; > + } > + } > + > + rte_smp_wmb(); > + oct_ep_write64(MBOX_DOWN_MSG, otx_ep->hw_addr + mbox->trigger); > + > +err: > + return ret; > +} > + > +static int > +otx_ep_cn20k_mbox_check_rsp_msgs(struct otx_ep_cn20k_mbox_priv *mbox) > +{ > + struct otx_ep_device *otx_ep = mbox->otx_ep; > + struct cn20k_mbox_hdr rx_hdr; > + int ret; > + > + ret = otx_ep_cn20k_mbox_read(otx_ep, (uint16_t)mbox->rx_start, > &rx_hdr, sizeof(rx_hdr)); > + if (ret) { > + otx_ep_err("Failed to read RX header"); > + return ret; > + } > + > + if (rx_hdr.num_msgs == 0) > + return 0; > + > + if (rx_hdr.msg_size > mbox->rx_size - CN20K_MBOX_MSGS_OFFSET) { > + otx_ep_err("RX message size %u exceeds buffer (%u)", > + (uint32_t)rx_hdr.msg_size, > + (uint32_t)(mbox->rx_size - > CN20K_MBOX_MSGS_OFFSET)); > + return -EINVAL; > + } > + > + if (mbox->mbase != mbox->hwbase) { > + ret = otx_ep_cn20k_mbox_read(otx_ep, > + (uint16_t)(mbox->rx_start + > CN20K_MBOX_MSGS_OFFSET), > + (uint8_t *)mbox->mbase + > mbox->rx_start + > + CN20K_MBOX_MSGS_OFFSET, > rx_hdr.msg_size); > + if (ret) { > + otx_ep_err("Failed to read response messages"); > + return ret; > + } > + } > + > + mbox->msgs_acked = rx_hdr.num_msgs; > + > + return 0; > +} > + > +static int > +otx_ep_cn20k_mbox_wait_for_rsp(struct otx_ep_cn20k_mbox_priv *mbox) > +{ > + uint64_t start = rte_get_timer_cycles(); > + uint64_t timeout = (MBOX_RSP_TIMEOUT_MS * rte_get_timer_hz()) / 1000; > + > + while (rte_get_timer_cycles() - start < timeout) { > + if (mbox->num_msgs == mbox->msgs_acked) > + return 0; > + rte_delay_us(1000); > + otx_ep_cn20k_mbox_check_rsp_msgs(mbox); > + } > + > + otx_ep_err("Mbox response timeout"); > + > + return -ETIMEDOUT; > +} > + > +static void * > +otx_ep_cn20k_mbox_alloc_msg(struct otx_ep_cn20k_mbox_priv *mbox, int size, > int size_rsp) > +{ > + struct otx_ep_cn20k_mbox_msghdr *msghdr; > + > + if ((uint32_t)(mbox->msg_size + size) > mbox->tx_size - > CN20K_MBOX_MSGS_OFFSET) { > + otx_ep_err("Mailbox message size exceeds limit"); > + return NULL; > + } > + > + msghdr = (struct otx_ep_cn20k_mbox_msghdr *)((uint8_t *)mbox->mbase + > mbox->tx_start + > + CN20K_MBOX_MSGS_OFFSET + > mbox->msg_size); > + > + memset(msghdr, 0, size); > + > + msghdr->ver = OCTEP_CN20K_MBOX_VERSION; > + mbox->msg_size += size; > + mbox->rsp_size += size_rsp; > + mbox->num_msgs++; > + msghdr->next_msgoff = mbox->msg_size + CN20K_MBOX_MSGS_OFFSET; > + > + return msghdr; > +} > + > +static struct otx_ep_cn20k_ready_msg_req * > +otx_ep_cn20k_mbox_alloc_msg_ready(struct otx_ep_device *otx_ep) > +{ > + struct otx_ep_cn20k_mbox *cn20k_mbox = otx_ep->mbox_info; > + struct otx_ep_cn20k_mbox_priv *mbox = &cn20k_mbox->mbox; > + struct otx_ep_cn20k_ready_msg_req *req; > + > + req = otx_ep_cn20k_mbox_alloc_msg(mbox, sizeof(*req), > + sizeof(struct > otx_ep_cn20k_ready_msg_rsp)); > + if (!req) > + return NULL; > + > + req->hdr.id = OCTEP_CN20K_MBOX_CMD_VF_READY; > + req->hdr.sig = OCTEP_CN20K_MBOX_REQ_SIG; > + req->hdr.pcifunc = 0; > + > + return req; > +} > + > +static int > +otx_ep_cn20k_mbox_setup(struct otx_ep_cn20k_mbox_priv *mbox, int direction) > +{ > + switch (direction) { > + case MBOX_DIR_HOSTVF_HOSTPF: > + mbox->tx_start = CN20K_MBOX_DOWN_RX_START; > + mbox->tx_size = CN20K_MBOX_DOWN_RX_SIZE; > + mbox->rx_start = CN20K_MBOX_DOWN_TX_START; > + mbox->rx_size = CN20K_MBOX_DOWN_TX_SIZE; > + mbox->trigger = CN20K_SDP_RMT_VFX_MBOX_SEND_INT; > + break; > + case MBOX_DIR_HOSTVF_HOSTPF_UP: > + mbox->tx_start = CN20K_MBOX_UP_TX_START; > + mbox->tx_size = CN20K_MBOX_UP_TX_SIZE; > + mbox->rx_start = CN20K_MBOX_UP_RX_START; > + mbox->rx_size = CN20K_MBOX_UP_RX_SIZE; > + mbox->trigger = CN20K_SDP_RMT_VFX_MBOX_SEND_INT; > + break; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int > +otx_ep_cn20k_mbox_bbuf_init(struct otx_ep_cn20k_mbox *mbox_info) > +{ > + mbox_info->bbuf_base = rte_zmalloc("cn20k_mbox_bbuf", > CN20K_VF_MBOX_SIZE, > + RTE_CACHE_LINE_SIZE); > + if (!mbox_info->bbuf_base) > + return -ENOMEM; > + > + mbox_info->mbox.mbase = mbox_info->bbuf_base; > + mbox_info->mbox_up.mbase = mbox_info->bbuf_base; > + > + return 0; > +} > + > +static int > +otx_ep_cn20k_setup_mbox(struct otx_ep_device *otx_ep) > +{ > + struct otx_ep_cn20k_mbox *mbox_info; > + int ret; > + > + if (otx_ep->mbox_info) > + return 0; > + > + mbox_info = rte_zmalloc("otx_ep_mbox", sizeof(*mbox_info), > RTE_CACHE_LINE_SIZE); > + if (!mbox_info) { > + otx_ep_err("MBOX structure allocation failed"); > + return -ENOMEM; > + } > + > + mbox_info->otx_ep = otx_ep; > + mbox_info->mbox.otx_ep = otx_ep; > + otx_ep->mbox_info = mbox_info; > + mbox_info->mbox_up.otx_ep = otx_ep; > + > + ret = otx_ep_cn20k_mbox_setup(&mbox_info->mbox, > MBOX_DIR_HOSTVF_HOSTPF); > + if (ret) { > + otx_ep_err("Failed to setup downward mailbox"); > + goto free_mbox; > + } > + > + ret = otx_ep_cn20k_mbox_setup(&mbox_info->mbox_up, > MBOX_DIR_HOSTVF_HOSTPF_UP); > + if (ret) { > + otx_ep_err("Failed to setup upward mailbox"); > + goto free_mbox; > + } > + > + ret = otx_ep_cn20k_mbox_bbuf_init(mbox_info); > + if (ret) { > + otx_ep_err("Failed to init bounce buffer"); > + goto free_mbox; > + } > + > + mbox_info->mbox.hwbase = NULL; > + mbox_info->mbox_up.hwbase = NULL; > + > + otx_ep_dbg("CN20K VF mailbox initialized (CMD register based)"); > + > + return 0; > + > +free_mbox: > + rte_free(mbox_info); > + otx_ep->mbox_info = NULL; > + return ret; > +} > + > +static void > +otx_ep_cn20k_delete_mbox(struct otx_ep_device *otx_ep) > +{ > + struct otx_ep_cn20k_mbox *mbox_info = otx_ep->mbox_info; > + > + if (!mbox_info) > + return; > + > + if (mbox_info->bbuf_base) > + rte_free(mbox_info->bbuf_base); > + > + rte_free(mbox_info); > + otx_ep->mbox_info = NULL; > + > + otx_ep_dbg("CN20K VF mailbox cleaned up"); > +} > + > +int > +otx_ep_cn20k_mbox_send_cmd(struct otx_ep_device *otx_ep, union > otx_ep_mbox_word cmd, > + union otx_ep_mbox_word *rsp) > +{ > + struct otx_ep_cn20k_mbox *mbox_info = otx_ep->mbox_info; > + struct otx_ep_cn20k_mbox_priv *mbox; > + struct otx_ep_cn20k_mbox_msghdr *msghdr; > + union otx_ep_mbox_word *msg_data; > + int ret; > + > + if (!mbox_info) > + return -EINVAL; > + > + mbox = &mbox_info->mbox; > + > + mbox->msg_size = 0; > + mbox->rsp_size = 0; > + mbox->num_msgs = 0; > + mbox->msgs_acked = 0; > + > + msghdr = otx_ep_cn20k_mbox_alloc_msg(mbox, > + sizeof(struct > otx_ep_cn20k_mbox_msghdr) + sizeof(cmd), > + sizeof(struct > otx_ep_cn20k_mbox_msghdr) + > + sizeof(*rsp)); > + if (!msghdr) > + return -ENOMEM; > + > + msghdr->id = cmd.s.opcode; > + msghdr->sig = OCTEP_CN20K_MBOX_REQ_SIG; > + msghdr->ver = OCTEP_CN20K_MBOX_VERSION; > + msghdr->pcifunc = 0; > + > + msg_data = (union otx_ep_mbox_word *)(msghdr + 1); > + *msg_data = cmd; > + > + ret = otx_ep_cn20k_mbox_msg_send(mbox); > + if (ret) > + return ret; > + > + ret = otx_ep_cn20k_mbox_wait_for_rsp(mbox); > + if (ret) > + return ret; > + > + ret = otx_ep_cn20k_mbox_check_rsp_msgs(mbox); > + if (ret) > + return ret; > + > + msghdr = (struct otx_ep_cn20k_mbox_msghdr *)((uint8_t *)mbox->mbase + > mbox->rx_start + > + CN20K_MBOX_MSGS_OFFSET); > + msg_data = (union otx_ep_mbox_word *)(msghdr + 1); > + *rsp = *msg_data; > + > + if (msghdr->rc) { > + otx_ep_err("Mailbox command failed: rc=%d", msghdr->rc); > + return msghdr->rc; > + } > + > + return 0; > +} > + > +int > +otx_ep_cn20k_mbox_bulk_read(struct otx_ep_device *otx_ep, enum > otx_ep_mbox_opcode opcode, > + uint8_t *data, int32_t max_size, int32_t *size) > +{ > + union otx_ep_mbox_word cmd = {0}; > + union otx_ep_mbox_word rsp; > + int data_len, tmp_len, read_cnt, i, ret; > + > + if (!otx_ep->mbox_info || !data || !size || max_size <= 0) > + return -EINVAL; > + > + rte_spinlock_lock(&otx_ep->mbox_lock); > + > + cmd.s_data.opcode = opcode; > + cmd.s_data.frag = 0; > + ret = otx_ep_cn20k_mbox_send_cmd(otx_ep, cmd, &rsp); > + if (ret) { > + otx_ep_err("CN20K mbox bulk read request failed"); > + goto unlock; > + } > + > + memcpy(&data_len, rsp.s_data.data, sizeof(data_len)); > + tmp_len = data_len; > + if (data_len <= 0 || data_len > max_size) { > + otx_ep_err("CN20K mbox bulk read invalid length %d", > data_len); > + ret = -EINVAL; > + goto unlock; > + } > + > + otx_ep->mbox_data_index = 0; > + cmd.u64 = 0; > + cmd.s_data.opcode = opcode; > + cmd.s_data.frag = 1; > + while (data_len) { > + ret = otx_ep_cn20k_mbox_send_cmd(otx_ep, cmd, &rsp); > + if (ret) { > + otx_ep_err("CN20K mbox bulk read fragment failed"); > + otx_ep->mbox_data_index = 0; > + memset(otx_ep->mbox_data_buf, 0, > MBOX_MAX_DATA_BUF_SIZE); > + goto unlock; > + } > + if (data_len > OTX_EP_MBOX_MAX_DATA_SIZE) { > + data_len -= OTX_EP_MBOX_MAX_DATA_SIZE; > + read_cnt = OTX_EP_MBOX_MAX_DATA_SIZE; > + } else { > + read_cnt = data_len; > + data_len = 0; > + } > + if (otx_ep->mbox_data_index + read_cnt > > MBOX_MAX_DATA_BUF_SIZE) { > + otx_ep_err("CN20K mbox bulk read buffer overflow"); > + ret = -EINVAL; > + goto unlock; > + } > + for (i = 0; i < read_cnt; i++) { > + otx_ep->mbox_data_buf[otx_ep->mbox_data_index] = > + rsp.s_data.data[i]; > + otx_ep->mbox_data_index++; > + } > + cmd.u64 = 0; > + cmd.s_data.opcode = opcode; > + cmd.s_data.frag = 1; > + } > + > + memcpy(data, otx_ep->mbox_data_buf, tmp_len); > + *size = tmp_len; > + otx_ep->mbox_data_index = 0; > + memset(otx_ep->mbox_data_buf, 0, MBOX_MAX_DATA_BUF_SIZE); > + > +unlock: > + rte_spinlock_unlock(&otx_ep->mbox_lock); > + return ret; > +} > + > +static void > +otx_ep_cn20k_mbox_intr_handler(void *param) > +{ > + struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param; > + struct otx_ep_device *otx_ep = (struct otx_ep_device > *)eth_dev->data->dev_private; > + uint64_t intr_status; > + > + /* Read and clear interrupt */ > + intr_status = oct_ep_read64(otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RINT); > + if (intr_status & CN20K_MBOX_INTR) { > + /* Clear interrupt (W1C) */ > + oct_ep_write64(CN20K_MBOX_INTR, otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RINT); > + } > +} > + > +int > +otx_ep_cn20k_mbox_init(struct rte_eth_dev *eth_dev) > +{ > + struct rte_pci_device *pdev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pdev); > + struct otx_ep_device *otx_ep = eth_dev->data->dev_private; > + int rc; > + > + rc = otx_ep_cn20k_setup_mbox(otx_ep); > + if (rc) { > + otx_ep_err("Failed to setup CN20K PF-VF mailbox"); > + return rc; > + } > + > + rte_intr_callback_register(pdev->intr_handle, > otx_ep_cn20k_mbox_intr_handler, > + (void *)eth_dev); > + > + rc = rte_intr_enable(pdev->intr_handle); > + > + if (!(rc == -1 || rc == 0)) { > + otx_ep_err("rte_intr_enable failed"); > + return -1; > + } > + > + oct_ep_write64(CN20K_MBOX_INTR, otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RINT_ENA_W1S); > + > + otx_ep_dbg("CN20K mailbox initialized successfully"); > + > + return 0; > +} > + > +void > +otx_ep_cn20k_mbox_uninit(struct rte_eth_dev *eth_dev) > +{ > + struct rte_pci_device *pdev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pdev); > + struct otx_ep_device *otx_ep = eth_dev->data->dev_private; > + > + oct_ep_write64(CN20K_MBOX_INTR, otx_ep->hw_addr + > CN20K_SDP_RMT_VFX_MBOX_RINT_ENA_W1C); > + > + rte_intr_disable(pdev->intr_handle); > + rte_intr_callback_unregister(pdev->intr_handle, > otx_ep_cn20k_mbox_intr_handler, > + (void *)eth_dev); > + > + otx_ep_cn20k_delete_mbox(otx_ep); > +} > + > +int > +otx_ep_cn20k_mbox_send_ready(struct otx_ep_device *otx_ep) > +{ > + struct otx_ep_cn20k_mbox *cn20k_mbox; > + struct otx_ep_cn20k_mbox_priv *mbox; > + struct otx_ep_cn20k_ready_msg_req *req; > + struct otx_ep_cn20k_ready_msg_rsp *rsp; > + int ret; > + > + if (!otx_ep->mbox_info) { > + otx_ep_err("CN20K mailbox not initialized"); > + return -EINVAL; > + } > + > + cn20k_mbox = otx_ep->mbox_info; > + mbox = &cn20k_mbox->mbox; > + > + mbox->msg_size = 0; > + mbox->num_msgs = 0; > + mbox->msgs_acked = 0; > + > + req = otx_ep_cn20k_mbox_alloc_msg_ready(otx_ep); > + if (!req) { > + otx_ep_err("CN20K: Failed to allocate VF_READY message"); > + return -ENOMEM; > + } > + > + otx_ep_dbg("CN20K: Allocated VF_READY request (id=0x%x, sig=0x%x, > ver=0x%x)", req->hdr.id, > + req->hdr.sig, req->hdr.ver); > + > + ret = otx_ep_cn20k_mbox_msg_send(mbox); > + if (ret) { > + otx_ep_err("CN20K: Failed to send VF_READY request: %d", ret); > + return ret; > + } > + > + otx_ep_dbg("CN20K: VF_READY request sent to PF"); > + > + ret = otx_ep_cn20k_mbox_wait_for_rsp(mbox); > + if (ret) { > + otx_ep_err("CN20K: Timeout waiting for VF_READY response: > %d", ret); > + return ret; > + } > + > + ret = otx_ep_cn20k_mbox_check_rsp_msgs(mbox); > + if (ret) { > + otx_ep_err("CN20K: Failed to read VF_READY response: %d", > ret); > + return ret; > + } > + > + rsp = (struct otx_ep_cn20k_ready_msg_rsp *)((uint8_t *)mbox->mbase + > + mbox->rx_start + > CN20K_MBOX_MSGS_OFFSET); > + > + if (rsp->hdr.sig != OCTEP_CN20K_MBOX_RSP_SIG) { > + otx_ep_err("CN20K: Invalid VF_READY response signature: 0x%x > (expected 0x%x)", > + rsp->hdr.sig, OCTEP_CN20K_MBOX_RSP_SIG); > + return -EINVAL; > + } > + > + if (rsp->hdr.rc != 0) { > + otx_ep_err("CN20K: VF_READY rejected by PF: rc=%d", > rsp->hdr.rc); > + return rsp->hdr.rc; > + } > + > + otx_ep_dbg("CN20K: VF_READY acknowledged by PF (sig=0x%x, rc=%d)", > rsp->hdr.sig, > + rsp->hdr.rc); > + > + return 0; > +} > + > +int > +otx_ep_cn20k_mbox_alloc_sdp_rings(struct otx_ep_device *otx_ep, uint16_t > nr_rings) > +{ > + struct otx_ep_cn20k_mbox *cn20k_mbox = otx_ep->mbox_info; > + struct otx_ep_cn20k_mbox_priv *mbox; > + struct sdp_rings_alloc_req *req; > + struct sdp_rings_alloc_rsp *rsp; > + struct otx_ep_cn20k_mbox_msghdr *msghdr; > + int ret; > + > + if (!cn20k_mbox) { > + otx_ep_err("CN20K mailbox not initialized"); > + return -EINVAL; > + } > + > + if (nr_rings == 0) { > + otx_ep_err("Invalid nr_rings=0"); > + return -EINVAL; > + } > + > + mbox = &cn20k_mbox->mbox; > + > + mbox->msg_size = 0; > + mbox->rsp_size = 0; > + mbox->num_msgs = 0; > + mbox->msgs_acked = 0; > + > + req = otx_ep_cn20k_mbox_alloc_msg(mbox, sizeof(*req), sizeof(struct > sdp_rings_alloc_rsp)); > + if (!req) { > + otx_ep_err("Failed to allocate SDP_RING_ALLOC message"); > + return -ENOMEM; > + } > + > + req->hdr.id = MBOX_MSG_SDP_RING_ALLOC; > + req->hdr.sig = OCTEP_CN20K_MBOX_REQ_SIG; > + req->hdr.pcifunc = 0; > + req->nr_rings = nr_rings; > + memset(req->rsvd, 0, sizeof(req->rsvd)); > + > + otx_ep_dbg("VF requesting %u SDP rings from PF", nr_rings); > + > + ret = otx_ep_cn20k_mbox_msg_send(mbox); > + if (ret) { > + otx_ep_err("Failed to send SDP_RING_ALLOC message: %d", ret); > + return ret; > + } > + > + ret = otx_ep_cn20k_mbox_wait_for_rsp(mbox); > + if (ret) { > + otx_ep_err("Failed to get response: %d", ret); > + return ret; > + } > + > + msghdr = (struct otx_ep_cn20k_mbox_msghdr *)((uint8_t *)mbox->mbase + > + mbox->rx_start + > CN20K_MBOX_MSGS_OFFSET); > + if (msghdr->rc) { > + otx_ep_err("PF returned error for SDP_RING_ALLOC: %d", > msghdr->rc); > + return msghdr->rc; > + } > + > + rsp = (struct sdp_rings_alloc_rsp *)msghdr; > + > + if (rsp->count == 0) > + return -EIO; > + > + return rsp->count; > +} > + > +int > +otx_ep_cn20k_mbox_free_sdp_rings(struct otx_ep_device *otx_ep, uint16_t > ring, uint8_t all) > +{ > + struct otx_ep_cn20k_mbox *mbox_info = otx_ep->mbox_info; > + struct otx_ep_cn20k_mbox_msghdr *msghdr; > + struct otx_ep_cn20k_mbox_priv *mbox; > + struct sdp_rings_free_req *req; > + int ret; > + > + if (!mbox_info) { > + otx_ep_err("CN20K mailbox not initialized"); > + return -EINVAL; > + } > + > + mbox = &mbox_info->mbox; > + mbox->msg_size = 0; > + mbox->rsp_size = 0; > + mbox->num_msgs = 0; > + mbox->msgs_acked = 0; > + > + req = otx_ep_cn20k_mbox_alloc_msg(mbox, sizeof(*req), sizeof(struct > otx_ep_cn20k_msg_rsp)); > + if (!req) { > + otx_ep_err("Failed to allocate SDP_RING_FREE message"); > + return -ENOMEM; > + } > + > + req->hdr.id = MBOX_MSG_SDP_RING_FREE; > + req->hdr.sig = OCTEP_CN20K_MBOX_REQ_SIG; > + req->hdr.pcifunc = 0; > + req->ring = ring; > + req->all = all; > + > + if (all) > + otx_ep_dbg("VF requesting to free all SDP rings"); > + else > + otx_ep_dbg("VF requesting to free SDP ring %u", ring); > + > + ret = otx_ep_cn20k_mbox_msg_send(mbox); > + if (ret) { > + otx_ep_err("Failed to send SDP_RING_FREE message: %d", ret); > + return ret; > + } > + > + ret = otx_ep_cn20k_mbox_wait_for_rsp(mbox); > + if (ret) { > + otx_ep_err("Failed to get rsp for SDP_RING_FREE message: %d", > ret); > + return ret; > + } > + > + msghdr = (struct otx_ep_cn20k_mbox_msghdr *)((uint8_t *)mbox->mbase + > + mbox->rx_start + > CN20K_MBOX_MSGS_OFFSET); > + if (msghdr->rc) { > + otx_ep_err("PF returned error for SDP_RING_FREE: %d", > msghdr->rc); > + return msghdr->rc; > + } > + > + return 0; > +} > diff --git a/drivers/net/octeon_ep/cn20k_ep_mbox.h > b/drivers/net/octeon_ep/cn20k_ep_mbox.h > new file mode 100644 > index 0000000000..0d03978b2c > --- /dev/null > +++ b/drivers/net/octeon_ep/cn20k_ep_mbox.h > @@ -0,0 +1,133 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2026 Marvell. > + */ > + > +#ifndef _CN20K_EP_MBOX_H_ > +#define _CN20K_EP_MBOX_H_ > + > +#include <stdint.h> > + > +#include "otx_ep_mbox.h" > + > +struct otx_ep_device; > + > +/* CN20K-specific mailbox opcodes */ > +enum otx_ep_cn20k_mbox_opcode { > + OCTEP_CN20K_MBOX_CMD_VF_READY = 0x100, /* CN20K VF readiness > notification */ > +}; > + > +/* SDP mbox IDs */ > +#define MBOX_MSG_SDP_RING_ALLOC 0x1002 > +#define MBOX_MSG_SDP_RING_FREE 0x1003 > + > +/* Mailbox message header */ > +struct otx_ep_cn20k_mbox_msghdr { > + uint16_t pcifunc; /* VF/PF identifier */ > + uint16_t id; /* Message ID (opcode) */ > +#define OCTEP_CN20K_MBOX_REQ_SIG (0xdead) > +#define OCTEP_CN20K_MBOX_RSP_SIG (0xbeef) > + uint16_t sig; /* Signature for verification */ > +#define OCTEP_CN20K_MBOX_VERSION (0x000b) > + uint16_t ver; /* Mailbox version */ > + uint16_t next_msgoff; /* Offset to next message */ > + int rc; /* Return code */ > +}; > + > +/* Generic request msg used for those mbox messages which > + * don't send any data in the request. > + */ > +struct otx_ep_cn20k_msg_req { > + struct otx_ep_cn20k_mbox_msghdr hdr; > +}; > + > +/* Generic response msg used as ack or response for those mbox > + * messages which don't have a specific rsp msg format. > + */ > +struct otx_ep_cn20k_msg_rsp { > + struct otx_ep_cn20k_mbox_msghdr hdr; > +}; > + > +/* VF_READY request message (VF → PF) */ > +struct otx_ep_cn20k_ready_msg_req { > + struct otx_ep_cn20k_mbox_msghdr hdr; > +}; > + > +/* VF_READY response message (PF → VF) */ > +struct otx_ep_cn20k_ready_msg_rsp { > + struct otx_ep_cn20k_mbox_msghdr hdr; > +}; > + > +#define MBOX_MSG_ALIGN 16 > +#define MBOX_DOWN_MSG 1 > +#define MBOX_UP_MSG 2 > + > +/* Mailbox message header */ > +struct cn20k_mbox_hdr { > + uint64_t msg_size; > + uint16_t num_msgs; > + uint16_t opt_msg; > + uint16_t sig; > +}; > + > +enum cn20k_mbox_dir { > + MBOX_DIR_HOSTVF_HOSTPF = 0, > + MBOX_DIR_HOSTVF_HOSTPF_UP = 1, > +}; > + > +struct otx_ep_cn20k_mbox_priv { > + struct otx_ep_device *otx_ep; > + void *hwbase; > + void *mbase; > + uint64_t trigger; > + uint64_t rx_start; > + uint64_t tx_start; > + uint16_t rx_size; > + uint16_t tx_size; > + uint16_t msg_size; > + uint16_t rsp_size; > + uint16_t num_msgs; > + uint16_t msgs_acked; > +}; > + > +/* Main mailbox container for VF */ > +struct otx_ep_cn20k_mbox { > + struct otx_ep_cn20k_mbox_priv mbox; > + struct otx_ep_cn20k_mbox_priv mbox_up; > + struct otx_ep_device *otx_ep; > + void *bbuf_base; > + int num_msgs; > + int up_num_msgs; > +}; > + > +/* SDP Ring allocation/free structures (same as octeon_ep) */ > +struct sdp_rings_alloc_req { > + struct otx_ep_cn20k_mbox_msghdr hdr; > + uint16_t nr_rings; > + uint16_t rsvd[16]; /* Reserved */ > +}; > + > +struct sdp_rings_alloc_rsp { > + struct otx_ep_cn20k_mbox_msghdr hdr; > + uint16_t count; /* Number of rings allocated */ > + uint16_t rsvd[16]; /* Reserved */ > +}; > + > +struct sdp_rings_free_req { > + struct otx_ep_cn20k_mbox_msghdr hdr; > + uint16_t ring; > + uint8_t all; > +}; > + > +int otx_ep_cn20k_mbox_init(struct rte_eth_dev *eth_dev); > +void otx_ep_cn20k_mbox_uninit(struct rte_eth_dev *eth_dev); > + > +int otx_ep_cn20k_mbox_send_cmd(struct otx_ep_device *otx_ep, union > otx_ep_mbox_word cmd, > + union otx_ep_mbox_word *rsp); > +int otx_ep_cn20k_mbox_bulk_read(struct otx_ep_device *otx_ep, enum > otx_ep_mbox_opcode opcode, > + uint8_t *data, int32_t max_size, int32_t > *size); > + > +int otx_ep_cn20k_mbox_send_ready(struct otx_ep_device *otx_ep); > +int otx_ep_cn20k_mbox_alloc_sdp_rings(struct otx_ep_device *otx_ep, uint16_t > nr_rings); > +int otx_ep_cn20k_mbox_free_sdp_rings(struct otx_ep_device *otx_ep, uint16_t > ring, uint8_t all); > + > +#endif /* _CN20K_EP_MBOX_H_ */ > diff --git a/drivers/net/octeon_ep/cn20k_ep_vf.c > b/drivers/net/octeon_ep/cn20k_ep_vf.c > new file mode 100644 > index 0000000000..5c162de6fc > --- /dev/null > +++ b/drivers/net/octeon_ep/cn20k_ep_vf.c > @@ -0,0 +1,425 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2026 Marvell. > + */ > + > +#include <inttypes.h> > +#include <errno.h> > + > +#include <rte_common.h> > +#include <rte_cycles.h> > +#include <rte_memzone.h> > +#include "otx_ep_common.h" > +#include "cnxk_ep_vf.h" > +#include "cn20k_ep_vf.h" > + > +static void > +cn20k_ep_vf_setup_global_iq_reg(struct otx_ep_device *otx_ep, int q_no) > +{ > + volatile uint64_t reg_val = 0ull; > + > + /* Select ES, RO, NS, RDSIZE,DPTR Format#0 for IQs > + * IS_64B is by default enabled. > + */ > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_IN_CONTROL(q_no)); > + > + reg_val |= CNXK_EP_R_IN_CTL_RDSIZE; > + reg_val |= CNXK_EP_R_IN_CTL_IS_64B; > + reg_val |= CNXK_EP_R_IN_CTL_ESR; > + > + oct_ep_write64(reg_val, otx_ep->hw_addr + > CN20K_EP_R_IN_CONTROL(q_no)); > +} > + > +static void > +cn20k_ep_vf_setup_global_oq_reg(struct otx_ep_device *otx_ep, int q_no) > +{ > + volatile uint64_t reg_val = 0ull; > + > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_OUT_CONTROL(q_no)); > + > + reg_val &= ~(CNXK_EP_R_OUT_CTL_IMODE); > + reg_val &= ~(CNXK_EP_R_OUT_CTL_ROR_P); > + reg_val &= ~(CNXK_EP_R_OUT_CTL_NSR_P); > + reg_val &= ~(CNXK_EP_R_OUT_CTL_ROR_I); > + reg_val &= ~(CNXK_EP_R_OUT_CTL_NSR_I); > + reg_val &= ~(CNXK_EP_R_OUT_CTL_ROR_D); > + reg_val &= ~(CNXK_EP_R_OUT_CTL_NSR_D); > + reg_val &= ~(CNXK_EP_R_OUT_CTL_ES_I | CNXK_EP_R_OUT_CTL_ES_D); > + > + /* INFO/DATA ptr swap is required */ > + reg_val |= (CNXK_EP_R_OUT_CTL_ES_P); > + oct_ep_write64(reg_val, otx_ep->hw_addr + > CN20K_EP_R_OUT_CONTROL(q_no)); > +} > + > +static int > +cn20k_ep_vf_setup_global_input_regs(struct otx_ep_device *otx_ep) > +{ > + uint64_t q_no = 0ull; > + > + for (q_no = 0; q_no < (otx_ep->sriov_info.rings_per_vf); q_no++) > + cn20k_ep_vf_setup_global_iq_reg(otx_ep, q_no); > + return 0; > +} > + > +static int > +cn20k_ep_vf_setup_global_output_regs(struct otx_ep_device *otx_ep) > +{ > + uint32_t q_no; > + > + for (q_no = 0; q_no < (otx_ep->sriov_info.rings_per_vf); q_no++) > + cn20k_ep_vf_setup_global_oq_reg(otx_ep, q_no); > + return 0; > +} > + > +static int > +cn20k_ep_vf_setup_device_regs(struct otx_ep_device *otx_ep) > +{ > + int ret; > + > + ret = cn20k_ep_vf_setup_global_input_regs(otx_ep); > + if (ret) > + return ret; > + ret = cn20k_ep_vf_setup_global_output_regs(otx_ep); > + return ret; > +} > + > +static int > +cn20k_ep_vf_setup_iq_regs(struct otx_ep_device *otx_ep, uint32_t iq_no) > +{ > + struct otx_ep_instr_queue *iq = otx_ep->instr_queue[iq_no]; > + int loop = OTX_EP_BUSY_LOOP_COUNT; > + volatile uint64_t reg_val = 0ull; > + uint64_t ism_addr; > + > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_IN_CONTROL(iq_no)); > + > + /* Wait till IDLE to set to 1, not supposed to configure BADDR > + * as long as IDLE is 0 > + */ > + if (!(reg_val & CNXK_EP_R_IN_CTL_IDLE)) { > + do { > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_IN_CONTROL(iq_no)); > + rte_delay_ms(1); > + } while ((!(reg_val & CNXK_EP_R_IN_CTL_IDLE)) && loop--); > + } > + > + if (loop < 0) { > + otx_ep_err("IDLE bit is not set"); > + return -EIO; > + } > + > + /* Configure input queue instruction size. */ > + if (otx_ep->conf->iq.instr_type == OTX_EP_32BYTE_INSTR) > + reg_val &= ~(CNXK_EP_R_IN_CTL_IS_64B); > + else > + reg_val |= CNXK_EP_R_IN_CTL_IS_64B; > + oct_ep_write64(reg_val, otx_ep->hw_addr + > CN20K_EP_R_IN_CONTROL(iq_no)); > + iq->desc_size = otx_ep->conf->iq.instr_type; > + > + /* CN20X supports 16B instruction instead of 32B instruction */ > + if (otx_ep->chip_gen == OTX_EP_CN20XX && iq->desc_size == > OTX_EP_32BYTE_INSTR) > + iq->desc_size = OTX_EP_16BYTE_INSTR; > + > + /* Write the start of the input queue's ring and its size */ > + oct_ep_write64(iq->base_addr_dma, otx_ep->hw_addr + > CN20K_EP_R_IN_INSTR_BADDR(iq_no)); > + oct_ep_write64(iq->nb_desc, otx_ep->hw_addr + > CN20K_EP_R_IN_INSTR_RSIZE(iq_no)); > + > + /* Remember the doorbell & instruction count register addr > + * for this queue > + */ > + iq->doorbell_reg = (uint8_t *)otx_ep->hw_addr + > CN20K_EP_R_IN_INSTR_DBELL(iq_no); > + iq->inst_cnt_reg = (uint8_t *)otx_ep->hw_addr + > CN20K_EP_R_IN_CNTS(iq_no); > + > + otx_ep_dbg("InstQ[%d]:dbell reg @ 0x%p instcnt_reg @ 0x%p", > + iq_no, iq->doorbell_reg, iq->inst_cnt_reg); > + loop = OTX_EP_BUSY_LOOP_COUNT; > + do { > + reg_val = rte_read32(iq->inst_cnt_reg); > + rte_write32(reg_val, iq->inst_cnt_reg); > + rte_delay_ms(1); > + } while (reg_val != 0 && loop--); > + > + if (loop < 0) { > + otx_ep_err("INST CNT REGISTER is not zero"); > + return -EIO; > + } > + > + /* Clear the IQ doorbell */ > + loop = OTX_EP_BUSY_LOOP_COUNT; > + while ((rte_read64(iq->doorbell_reg) != 0ull) && loop--) { > + rte_write32(OTX_EP_CLEAR_INSTR_DBELL, iq->doorbell_reg); > + rte_delay_ms(1); > + } > + > + if (loop < 0) { > + otx_ep_err("INSTR DBELL is not zero"); > + return -EIO; > + } > + > + /* IN INTR_THRESHOLD is set to max(FFFFFFFF) which disable the IN INTR > + * to raise > + */ > + oct_ep_write64(OTX_EP_CLEAR_SDP_IN_INT_LVLS, > + otx_ep->hw_addr + CN20K_EP_R_IN_INT_LEVELS(iq_no)); > + /* Set up IQ ISM registers and structures */ > + ism_addr = (otx_ep->ism_buffer_mz->iova | CNXK_EP_ISM_EN > + | CNXK_EP_ISM_MSIX_DIS) > + + CNXK_EP_IQ_ISM_OFFSET(iq_no); > + rte_write64(ism_addr, (uint8_t *)otx_ep->hw_addr + > + CN20K_EP_R_IN_CNTS_ISM(iq_no)); > + iq->inst_cnt_ism = > + (uint32_t __rte_atomic *)((uint8_t > *)otx_ep->ism_buffer_mz->addr > + + CNXK_EP_IQ_ISM_OFFSET(iq_no)); > + otx_ep_dbg("SDP_R[%d] INST Q ISM virt: %p, dma: 0x%" PRIX64, iq_no, > + (void *)(uintptr_t)iq->inst_cnt_ism, ism_addr); > + *iq->inst_cnt_ism = 0; > + iq->inst_cnt_prev = 0; > + iq->partial_ih = ((uint64_t)otx_ep->pkind) << 36; > + > + return 0; > +} > + > +static int > +cn20k_ep_vf_setup_oq_regs(struct otx_ep_device *otx_ep, uint32_t oq_no) > +{ > + volatile uint64_t reg_val = 0ull; > + uint64_t oq_ctl = 0ull; > + int loop = OTX_EP_BUSY_LOOP_COUNT; > + struct otx_ep_droq *droq = otx_ep->droq[oq_no]; > + uint64_t ism_addr; > + > + /* Wait on IDLE to set to 1, supposed to configure BADDR > + * as long as IDLE is 0 > + */ > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_OUT_CONTROL(oq_no)); > + > + while ((!(reg_val & CNXK_EP_R_OUT_CTL_IDLE)) && loop--) { > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_OUT_CONTROL(oq_no)); > + rte_delay_ms(1); > + } > + > + if (loop < 0) { > + otx_ep_err("OUT CNT REGISTER value is zero"); > + return -EIO; > + } > + > + oct_ep_write64(droq->desc_ring_dma, otx_ep->hw_addr + > CN20K_EP_R_OUT_SLIST_BADDR(oq_no)); > + oct_ep_write64(droq->nb_desc, otx_ep->hw_addr + > CN20K_EP_R_OUT_SLIST_RSIZE(oq_no)); > + > + oq_ctl = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_OUT_CONTROL(oq_no)); > + > + /* Clear the ISIZE and BSIZE (22-0) */ > + oq_ctl &= ~(OTX_EP_CLEAR_ISIZE_BSIZE); > + > + /* Populate the BSIZE (15-0) */ > + oq_ctl |= (droq->buffer_size & OTX_EP_DROQ_BUFSZ_MASK); > + > + oct_ep_write64(oq_ctl, otx_ep->hw_addr + > CN20K_EP_R_OUT_CONTROL(oq_no)); > + > + /* Mapped address of the pkt_sent and pkts_credit regs */ > + droq->pkts_sent_reg = (uint8_t *)otx_ep->hw_addr + > CN20K_EP_R_OUT_CNTS(oq_no); > + droq->pkts_credit_reg = (uint8_t *)otx_ep->hw_addr + > CN20K_EP_R_OUT_SLIST_DBELL(oq_no); > + > + rte_write64(OTX_EP_CLEAR_OUT_INT_LVLS, otx_ep->hw_addr + > CN20K_EP_R_OUT_INT_LEVELS(oq_no)); > + > + /* Clear PKT_CNT register */ > + rte_write64(OTX_EP_CLEAR_SDP_OUT_PKT_CNT, (uint8_t *)otx_ep->hw_addr + > + CN20K_EP_R_OUT_PKT_CNT(oq_no)); > + > + /* Clear the OQ doorbell */ > + rte_write32(OTX_EP_CLEAR_SLIST_DBELL, droq->pkts_credit_reg); > + loop = OTX_EP_BUSY_LOOP_COUNT; > + while ((rte_read32(droq->pkts_credit_reg) != 0ull) && loop--) { > + rte_write32(OTX_EP_CLEAR_SLIST_DBELL, droq->pkts_credit_reg); > + rte_delay_ms(1); > + } > + > + if (loop < 0) { > + otx_ep_err("Packets credit register value is not cleared"); > + return -EIO; > + } > + > + otx_ep_dbg("SDP_R[%d]_credit:%x", oq_no, > rte_read32(droq->pkts_credit_reg)); > + > + /* Clear the OQ_OUT_CNTS doorbell */ > + reg_val = rte_read32(droq->pkts_sent_reg); > + rte_write32((uint32_t)reg_val, droq->pkts_sent_reg); > + > + otx_ep_dbg("SDP_R[%d]_sent: %x", oq_no, > rte_read32(droq->pkts_sent_reg)); > + /* Set up ISM registers and structures */ > + ism_addr = (otx_ep->ism_buffer_mz->iova | CNXK_EP_ISM_EN > + | CNXK_EP_ISM_MSIX_DIS) > + + CNXK_EP_OQ_ISM_OFFSET(oq_no); > + rte_write64(ism_addr, (uint8_t *)otx_ep->hw_addr + > + CN20K_EP_R_OUT_CNTS_ISM(oq_no)); > + droq->pkts_sent_ism = > + (uint32_t __rte_atomic *)((uint8_t > *)otx_ep->ism_buffer_mz->addr > + + CNXK_EP_OQ_ISM_OFFSET(oq_no)); > + otx_ep_dbg("SDP_R[%d] OQ ISM virt: %p dma: 0x%" PRIX64, oq_no, > + (void *)(uintptr_t)droq->pkts_sent_ism, ism_addr); > + *droq->pkts_sent_ism = 0; > + droq->pkts_sent_prev = 0; > + > + loop = OTX_EP_BUSY_LOOP_COUNT; > + while (((rte_read32(droq->pkts_sent_reg)) != 0ull) && loop--) { > + reg_val = rte_read32(droq->pkts_sent_reg); > + rte_write32((uint32_t)reg_val, droq->pkts_sent_reg); > + rte_delay_ms(1); > + } > + > + if (loop < 0) { > + otx_ep_err("Packets sent register value is not cleared"); > + return -EIO; > + } > + > + otx_ep_dbg("SDP_R[%d]_sent: %x", oq_no, > rte_read32(droq->pkts_sent_reg)); > + > + /* Set Watermark for backpressure */ > + oct_ep_write64(OTX_EP_OQ_WMARK_MIN, > + otx_ep->hw_addr + CN20K_EP_R_OUT_WMARK(oq_no)); > + > + return 0; > +} > + > +static int > +cn20k_ep_vf_enable_iq(struct otx_ep_device *otx_ep, uint32_t q_no) > +{ > + uint64_t reg_val = 0ull; > + > + reg_val = oct_ep_read64(otx_ep->hw_addr + CN20K_EP_R_IN_ENABLE(q_no)); > + reg_val |= 0x1ull; > + > + oct_ep_write64(reg_val, otx_ep->hw_addr + CN20K_EP_R_IN_ENABLE(q_no)); > + > + otx_ep_info("IQ[%d] enable done", q_no); > + > + return 0; > +} > + > +static int > +cn20k_ep_vf_enable_oq(struct otx_ep_device *otx_ep, uint32_t q_no) > +{ > + uint64_t reg_val = 0ull; > + > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_OUT_ENABLE(q_no)); > + reg_val |= 0x1ull; > + oct_ep_write64(reg_val, otx_ep->hw_addr + > CN20K_EP_R_OUT_ENABLE(q_no)); > + > + otx_ep_info("OQ[%d] enable done", q_no); > + > + return 0; > +} > + > +static int > +cn20k_ep_vf_enable_io_queues(struct otx_ep_device *otx_ep) > +{ > + uint32_t q_no = 0; > + int ret; > + > + for (q_no = 0; q_no < otx_ep->nb_tx_queues; q_no++) { > + ret = cn20k_ep_vf_enable_iq(otx_ep, q_no); > + if (ret) > + return ret; > + } > + > + for (q_no = 0; q_no < otx_ep->nb_rx_queues; q_no++) > + cn20k_ep_vf_enable_oq(otx_ep, q_no); > + > + return 0; > +} > + > +static void > +cn20k_ep_vf_disable_iq(struct otx_ep_device *otx_ep, uint32_t q_no) > +{ > + uint64_t reg_val = 0ull; > + > + /* Reset the doorbell register for this Input Queue. */ > + reg_val = oct_ep_read64(otx_ep->hw_addr + CN20K_EP_R_IN_ENABLE(q_no)); > + reg_val &= ~0x1ull; > + > + oct_ep_write64(reg_val, otx_ep->hw_addr + CN20K_EP_R_IN_ENABLE(q_no)); > +} > + > +static void > +cn20k_ep_vf_disable_oq(struct otx_ep_device *otx_ep, uint32_t q_no) > +{ > + volatile uint64_t reg_val = 0ull; > + > + reg_val = oct_ep_read64(otx_ep->hw_addr + > CN20K_EP_R_OUT_ENABLE(q_no)); > + reg_val &= ~0x1ull; > + > + oct_ep_write64(reg_val, otx_ep->hw_addr + > CN20K_EP_R_OUT_ENABLE(q_no)); > +} > + > +static void > +cn20k_ep_vf_disable_io_queues(struct otx_ep_device *otx_ep) > +{ > + uint32_t q_no = 0; > + > + for (q_no = 0; q_no < otx_ep->sriov_info.rings_per_vf; q_no++) { > + cn20k_ep_vf_disable_iq(otx_ep, q_no); > + cn20k_ep_vf_disable_oq(otx_ep, q_no); > + } > +} > + > +static const struct otx_ep_config default_cnxk_ep_conf = { > + /* IQ attributes */ > + .iq = { > + .max_iqs = OTX_EP_CFG_IO_QUEUES, > + .instr_type = OTX_EP_32BYTE_INSTR, > + .pending_list_size = (OTX_EP_MAX_IQ_DESCRIPTORS * > + OTX_EP_CFG_IO_QUEUES), > + }, > + > + /* OQ attributes */ > + .oq = { > + .max_oqs = OTX_EP_CFG_IO_QUEUES, > + .info_ptr = OTX_EP_OQ_INFOPTR_MODE, > + .refill_threshold = OTX_EP_OQ_REFIL_THRESHOLD, > + }, > + > + .num_iqdef_descs = OTX_EP_MAX_IQ_DESCRIPTORS, > + .num_oqdef_descs = OTX_EP_MAX_OQ_DESCRIPTORS, > + .oqdef_buf_size = OTX_EP_OQ_BUF_SIZE, > +}; > + > +static const struct otx_ep_config* > +cn20k_ep_get_defconf(struct otx_ep_device *otx_ep_dev __rte_unused) > +{ > + const struct otx_ep_config *default_conf = NULL; > + > + default_conf = &default_cnxk_ep_conf; > + > + return default_conf; > +} > + > +int > +cn20k_ep_vf_setup_device(struct otx_ep_device *otx_ep) > +{ > + /* If application does not provide its conf, use driver default conf > */ > + if (!otx_ep->conf) { > + otx_ep->conf = cn20k_ep_get_defconf(otx_ep); > + if (!otx_ep->conf) { > + otx_ep_err("SDP VF default config not found"); > + return -ENOENT; > + } > + otx_ep_info("Default config is used"); > + } > + > + otx_ep_info("SDP RPVF: %d", otx_ep->sriov_info.rings_per_vf); > + > + otx_ep->fn_list.setup_iq_regs = cn20k_ep_vf_setup_iq_regs; > + otx_ep->fn_list.setup_oq_regs = cn20k_ep_vf_setup_oq_regs; > + > + otx_ep->fn_list.setup_device_regs = cn20k_ep_vf_setup_device_regs; > + > + otx_ep->fn_list.enable_io_queues = cn20k_ep_vf_enable_io_queues; > + otx_ep->fn_list.disable_io_queues = cn20k_ep_vf_disable_io_queues; > + > + otx_ep->fn_list.enable_iq = cn20k_ep_vf_enable_iq; > + otx_ep->fn_list.disable_iq = cn20k_ep_vf_disable_iq; > + > + otx_ep->fn_list.enable_oq = cn20k_ep_vf_enable_oq; > + otx_ep->fn_list.disable_oq = cn20k_ep_vf_disable_oq; > + > + return 0; > +} > diff --git a/drivers/net/octeon_ep/cn20k_ep_vf.h > b/drivers/net/octeon_ep/cn20k_ep_vf.h > new file mode 100644 > index 0000000000..6342b885ec > --- /dev/null > +++ b/drivers/net/octeon_ep/cn20k_ep_vf.h > @@ -0,0 +1,175 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2026 Marvell. > + */ > +#ifndef _CN20K_EP_VF_H_ > +#define _CN20K_EP_VF_H_ > + > +#include <rte_io.h> > +#include <rte_bitops.h> > + > +#include "otx_ep_common.h" > + > +#define CN20K_MAX_RINGS_PER_VF (8) > + > +#define CN20K_EP_R_IN_CONTROL_START 0x40000 > +#define CN20K_EP_R_IN_ENABLE_START 0x40008 > +#define CN20K_EP_R_IN_INSTR_BADDR_START 0x40010 > +#define CN20K_EP_R_IN_INSTR_RSIZE_START 0x40018 > +#define CN20K_EP_R_IN_INSTR_DBELL_START 0x40020 > +#define CN20K_EP_R_IN_CNTS_START 0x40030 > +#define CN20K_EP_R_IN_INT_LEVELS_START 0x40040 > +#define CN20K_EP_R_IN_CNTS_ISM_START 0x40050 > +#define CN20K_EP_R_IN_PKT_CNT_START 0x40460 > +#define CN20K_EP_R_IN_BYTE_CNT_START 0x40470 > +#define CN20K_EP_R_ERR_TYPE_START 0x10400 > + > +#define CN20K_EP_RING_OFFSET (0x1ULL << 12) > + > +#define CN20K_EP_R_ERR_TYPE(ring) \ > + (CN20K_EP_R_ERR_TYPE_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_CONTROL(ring) \ > + (CN20K_EP_R_IN_CONTROL_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_ENABLE(ring) \ > + (CN20K_EP_R_IN_ENABLE_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_INSTR_BADDR(ring) \ > + (CN20K_EP_R_IN_INSTR_BADDR_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_INSTR_RSIZE(ring) \ > + (CN20K_EP_R_IN_INSTR_RSIZE_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_INSTR_DBELL(ring) \ > + (CN20K_EP_R_IN_INSTR_DBELL_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_CNTS(ring) \ > + (CN20K_EP_R_IN_CNTS_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_INT_LEVELS(ring) \ > + (CN20K_EP_R_IN_INT_LEVELS_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_IN_CNTS_ISM(ring) \ > + (CN20K_EP_R_IN_CNTS_ISM_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_CNTS_START 0x40130 > +#define CN20K_EP_R_OUT_INT_LEVELS_START 0x40140 > +#define CN20K_EP_R_OUT_CNTS_ISM_START 0x40150 > +#define CN20K_EP_R_OUT_SLIST_BADDR_START 0x40110 > +#define CN20K_EP_R_OUT_SLIST_RSIZE_START 0x40118 > +#define CN20K_EP_R_OUT_SLIST_DBELL_START 0x40120 > +#define CN20K_EP_R_OUT_CONTROL_START 0x40100 > +#define CN20K_EP_R_OUT_WMARK_START 0x40128 > +#define CN20K_EP_R_OUT_ENABLE_START 0x40108 > +#define CN20K_EP_R_OUT_PKT_CNT_START 0x40560 > +#define CN20K_EP_R_OUT_BYTE_CNT_START 0x40570 > + > +#define CN20K_EP_R_OUT_CONTROL(ring) \ > + (CN20K_EP_R_OUT_CONTROL_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_ENABLE(ring) \ > + (CN20K_EP_R_OUT_ENABLE_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_SLIST_BADDR(ring) \ > + (CN20K_EP_R_OUT_SLIST_BADDR_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_SLIST_RSIZE(ring) \ > + (CN20K_EP_R_OUT_SLIST_RSIZE_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_SLIST_DBELL(ring) \ > + (CN20K_EP_R_OUT_SLIST_DBELL_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_WMARK(ring) \ > + (CN20K_EP_R_OUT_WMARK_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_CNTS(ring) \ > + (CN20K_EP_R_OUT_CNTS_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_INT_LEVELS(ring) \ > + (CN20K_EP_R_OUT_INT_LEVELS_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_CNTS_ISM(ring) \ > + (CN20K_EP_R_OUT_CNTS_ISM_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_PKT_CNT(ring) \ > + (CN20K_EP_R_OUT_PKT_CNT_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define CN20K_EP_R_OUT_BYTE_CNT(ring) \ > + (CN20K_EP_R_OUT_BYTE_CNT_START + ((ring) * CN20K_EP_RING_OFFSET)) > + > +#define PCI_DEVID_CN20KA_EP_NET_VF 0xC203 > +#define PCI_DEVID_CNF20KA_EP_NET_VF 0xCA03 > + > +#ifndef BIT_ULL > +#define BIT_ULL(n) RTE_BIT64(n) > +#endif > + > +int > +cn20k_ep_vf_setup_device(struct otx_ep_device *sdpvf); > + > +/* ##################### CN20K Mailbox Registers ########################## > */ > +/* CN20K uses a completely different mailbox architecture compared to > CN9X/CN10X > + * - Uses command/data/control register interface > + * - Shared DMA memory buffer (allocated by PF in system RAM) > + * - VF accesses via indirect CMD registers with offset/data/control > + * - PF accesses directly via pointers to DMA memory > + */ > + > +/* VF Write Command Registers - for VF_PF communication */ > +#define CN20K_SDP_RMT_VFX_MBOX_WR_CMD_CTL 0x24040 > +#define CN20K_SDP_RMT_VFX_MBOX_WR_CMD_OFFSET 0x24048 > +#define CN20K_SDP_RMT_VFX_MBOX_WR_CMD_DATA 0x24050 > + > +/* VF Read Command Registers - for PF_VF communication */ > +#define CN20K_SDP_RMT_VFX_MBOX_RD_CMD_CTL 0x24060 > +#define CN20K_SDP_RMT_VFX_MBOX_RD_CMD_OFFSET 0x24068 > +#define CN20K_SDP_RMT_VFX_MBOX_RD_CMD_DATA 0x24070 > + > +/* VF Mailbox Interrupt Registers */ > +#define CN20K_SDP_RMT_VFX_MBOX_RINT 0x24020 > +#define CN20K_SDP_RMT_VFX_MBOX_RINT_W1S 0x24028 > +#define CN20K_SDP_RMT_VFX_MBOX_RINT_ENA_W1C 0x24030 > +#define CN20K_SDP_RMT_VFX_MBOX_RINT_ENA_W1S 0x24038 > + > +/* VF Send Interrupt to PF */ > +#define CN20K_SDP_RMT_VFX_MBOX_SEND_INT 0x24000 > + > +/* Direct Mailbox Data Access (8K registers * 8 bytes = 64KB) */ > +#define CN20K_SDP_RMT_VFX_MBOX_DATA_START 0x30000 > +#define CN20K_SDP_RMT_VFX_MBOX_DATA(offset) \ > + (CN20K_SDP_RMT_VFX_MBOX_DATA_START + ((offset) * 8)) > + > +/* Command Control Bit Definitions */ > +#define CN20K_MBOX_WR_CMD_DONE BIT_ULL(0) > +#define CN20K_MBOX_WR_CMD_ERR BIT_ULL(1) > +#define CN20K_MBOX_WR_CMD_OUT BIT_ULL(2) > +#define CN20K_MBOX_WR_COMMIT BIT_ULL(3) > +#define CN20K_MBOX_WR_DROP BIT_ULL(4) > + > +#define CN20K_MBOX_RD_CMD_DONE BIT_ULL(0) > +#define CN20K_MBOX_RD_CMD_ERR BIT_ULL(1) > +#define CN20K_MBOX_RD_CMD_OUT BIT_ULL(2) > + > +/* Mailbox Interrupt Bits */ > +#define CN20K_MBOX_INTR BIT_ULL(0) > + > +/* Mailbox Memory Layout (64KB per VF, same as PFAF) */ > +#define CN20K_VF_MBOX_SIZE (64 * 1024) > +#define CN20K_MBOX_DOWN_RX_START 0 > +#define CN20K_MBOX_DOWN_RX_SIZE (46 * 1024) > +#define CN20K_MBOX_DOWN_TX_START (CN20K_MBOX_DOWN_RX_START + > CN20K_MBOX_DOWN_RX_SIZE) > +#define CN20K_MBOX_DOWN_TX_SIZE (16 * 1024) > +#define CN20K_MBOX_UP_RX_START (CN20K_MBOX_DOWN_TX_START + > CN20K_MBOX_DOWN_TX_SIZE) > +#define CN20K_MBOX_UP_RX_SIZE (1 * 1024) > +#define CN20K_MBOX_UP_TX_START (CN20K_MBOX_UP_RX_START + > CN20K_MBOX_UP_RX_SIZE) > +#define CN20K_MBOX_UP_TX_SIZE (1 * 1024) > + > +/* Non-IOQ Interrupt Configuration */ > +#define CN20K_VF_NUM_NON_IOQ_INTR 16 /* Vectors 0-15 for non-IOQ > (control path) */ > +#define CN20K_VF_IOQ_INTR_BASE 16 /* IOQ interrupts start at vector > 16 (data path) */ > + > +/* Non-IOQ Interrupt Vector Assignments */ > +#define CN20K_VF_NON_IOQ_INTR_MBOX 0 /* Vector 0: Mailbox (control > path) */ > +/* Vectors 1-15: Reserved for other non-IOQ interrupts (errors, etc.) */ > + > +#endif /*_CN20K_EP_VF_H_ */ > diff --git a/drivers/net/octeon_ep/cnxk_ep_rx.c > b/drivers/net/octeon_ep/cnxk_ep_rx.c > index 9678cec90b..f9bfffe759 100644 > --- a/drivers/net/octeon_ep/cnxk_ep_rx.c > +++ b/drivers/net/octeon_ep/cnxk_ep_rx.c > @@ -8,56 +8,94 @@ static __rte_always_inline void > cnxk_ep_process_pkts_scalar_mseg(struct rte_mbuf **rx_pkts, struct > otx_ep_droq *droq, > uint16_t new_pkts) > { > + struct otx_ep_droq_desc *desc_ring = droq->desc_ring; > struct rte_mbuf **recv_buf_list = droq->recv_buf_list; > uint32_t total_pkt_len, bytes_rsvd = 0; > uint16_t nb_desc = droq->nb_desc; > uint16_t pkts; > > for (pkts = 0; pkts < new_pkts; pkts++) { > + union cn20k_ep_rx_compl_t compl; > struct otx_ep_droq_info *info; > struct rte_mbuf *first_buf = NULL; > struct rte_mbuf *last_buf = NULL; > struct rte_mbuf *mbuf; > - uint32_t pkt_len = 0; > + uint32_t i, pkt_len = 0; > > mbuf = recv_buf_list[droq->read_idx]; > - info = cnxk_pktmbuf_mtod(mbuf, struct otx_ep_droq_info *); > > - total_pkt_len = rte_bswap16(info->length >> 48) + > OTX_EP_INFO_SIZE; > + if (droq->chip_gen == OTX_EP_CN20XX) { > + uint32_t num_bufs; > > - while (pkt_len < total_pkt_len) { > - int cpy_len; > + compl.u = > rte_bswap64(desc_ring[droq->read_idx].info_ptr); > + num_bufs = compl.s.num_buf; > > - cpy_len = ((pkt_len + droq->buffer_size) > > total_pkt_len) > - ? ((uint32_t)total_pkt_len - pkt_len) > : droq->buffer_size; > + first_buf = mbuf; > + *(uint64_t *)&first_buf->rearm_data = > droq->rearm_data; > + first_buf->pkt_len = compl.s.pkt_len; > + first_buf->nb_segs = num_bufs; > > - mbuf = droq->recv_buf_list[droq->read_idx]; > + first_buf->data_len = droq->buffer_size; > + last_buf = first_buf; > > - if (!pkt_len) { > - /* Note the first seg */ > - first_buf = mbuf; > - *(uint64_t *)&mbuf->rearm_data = > droq->rearm_data; > - mbuf->pkt_len = cpy_len - OTX_EP_INFO_SIZE; > - mbuf->data_len = cpy_len - OTX_EP_INFO_SIZE; > - } else { > - mbuf->pkt_len = cpy_len; > - mbuf->data_len = cpy_len; > - first_buf->nb_segs++; > - first_buf->pkt_len += mbuf->pkt_len; > - } > + for (i = 1; i < num_bufs; i++) { > + droq->read_idx = > otx_ep_incr_index(droq->read_idx, 1, > + nb_desc); > + mbuf = recv_buf_list[droq->read_idx]; > + if (unlikely(!mbuf)) > + break; > > - if (last_buf) > - last_buf->next = mbuf; > + if (i == (num_bufs - 1)) > + mbuf->data_len = compl.s.last_buf_len; > + else > + mbuf->data_len = droq->buffer_size; > > - last_buf = mbuf; > + last_buf->next = mbuf; > + last_buf = mbuf; > + } > + last_buf->next = NULL; > > - pkt_len += cpy_len; > droq->read_idx = otx_ep_incr_index(droq->read_idx, 1, > nb_desc); > - droq->refill_count++; > + droq->refill_count += num_bufs; > + } else { > + info = rte_pktmbuf_mtod(mbuf, struct otx_ep_droq_info > *); > + total_pkt_len = rte_bswap16(info->length >> 48) + > OTX_EP_INFO_SIZE; > + > + while (pkt_len < total_pkt_len) { > + int cpy_len; > + > + cpy_len = ((pkt_len + droq->buffer_size) > > total_pkt_len) > + ? ((uint32_t)total_pkt_len - > pkt_len) : > + droq->buffer_size; > + > + mbuf = droq->recv_buf_list[droq->read_idx]; > + > + if (!pkt_len) { > + /* Note the first seg */ > + first_buf = mbuf; > + mbuf->data_off += OTX_EP_INFO_SIZE; > + mbuf->pkt_len = cpy_len - > OTX_EP_INFO_SIZE; > + mbuf->data_len = cpy_len - > OTX_EP_INFO_SIZE; > + } else { > + mbuf->pkt_len = cpy_len; > + mbuf->data_len = cpy_len; > + first_buf->nb_segs++; > + first_buf->pkt_len += mbuf->pkt_len; > + } > + > + if (last_buf) > + last_buf->next = mbuf; > + > + last_buf = mbuf; > + > + pkt_len += cpy_len; > + droq->read_idx = > otx_ep_incr_index(droq->read_idx, 1, nb_desc); > + droq->refill_count++; > + } > } > mbuf = first_buf; > rx_pkts[pkts] = mbuf; > - bytes_rsvd += pkt_len; > + bytes_rsvd += mbuf->pkt_len; > } > > droq->pkts_pending -= pkts; > diff --git a/drivers/net/octeon_ep/cnxk_ep_rx.h > b/drivers/net/octeon_ep/cnxk_ep_rx.h > index 5db32c4448..c06e9d858c 100644 > --- a/drivers/net/octeon_ep/cnxk_ep_rx.h > +++ b/drivers/net/octeon_ep/cnxk_ep_rx.h > @@ -11,6 +11,18 @@ > #define CNXK_EP_OQ_DESC_PER_LOOP_SSE 4 > #define CNXK_EP_OQ_DESC_PER_LOOP_AVX 8 > > +union cn20k_ep_rx_compl_t { > + uint64_t u; > + struct cn20k_ep_rx_compl_s { > + uint64_t pkt_len : 16; > + uint64_t last_buf_len : 16; > + uint64_t num_buf : 10; > + uint64_t rsvd : 20; > + uint64_t ptp : 1; > + uint64_t done : 1; > + } s; > +}; > + > static inline int > cnxk_ep_rx_refill_mbuf(struct otx_ep_droq *droq, uint32_t count) > { > @@ -32,7 +44,10 @@ cnxk_ep_rx_refill_mbuf(struct otx_ep_droq *droq, uint32_t > count) > if (i < count - 1) > rte_prefetch_non_temporal(recv_buf_list[refill_idx + > 1]); > buf = recv_buf_list[refill_idx]; > + > desc_ring[refill_idx].buffer_ptr = > rte_mbuf_data_iova_default(buf); > + if (droq->chip_gen == OTX_EP_CN20XX) > + desc_ring[refill_idx].info_ptr = 0; > refill_idx++; > } > > @@ -164,12 +179,14 @@ cnxk_ep_rx_pkts_to_process(struct otx_ep_droq *droq, > uint16_t nb_pkts) > static __rte_always_inline void > cnxk_ep_process_pkts_scalar(struct rte_mbuf **rx_pkts, struct otx_ep_droq > *droq, uint16_t new_pkts) > { > + struct otx_ep_droq_desc *desc_ring = droq->desc_ring; > struct rte_mbuf **recv_buf_list = droq->recv_buf_list; > uint32_t bytes_rsvd = 0, read_idx = droq->read_idx; > uint16_t nb_desc = droq->nb_desc; > uint16_t pkts; > > for (pkts = 0; pkts < new_pkts; pkts++) { > + union cn20k_ep_rx_compl_t compl; > struct otx_ep_droq_info *info; > struct rte_mbuf *mbuf; > uint16_t pkt_len; > @@ -180,9 +197,15 @@ cnxk_ep_process_pkts_scalar(struct rte_mbuf **rx_pkts, > struct otx_ep_droq *droq, > void *)); > > mbuf = recv_buf_list[read_idx]; > - info = cnxk_pktmbuf_mtod(mbuf, struct otx_ep_droq_info *); > - read_idx = otx_ep_incr_index(read_idx, 1, nb_desc); > - pkt_len = rte_bswap16(info->length >> 48); > + if (droq->chip_gen == OTX_EP_CN20XX) { > + compl.u = rte_bswap64(desc_ring[read_idx].info_ptr); > + pkt_len = compl.s.pkt_len; > + read_idx = otx_ep_incr_index(read_idx, 1, nb_desc); > + } else { > + info = cnxk_pktmbuf_mtod(mbuf, struct > otx_ep_droq_info *); > + read_idx = otx_ep_incr_index(read_idx, 1, nb_desc); > + pkt_len = rte_bswap16(info->length >> 48); > + } > mbuf->pkt_len = pkt_len; > mbuf->data_len = pkt_len; > > diff --git a/drivers/net/octeon_ep/cnxk_ep_rx_avx.c > b/drivers/net/octeon_ep/cnxk_ep_rx_avx.c > index 47eb1d2ef7..37b613dbf5 100644 > --- a/drivers/net/octeon_ep/cnxk_ep_rx_avx.c > +++ b/drivers/net/octeon_ep/cnxk_ep_rx_avx.c > @@ -7,6 +7,7 @@ > static __rte_always_inline void > cnxk_ep_process_pkts_vec_avx(struct rte_mbuf **rx_pkts, struct otx_ep_droq > *droq, uint16_t new_pkts) > { > + struct otx_ep_droq_desc *desc_ring = droq->desc_ring; > struct rte_mbuf **recv_buf_list = droq->recv_buf_list; > uint32_t bytes_rsvd = 0, read_idx = droq->read_idx; > const uint64_t rearm_data = droq->rearm_data; > @@ -25,6 +26,11 @@ cnxk_ep_process_pkts_vec_avx(struct rte_mbuf **rx_pkts, > struct otx_ep_droq *droq > _mm256_set_epi8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, > 20, 21, 0xFF, 0xFF, 20, > 21, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, > 0xFF, 0xFF, 0xFF, 0xFF, > 0xFF, 0xFF, 0xFF, 7, 6, 5, 4, 3, 2, > 1, 0); > + const __m256i mask1 = > + _mm256_set_epi8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, > 25, 24, 0xFF, 0xFF, 25, > + 24, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, > 0xFF, 0xFF, 0xFF, 0xFF, > + 0xFF, 0xFF, 0xFF, 7, 6, 5, 4, 3, 2, > 1, 0); > + > > /* Load indexes. */ > for (i = 1; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) > @@ -46,16 +52,28 @@ cnxk_ep_process_pkts_vec_avx(struct rte_mbuf **rx_pkts, > struct otx_ep_droq *droq > for (i = 0; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) > m[i] = recv_buf_list[idx[i]]; > > - /* Load rearm data and packet length for shuffle. */ > - for (i = 0; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) > - data[i] = _mm256_set_epi64x(0, > - cnxk_pktmbuf_mtod(m[i], struct > otx_ep_droq_info *)->length >> 16, > - 0, rearm_data); > - > - /* Shuffle data to its place and sum the packet length. */ > - for (i = 0; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) { > - data[i] = _mm256_shuffle_epi8(data[i], mask); > - bytes_rsvd += _mm256_extract_epi16(data[i], 10); > + if (droq->chip_gen == OTX_EP_CN20XX) { > + for (i = 0; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) > + data[i] = > _mm256_set_epi64x(rte_bswap64(desc_ring[idx[i]].info_ptr), > + 0, 0, rearm_data); > + > + for (i = 0; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) { > + data[i] = _mm256_shuffle_epi8(data[i], mask1); > + bytes_rsvd += _mm256_extract_epi16(data[i], > 10); > + } > + } else { > + uint64_t len; > + /* Load rearm data and packet length for shuffle. */ > + for (i = 0; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) { > + len = cnxk_pktmbuf_mtod(m[i], struct > otx_ep_droq_info *)->length; > + data[i] = _mm256_set_epi64x(0, len >> 16, 0, > rearm_data); > + } > + > + /* Shuffle data to its place and sum the packet > length. */ > + for (i = 0; i < CNXK_EP_OQ_DESC_PER_LOOP_AVX; i++) { > + data[i] = _mm256_shuffle_epi8(data[i], mask); > + bytes_rsvd += _mm256_extract_epi16(data[i], > 10); > + } > } > > /* Store the 256bit data to the mbuf. */ > diff --git a/drivers/net/octeon_ep/cnxk_ep_rx_neon.c > b/drivers/net/octeon_ep/cnxk_ep_rx_neon.c > index 2cb5cf4ad8..4b9792c261 100644 > --- a/drivers/net/octeon_ep/cnxk_ep_rx_neon.c > +++ b/drivers/net/octeon_ep/cnxk_ep_rx_neon.c > @@ -12,6 +12,7 @@ cnxk_ep_process_pkts_vec_neon(struct rte_mbuf **rx_pkts, > struct otx_ep_droq *dro > 4, 5, 0xff, 0xff, 4, 5, 0xff, 0xff}; > const uint8x16_t mask1 = {8, 9, 0xff, 0xff, 8, 9, 0xff, 0xff, > 12, 13, 0xff, 0xff, 12, 13, 0xff, 0xff}; > + struct otx_ep_droq_desc *desc_ring = droq->desc_ring; > struct rte_mbuf **recv_buf_list = droq->recv_buf_list; > uint32_t pidx0, pidx1, pidx2, pidx3; > struct rte_mbuf *m0, *m1, *m2, *m3; > @@ -47,29 +48,53 @@ cnxk_ep_process_pkts_vec_neon(struct rte_mbuf **rx_pkts, > struct otx_ep_droq *dro > m2 = recv_buf_list[idx2]; > m3 = recv_buf_list[idx3]; > > - /* Load packet size big-endian. */ > - s01 = vsetq_lane_u32(cnxk_pktmbuf_mtod(m0, struct > otx_ep_droq_info *)->length >> 48, > - s01, 0); > - s01 = vsetq_lane_u32(cnxk_pktmbuf_mtod(m1, struct > otx_ep_droq_info *)->length >> 48, > - s01, 1); > - s01 = vsetq_lane_u32(cnxk_pktmbuf_mtod(m2, struct > otx_ep_droq_info *)->length >> 48, > - s01, 2); > - s01 = vsetq_lane_u32(cnxk_pktmbuf_mtod(m3, struct > otx_ep_droq_info *)->length >> 48, > - s01, 3); > - /* Convert to little-endian. */ > - s01 = vrev16q_u8(s01); > - > - /* Vertical add, consolidate outside the loop. */ > - bytes += vaddq_u32(bytes, s01); > - /* Separate into packet length and data length. */ > - s23 = vqtbl1q_u8(s01, mask1); > - s01 = vqtbl1q_u8(s01, mask0); > - > - /* Store packet length and data length to mbuf. */ > - *(uint64_t *)&m0->pkt_len = vgetq_lane_u64(s01, 0); > - *(uint64_t *)&m1->pkt_len = vgetq_lane_u64(s01, 1); > - *(uint64_t *)&m2->pkt_len = vgetq_lane_u64(s23, 0); > - *(uint64_t *)&m3->pkt_len = vgetq_lane_u64(s23, 1); > + if (droq->chip_gen == OTX_EP_CN20XX) { > + uint32x4_t lens; > + > + /* Load packet size (completion is in big-endian > order) */ > + lens = vdupq_n_u32(0); > + lens = > vsetq_lane_u32((uint32_t)rte_bswap64(desc_ring[idx0].info_ptr), > + lens, 0); > + lens = > vsetq_lane_u32((uint32_t)rte_bswap64(desc_ring[idx1].info_ptr), > + lens, 1); > + lens = > vsetq_lane_u32((uint32_t)rte_bswap64(desc_ring[idx2].info_ptr), > + lens, 2); > + lens = > vsetq_lane_u32((uint32_t)rte_bswap64(desc_ring[idx3].info_ptr), > + lens, 3); > + lens = vandq_u32(lens, vdupq_n_u32(0xFFFF)); > + bytes = vaddq_u32(bytes, lens); > + > + m0->pkt_len = m0->data_len = vgetq_lane_u32(lens, 0); > + m1->pkt_len = m1->data_len = vgetq_lane_u32(lens, 1); > + m2->pkt_len = m2->data_len = vgetq_lane_u32(lens, 2); > + m3->pkt_len = m3->data_len = vgetq_lane_u32(lens, 3); > + } else { > + uint8x16_t len_vec; > + uint32_t p0, p1, p2, p3; > + > + /* Load packet size big-endian. */ > + p0 = cnxk_pktmbuf_mtod(m0, struct otx_ep_droq_info > *)->length >> 48; > + p1 = cnxk_pktmbuf_mtod(m1, struct otx_ep_droq_info > *)->length >> 48; > + p2 = cnxk_pktmbuf_mtod(m2, struct otx_ep_droq_info > *)->length >> 48; > + p3 = cnxk_pktmbuf_mtod(m3, struct otx_ep_droq_info > *)->length >> 48; > + > + s01 = vsetq_lane_u32(p0, s01, 0); > + s01 = vsetq_lane_u32(p1, s01, 1); > + s01 = vsetq_lane_u32(p2, s01, 2); > + s01 = vsetq_lane_u32(p3, s01, 3); > + /* Convert to little-endian. */ > + len_vec = vrev16q_u8(vreinterpretq_u8_u64(s01)); > + bytes = vaddq_u32(bytes, > vreinterpretq_u32_u8(len_vec)); > + /* Separate into packet length and data length. */ > + s23 = vreinterpretq_u64_u8(vqtbl1q_u8(len_vec, > mask1)); > + s01 = vreinterpretq_u64_u8(vqtbl1q_u8(len_vec, > mask0)); > + > + /* Store packet length and data length to mbuf. */ > + *(uint64_t *)&m0->pkt_len = vgetq_lane_u64(s01, 0); > + *(uint64_t *)&m1->pkt_len = vgetq_lane_u64(s01, 1); > + *(uint64_t *)&m2->pkt_len = vgetq_lane_u64(s23, 0); > + *(uint64_t *)&m3->pkt_len = vgetq_lane_u64(s23, 1); > + } > > /* Reset rearm data. */ > *(uint64_t *)&m0->rearm_data = droq->rearm_data; > diff --git a/drivers/net/octeon_ep/cnxk_ep_rx_sse.c > b/drivers/net/octeon_ep/cnxk_ep_rx_sse.c > index d17ec46211..7802d73477 100644 > --- a/drivers/net/octeon_ep/cnxk_ep_rx_sse.c > +++ b/drivers/net/octeon_ep/cnxk_ep_rx_sse.c > @@ -17,6 +17,7 @@ hadd(__m128i x) > static __rte_always_inline void > cnxk_ep_process_pkts_vec_sse(struct rte_mbuf **rx_pkts, struct otx_ep_droq > *droq, uint16_t new_pkts) > { > + struct otx_ep_droq_desc *desc_ring = droq->desc_ring; > struct rte_mbuf **recv_buf_list = droq->recv_buf_list; > uint32_t read_idx = droq->read_idx; > struct rte_mbuf *m0, *m1, *m2, *m3; > @@ -32,6 +33,8 @@ cnxk_ep_process_pkts_vec_sse(struct rte_mbuf **rx_pkts, > struct otx_ep_droq *droq > 0xFF, 4, 5, 0xFF, > 0xFF, 0, 1); > const __m128i cpy_mask = _mm_set_epi8(0xFF, 0xFF, 9, 8, 0xFF, > 0xFF, 9, 8, 0xFF, > 0xFF, 1, 0, 0xFF, 0xFF, > 1, 0); > + const __m128i cpy_mask1 = _mm_set_epi8(0xFF, 0xFF, 13, 12, > 0xFF, 0xFF, 9, 8, > + 0xFF, 0xFF, 5, 4, > 0xFF, 0xFF, 1, 0); > __m128i s01, s23; > > idx1 = otx_ep_incr_index(idx0, 1, nb_desc); > @@ -43,13 +46,25 @@ cnxk_ep_process_pkts_vec_sse(struct rte_mbuf **rx_pkts, > struct otx_ep_droq *droq > m2 = recv_buf_list[idx2]; > m3 = recv_buf_list[idx3]; > > - /* Load packet size big-endian. */ > - s01 = _mm_set_epi32(cnxk_pktmbuf_mtod(m3, struct > otx_ep_droq_info *)->length >> 48, > - cnxk_pktmbuf_mtod(m1, struct > otx_ep_droq_info *)->length >> 48, > - cnxk_pktmbuf_mtod(m2, struct > otx_ep_droq_info *)->length >> 48, > - cnxk_pktmbuf_mtod(m0, struct > otx_ep_droq_info *)->length >> 48); > - /* Convert to little-endian. */ > - s01 = _mm_shuffle_epi8(s01, bswap_mask); > + if (droq->chip_gen == OTX_EP_CN20XX) { > + /* Load packet size (completion is in big-endian > order) */ > + s01 = > _mm_set_epi32((uint32_t)rte_bswap64(desc_ring[idx3].info_ptr), > + > (uint32_t)rte_bswap64(desc_ring[idx2].info_ptr), > + > (uint32_t)rte_bswap64(desc_ring[idx1].info_ptr), > + > (uint32_t)rte_bswap64(desc_ring[idx0].info_ptr)); > + s01 = _mm_shuffle_epi8(s01, cpy_mask1); > + } else { > + uint32_t p0, p1, p2, p3; > + > + /* Load packet size big-endian. */ > + p0 = cnxk_pktmbuf_mtod(m0, struct otx_ep_droq_info > *)->length >> 48; > + p1 = cnxk_pktmbuf_mtod(m1, struct otx_ep_droq_info > *)->length >> 48; > + p2 = cnxk_pktmbuf_mtod(m2, struct otx_ep_droq_info > *)->length >> 48; > + p3 = cnxk_pktmbuf_mtod(m3, struct otx_ep_droq_info > *)->length >> 48; > + s01 = _mm_set_epi32(p3, p1, p2, p0); > + /* Convert to little-endian. */ > + s01 = _mm_shuffle_epi8(s01, bswap_mask); > + } > /* Vertical add, consolidate outside loop */ > bytes = _mm_add_epi32(bytes, s01); > /* Separate into packet length and data length. */ > diff --git a/drivers/net/octeon_ep/meson.build > b/drivers/net/octeon_ep/meson.build > index cbb729b689..b2101bc670 100644 > --- a/drivers/net/octeon_ep/meson.build > +++ b/drivers/net/octeon_ep/meson.build > @@ -11,6 +11,8 @@ sources = files( > 'otx_ep_mbox.c', > 'cnxk_ep_rx.c', > 'cnxk_ep_tx.c', > + 'cn20k_ep_vf.c', > + 'cn20k_ep_mbox.c', > ) > > if arch_subdir == 'x86' > diff --git a/drivers/net/octeon_ep/otx_ep_common.h > b/drivers/net/octeon_ep/otx_ep_common.h > index 53de8b18d6..406155078b 100644 > --- a/drivers/net/octeon_ep/otx_ep_common.h > +++ b/drivers/net/octeon_ep/otx_ep_common.h > @@ -19,12 +19,14 @@ > #define OTX_EP_CN8XX RTE_BIT32(0) > #define OTX_EP_CN9XX RTE_BIT32(1) > #define OTX_EP_CN10XX RTE_BIT32(2) > +#define OTX_EP_CN20XX RTE_BIT32(3) > > #define OTX_EP_NW_PKT_OP 0x1220 > #define OTX_EP_NW_CMD_OP 0x1221 > > #define OTX_EP_MAX_RINGS_PER_VF (8) > #define OTX_EP_CFG_IO_QUEUES OTX_EP_MAX_RINGS_PER_VF > +#define OTX_EP_16BYTE_INSTR (16) > #define OTX_EP_32BYTE_INSTR (32) > #define OTX_EP_64BYTE_INSTR (64) > /* > @@ -406,6 +408,9 @@ struct otx_ep_droq { > */ > void *pkts_sent_reg; > > + /* Generation */ > + uint32_t chip_gen; > + > /* Use ISM memory */ > uint8_t ism_ena; > > @@ -572,6 +577,10 @@ struct otx_ep_device { > > /* Use ISM memory */ > uint8_t ism_ena; > + > + uint8_t configured; > + > + struct otx_ep_cn20k_mbox *mbox_info; > }; > > int otx_ep_setup_iqs(struct otx_ep_device *otx_ep, uint32_t iq_no, > diff --git a/drivers/net/octeon_ep/otx_ep_ethdev.c > b/drivers/net/octeon_ep/otx_ep_ethdev.c > index 876d2f9d7d..8a2dd877a1 100644 > --- a/drivers/net/octeon_ep/otx_ep_ethdev.c > +++ b/drivers/net/octeon_ep/otx_ep_ethdev.c > @@ -9,6 +9,8 @@ > #include "otx_ep_vf.h" > #include "otx2_ep_vf.h" > #include "cnxk_ep_vf.h" > +#include "cn20k_ep_vf.h" > +#include "cn20k_ep_mbox.h" > #include "otx_ep_rxtx.h" > #include "otx_ep_mbox.h" > > @@ -16,6 +18,7 @@ > ((struct otx_ep_device *)(_eth_dev)->data->dev_private) > > #define OTX_ISM_ENABLE "ism_enable" > +#define OTX_MAX_RINGS "max_rings" > > static const struct rte_eth_desc_lim otx_ep_rx_desc_lim = { > .nb_max = OTX_EP_MAX_OQ_DESCRIPTORS, > @@ -42,6 +45,7 @@ parse_flag(const char *key, const char *value, void > *extra_args) > static int > otx_ethdev_parse_devargs(struct rte_devargs *devargs, struct otx_ep_device > *otx_epvf) > { > + uint8_t max_rings = CN20K_MAX_RINGS_PER_VF; > struct rte_kvargs *kvlist; > uint8_t ism_enable = 0; > > @@ -53,10 +57,12 @@ otx_ethdev_parse_devargs(struct rte_devargs *devargs, > struct otx_ep_device *otx_ > goto exit; > > rte_kvargs_process(kvlist, OTX_ISM_ENABLE, &parse_flag, &ism_enable); > + rte_kvargs_process(kvlist, OTX_MAX_RINGS, &parse_flag, &max_rings); > rte_kvargs_free(kvlist); > > null_devargs: > otx_epvf->ism_ena = !!ism_enable; > + otx_epvf->sriov_info.rings_per_vf = max_rings; > > return 0; > > @@ -69,7 +75,8 @@ otx_ep_set_tx_func(struct rte_eth_dev *eth_dev) > { > struct otx_ep_device *otx_epvf = OTX_EP_DEV(eth_dev); > > - if (otx_epvf->chip_gen == OTX_EP_CN10XX || otx_epvf->chip_gen == > OTX_EP_CN9XX) { > + if (otx_epvf->chip_gen == OTX_EP_CN10XX || otx_epvf->chip_gen == > OTX_EP_CN9XX || > + otx_epvf->chip_gen == OTX_EP_CN20XX) { > eth_dev->tx_pkt_burst = &cnxk_ep_xmit_pkts; > if (otx_epvf->tx_offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS) > eth_dev->tx_pkt_burst = &cnxk_ep_xmit_pkts_mseg; > @@ -87,7 +94,7 @@ otx_ep_set_rx_func(struct rte_eth_dev *eth_dev) > { > struct otx_ep_device *otx_epvf = OTX_EP_DEV(eth_dev); > > - if (otx_epvf->chip_gen == OTX_EP_CN10XX) { > + if (otx_epvf->chip_gen == OTX_EP_CN10XX || otx_epvf->chip_gen == > OTX_EP_CN20XX) { > eth_dev->rx_pkt_burst = &cnxk_ep_recv_pkts; > #ifdef RTE_ARCH_X86 > eth_dev->rx_pkt_burst = &cnxk_ep_recv_pkts_sse; > @@ -338,6 +345,11 @@ otx_ep_chip_specific_setup(struct otx_ep_device > *otx_epvf) > otx_epvf->chip_id = dev_id; > ret = cnxk_ep_vf_setup_device(otx_epvf); > break; > + case PCI_DEVID_CN20KA_EP_NET_VF: > + case PCI_DEVID_CNF20KA_EP_NET_VF: > + otx_epvf->chip_id = dev_id; > + ret = cn20k_ep_vf_setup_device(otx_epvf); > + break; > default: > otx_ep_err("Unsupported device"); > ret = -EINVAL; > @@ -384,11 +396,16 @@ otx_epdev_init(struct otx_ep_device *otx_epvf) > otx_epvf->chip_id == PCI_DEVID_CNF10KB_EP_NET_VF) { > otx_epvf->eth_dev->rx_pkt_burst = &cnxk_ep_recv_pkts; > otx_epvf->chip_gen = OTX_EP_CN10XX; > + } else if (otx_epvf->chip_id == PCI_DEVID_CN20KA_EP_NET_VF || > + otx_epvf->chip_id == PCI_DEVID_CNF20KA_EP_NET_VF) { > + otx_epvf->eth_dev->rx_pkt_burst = &cnxk_ep_recv_pkts; > + otx_epvf->chip_gen = OTX_EP_CN20XX; > } else { > otx_ep_err("Invalid chip_id"); > ret = -EINVAL; > goto setup_fail; > } > + > ethdev_queues = (uint32_t)(otx_epvf->sriov_info.rings_per_vf); > otx_epvf->max_rx_queues = ethdev_queues; > otx_epvf->max_tx_queues = ethdev_queues; > @@ -407,6 +424,7 @@ otx_ep_dev_configure(struct rte_eth_dev *eth_dev) > struct rte_eth_rxmode *rxmode; > struct rte_eth_txmode *txmode; > struct rte_eth_conf *conf; > + int rc; > > conf = &data->dev_conf; > rxmode = &conf->rxmode; > @@ -417,6 +435,20 @@ otx_ep_dev_configure(struct rte_eth_dev *eth_dev) > return -EINVAL; > } > > + if (otx_epvf->chip_gen == OTX_EP_CN20XX) { > + if (otx_epvf->configured) { > + otx_ep_cn20k_mbox_free_sdp_rings(otx_epvf, 0, true); > + otx_epvf->configured = 0; > + } > + > + rc = otx_ep_cn20k_mbox_alloc_sdp_rings(otx_epvf, > eth_dev->data->nb_rx_queues); > + if (rc != eth_dev->data->nb_rx_queues) { > + otx_ep_err("Failed to allocate the rings"); > + otx_epvf->configured = 0; > + return rc; > + } > + } > + > otx_epvf->fn_list.setup_device_regs(otx_epvf); > otx_epvf->fn_list.disable_io_queues(otx_epvf); > > @@ -425,6 +457,7 @@ otx_ep_dev_configure(struct rte_eth_dev *eth_dev) > > otx_epvf->rx_offloads = rxmode->offloads; > otx_epvf->tx_offloads = txmode->offloads; > + otx_epvf->configured = 1; > > return 0; > } > @@ -660,8 +693,11 @@ otx_ep_dev_close(struct rte_eth_dev *eth_dev) > return 0; > > otx_epvf = OTX_EP_DEV(eth_dev); > - otx_ep_mbox_send_dev_exit(eth_dev); > - otx_ep_mbox_uninit(eth_dev); > + > + if (otx_epvf->chip_gen != OTX_EP_CN20XX) { > + otx_ep_mbox_send_dev_exit(eth_dev); > + otx_ep_mbox_uninit(eth_dev); > + } > otx_epvf->fn_list.disable_io_queues(otx_epvf); > num_queues = otx_epvf->nb_rx_queues; > for (q_no = 0; q_no < num_queues; q_no++) { > @@ -686,6 +722,14 @@ otx_ep_dev_close(struct rte_eth_dev *eth_dev) > return -EINVAL; > } > > + if (otx_epvf->chip_gen == OTX_EP_CN20XX) { > + if (otx_epvf->configured) { > + otx_ep_cn20k_mbox_free_sdp_rings(otx_epvf, 0, true); > + otx_epvf->configured = 0; > + } > + otx_ep_cn20k_mbox_uninit(eth_dev); > + } > + > return 0; > } > > @@ -724,8 +768,14 @@ static const struct eth_dev_ops otx_ep_eth_dev_ops = { > static int > otx_ep_eth_dev_uninit(struct rte_eth_dev *eth_dev) > { > - if (rte_eal_process_type() == RTE_PROC_PRIMARY) > - otx_ep_mbox_uninit(eth_dev); > + struct otx_ep_device *otx_epvf = OTX_EP_DEV(eth_dev); > + > + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { > + if (otx_epvf->chip_gen == OTX_EP_CN20XX) > + otx_ep_cn20k_mbox_uninit(eth_dev); > + else > + otx_ep_mbox_uninit(eth_dev); > + } > > return 0; > } > @@ -835,7 +885,9 @@ otx_ep_eth_dev_init(struct rte_eth_dev *eth_dev) > otx_epvf->chip_id == PCI_DEVID_CN10KA_EP_NET_VF || > otx_epvf->chip_id == PCI_DEVID_CN10KB_EP_NET_VF || > otx_epvf->chip_id == PCI_DEVID_CNF10KA_EP_NET_VF || > - otx_epvf->chip_id == PCI_DEVID_CNF10KB_EP_NET_VF) { > + otx_epvf->chip_id == PCI_DEVID_CNF10KB_EP_NET_VF || > + otx_epvf->chip_id == PCI_DEVID_CN20KA_EP_NET_VF || > + otx_epvf->chip_id == PCI_DEVID_CNF20KA_EP_NET_VF) { > otx_epvf->pkind = SDP_OTX2_PKIND_FS0; > otx_ep_info("using pkind %d", otx_epvf->pkind); > } else if (otx_epvf->chip_id == PCI_DEVID_OCTEONTX_EP_VF) { > @@ -847,17 +899,28 @@ otx_ep_eth_dev_init(struct rte_eth_dev *eth_dev) > goto exit; > } > > - if (otx_ep_mbox_init(eth_dev)) { > + if (otx_epvf->chip_gen == OTX_EP_CN20XX) > + ret = otx_ep_cn20k_mbox_init(eth_dev); > + else > + ret = otx_ep_mbox_init(eth_dev); > + > + if (ret) { > ret = -EINVAL; > goto exit; > } > > - if (otx_ep_eth_dev_query_set_vf_mac(eth_dev, > - (struct rte_ether_addr *)&vf_mac_addr)) { > + if (otx_epvf->chip_gen == OTX_EP_CN20XX) { > + ret = otx_ep_cn20k_mbox_send_ready(otx_epvf); > + if (ret) > + goto exit; > + } > + > + if (otx_ep_eth_dev_query_set_vf_mac(eth_dev, (struct rte_ether_addr > *)&vf_mac_addr)) { > otx_ep_err("set mac addr failed"); > ret = -ENODEV; > goto exit; > } > + > rte_ether_addr_copy(&vf_mac_addr, eth_dev->data->mac_addrs); > > exit: > @@ -893,6 +956,8 @@ static const struct rte_pci_id pci_id_otx_ep_map[] = { > { RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10KB_EP_NET_VF) }, > { RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CNF10KA_EP_NET_VF) }, > { RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CNF10KB_EP_NET_VF) }, > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN20KA_EP_NET_VF) }, > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CNF20KA_EP_NET_VF) }, > { .vendor_id = 0, /* sentinel */ } > }; > > @@ -908,4 +973,5 @@ RTE_PMD_REGISTER_PCI_TABLE(net_otx_ep, pci_id_otx_ep_map); > RTE_PMD_REGISTER_KMOD_DEP(net_otx_ep, "* igb_uio | vfio-pci"); > RTE_LOG_REGISTER_DEFAULT(otx_net_ep_logtype, NOTICE); > RTE_PMD_REGISTER_PARAM_STRING(net_otx_ep, > - OTX_ISM_ENABLE "=<0|1>"); > + OTX_ISM_ENABLE "=<0|1> " > + OTX_MAX_RINGS "=<1-8>"); > diff --git a/drivers/net/octeon_ep/otx_ep_mbox.c > b/drivers/net/octeon_ep/otx_ep_mbox.c > index 5e6be29a96..47aec5f7a2 100644 > --- a/drivers/net/octeon_ep/otx_ep_mbox.c > +++ b/drivers/net/octeon_ep/otx_ep_mbox.c > @@ -10,6 +10,8 @@ > #include "otx_ep_vf.h" > #include "otx2_ep_vf.h" > #include "cnxk_ep_vf.h" > +#include "cn20k_ep_mbox.h" > +#include "cn20k_ep_vf.h" > #include "otx_ep_mbox.h" > > /* > @@ -95,7 +97,11 @@ otx_ep_send_mbox_cmd(struct otx_ep_device *otx_ep, > rte_spinlock_unlock(&otx_ep->mbox_lock); > return -EOPNOTSUPP; > } > - ret = __otx_ep_send_mbox_cmd(otx_ep, cmd, rsp); > + > + if (otx_ep->chip_gen == OTX_EP_CN20XX) > + ret = otx_ep_cn20k_mbox_send_cmd(otx_ep, cmd, rsp); > + else > + ret = __otx_ep_send_mbox_cmd(otx_ep, cmd, rsp); > rte_spinlock_unlock(&otx_ep->mbox_lock); > return ret; > } > @@ -264,8 +270,12 @@ int otx_ep_mbox_get_link_info(struct rte_eth_dev > *eth_dev, > struct otx_ep_device *otx_ep = > (struct otx_ep_device *)(eth_dev)->data->dev_private; > memset(&link_info, 0, sizeof(struct otx_ep_iface_link_info)); > - ret = otx_ep_mbox_bulk_read(otx_ep, OTX_EP_MBOX_CMD_GET_LINK_INFO, > - (uint8_t *)&link_info, (int32_t > *)&size); > + if (otx_ep->chip_gen == OTX_EP_CN20XX) > + ret = otx_ep_cn20k_mbox_bulk_read(otx_ep, > OTX_EP_MBOX_CMD_GET_LINK_INFO, > + (uint8_t *)&link_info, > sizeof(link_info), &size); > + else > + ret = otx_ep_mbox_bulk_read(otx_ep, > OTX_EP_MBOX_CMD_GET_LINK_INFO, > + (uint8_t *)&link_info, (int32_t > *)&size); > if (ret) { > otx_ep_err("Get link info failed"); > return ret; > diff --git a/drivers/net/octeon_ep/otx_ep_rxtx.c > b/drivers/net/octeon_ep/otx_ep_rxtx.c > index 09ed3c8da0..a21764868d 100644 > --- a/drivers/net/octeon_ep/otx_ep_rxtx.c > +++ b/drivers/net/octeon_ep/otx_ep_rxtx.c > @@ -378,6 +378,9 @@ otx_ep_init_droq(struct otx_ep_device *otx_ep, uint32_t > q_no, > > otx_ep->io_qmask.oq |= (1ull << q_no); > > + if (otx_ep->chip_gen == OTX_EP_CN20XX) > + droq->chip_gen = OTX_EP_CN20XX; > + > return 0; > > init_droq_fail: > -- > 2.34.1 >

