@@ -36,6 +36,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_OCTEONTX2_PMD) += \
otx2_ptp.c \
otx2_flow.c \
otx2_link.c \
+ otx2_vlan.c \
otx2_stats.c \
otx2_lookup.c \
otx2_ethdev.c \
@@ -9,6 +9,7 @@ sources = files(
'otx2_ptp.c',
'otx2_flow.c',
'otx2_link.c',
+ 'otx2_vlan.c',
'otx2_stats.c',
'otx2_lookup.c',
'otx2_ethdev.c',
@@ -1079,6 +1079,7 @@ otx2_nix_configure(struct rte_eth_dev *eth_dev)
/* Free the resources allocated from the previous configure */
if (dev->configured == 1) {
otx2_nix_rxchan_bpid_cfg(eth_dev, false);
+ otx2_nix_vlan_fini(eth_dev);
otx2_flow_fini(dev);
oxt2_nix_unregister_queue_irqs(eth_dev);
nix_set_nop_rxtx_function(eth_dev);
@@ -1126,6 +1127,12 @@ otx2_nix_configure(struct rte_eth_dev *eth_dev)
goto free_nix_lf;
}
+ rc = otx2_nix_vlan_offload_init(eth_dev);
+ if (rc) {
+ otx2_err("Failed to init vlan offload rc=%d", rc);
+ goto free_nix_lf;
+ }
+
/* Register queue IRQs */
rc = oxt2_nix_register_queue_irqs(eth_dev);
if (rc) {
@@ -1546,6 +1553,9 @@ otx2_eth_dev_uninit(struct rte_eth_dev *eth_dev, bool mbox_close)
/* Disable nix bpid config */
otx2_nix_rxchan_bpid_cfg(eth_dev, false);
+ /* Disable vlan offloads */
+ otx2_nix_vlan_fini(eth_dev);
+
/* Disable other rte_flow entries */
otx2_flow_fini(dev);
@@ -40,6 +40,7 @@
/* Used for struct otx2_eth_dev::flags */
#define OTX2_LINK_CFG_IN_PROGRESS_F BIT_ULL(0)
+#define NIX_MAX_VTAG_INS 2
#define VLAN_TAG_SIZE 4
#define NIX_HW_L2_OVERHEAD 22
/* ETH_HLEN+2*VLAN_HLEN */
@@ -163,6 +164,47 @@ struct otx2_fc_info {
uint16_t bpid[NIX_MAX_CHAN];
};
+struct vlan_mkex_info {
+ struct npc_xtract_info la_xtract;
+ struct npc_xtract_info lb_xtract;
+ uint64_t lb_lt_offset;
+};
+
+struct vlan_entry {
+ uint32_t mcam_idx;
+ uint16_t vlan_id;
+ TAILQ_ENTRY(vlan_entry) next;
+};
+
+TAILQ_HEAD(otx2_vlan_filter_tbl, vlan_entry);
+
+struct otx2_vlan_info {
+ struct otx2_vlan_filter_tbl fltr_tbl;
+ /* MKEX layer info */
+ struct mcam_entry def_tx_mcam_ent;
+ struct mcam_entry def_rx_mcam_ent;
+ struct vlan_mkex_info mkex;
+ /* Default mcam entry that matches vlan packets */
+ uint32_t def_rx_mcam_idx;
+ uint32_t def_tx_mcam_idx;
+ /* MCAM entry that matches double vlan packets */
+ uint32_t qinq_mcam_idx;
+ /* Indices of tx_vtag def registers */
+ uint32_t outer_vlan_idx;
+ uint32_t inner_vlan_idx;
+ uint16_t outer_vlan_tpid;
+ uint16_t inner_vlan_tpid;
+ uint16_t pvid;
+ /* QinQ entry allocated before default one */
+ uint8_t qinq_before_def;
+ uint8_t pvid_insert_on;
+ /* Rx vtag action type */
+ uint8_t vtag_type_idx;
+ uint8_t filter_on;
+ uint8_t strip_on;
+ uint8_t qinq_on;
+};
+
struct otx2_eth_dev {
OTX2_DEV; /* Base class */
MARKER otx2_eth_dev_data_start;
@@ -222,6 +264,7 @@ struct otx2_eth_dev {
struct rte_timecounter systime_tc;
struct rte_timecounter rx_tstamp_tc;
struct rte_timecounter tx_tstamp_tc;
+ struct otx2_vlan_info vlan_info;
} __rte_cache_aligned;
struct otx2_eth_txq {
@@ -422,4 +465,9 @@ int otx2_nix_timesync_read_time(struct rte_eth_dev *eth_dev,
struct timespec *ts);
int otx2_eth_dev_ptp_info_update(struct otx2_dev *dev, bool ptp_en);
+/* VLAN */
+int otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev);
+int otx2_nix_vlan_fini(struct rte_eth_dev *eth_dev);
+
+
#endif /* __OTX2_ETHDEV_H__ */
@@ -359,7 +359,7 @@ populate_tm_registers(struct otx2_eth_dev *dev,
/* Set xoff which will be cleared later */
*reg++ = NIX_AF_SMQX_CFG(schq);
- *regval++ = BIT_ULL(50) |
+ *regval++ = BIT_ULL(50) | ((uint64_t)NIX_MAX_VTAG_INS << 36) |
(NIX_MAX_HW_FRS << 8) | NIX_MIN_HW_FRS;
req->num_regs++;
*reg++ = NIX_AF_MDQX_PARENT(schq);
@@ -688,7 +688,8 @@ nix_smq_xoff(struct otx2_eth_dev *dev, uint16_t smq, bool enable)
req->reg[0] = NIX_AF_SMQX_CFG(smq);
/* Unmodified fields */
- req->regval[0] = (NIX_MAX_HW_FRS << 8) | NIX_MIN_HW_FRS;
+ req->regval[0] = ((uint64_t)NIX_MAX_VTAG_INS << 36) |
+ (NIX_MAX_HW_FRS << 8) | NIX_MIN_HW_FRS;
if (enable)
req->regval[0] |= BIT_ULL(50) | BIT_ULL(49);
new file mode 100644
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2019 Marvell International Ltd.
+ */
+
+#include <rte_malloc.h>
+#include <rte_tailq.h>
+
+#include "otx2_ethdev.h"
+#include "otx2_flow.h"
+
+
+#define VLAN_ID_MATCH 0x1
+#define VTAG_F_MATCH 0x2
+#define MAC_ADDR_MATCH 0x4
+#define QINQ_F_MATCH 0x8
+#define VLAN_DROP 0x10
+
+enum vtag_cfg_dir {
+ VTAG_TX,
+ VTAG_RX
+};
+
+static int
+__rte_unused nix_vlan_mcam_enb_dis(struct otx2_eth_dev *dev,
+ uint32_t entry, const int enable)
+{
+ struct npc_mcam_ena_dis_entry_req *req;
+ struct otx2_mbox *mbox = dev->mbox;
+ int rc = -EINVAL;
+
+ if (enable)
+ req = otx2_mbox_alloc_msg_npc_mcam_ena_entry(mbox);
+ else
+ req = otx2_mbox_alloc_msg_npc_mcam_dis_entry(mbox);
+
+ req->entry = entry;
+
+ rc = otx2_mbox_process_msg(mbox, NULL);
+ return rc;
+}
+
+static int
+__rte_unused nix_vlan_mcam_free(struct otx2_eth_dev *dev, uint32_t entry)
+{
+ struct npc_mcam_free_entry_req *req;
+ struct otx2_mbox *mbox = dev->mbox;
+ int rc = -EINVAL;
+
+ req = otx2_mbox_alloc_msg_npc_mcam_free_entry(mbox);
+ req->entry = entry;
+
+ rc = otx2_mbox_process_msg(mbox, NULL);
+ return rc;
+}
+
+static int
+__rte_unused nix_vlan_mcam_write(struct rte_eth_dev *eth_dev, uint16_t ent_idx,
+ struct mcam_entry *entry, uint8_t intf)
+{
+ struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+ struct npc_mcam_write_entry_req *req;
+ struct otx2_mbox *mbox = dev->mbox;
+ struct msghdr *rsp;
+ int rc = -EINVAL;
+
+ req = otx2_mbox_alloc_msg_npc_mcam_write_entry(mbox);
+
+ req->entry = ent_idx;
+ req->intf = intf;
+ req->enable_entry = 1;
+ memcpy(&req->entry_data, entry, sizeof(struct mcam_entry));
+
+ rc = otx2_mbox_process_msg(mbox, (void *)&rsp);
+ return rc;
+}
+
+static int
+__rte_unused nix_vlan_mcam_alloc_and_write(struct rte_eth_dev *eth_dev,
+ struct mcam_entry *entry,
+ uint8_t intf, bool drop)
+{
+ struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+ struct npc_mcam_alloc_and_write_entry_req *req;
+ struct npc_mcam_alloc_and_write_entry_rsp *rsp;
+ struct otx2_mbox *mbox = dev->mbox;
+ int rc = -EINVAL;
+
+ req = otx2_mbox_alloc_msg_npc_mcam_alloc_and_write_entry(mbox);
+
+ if (intf == NPC_MCAM_RX) {
+ if (!drop && dev->vlan_info.def_rx_mcam_idx) {
+ req->priority = NPC_MCAM_HIGHER_PRIO;
+ req->ref_entry = dev->vlan_info.def_rx_mcam_idx;
+ } else if (drop && dev->vlan_info.qinq_mcam_idx) {
+ req->priority = NPC_MCAM_LOWER_PRIO;
+ req->ref_entry = dev->vlan_info.qinq_mcam_idx;
+ } else {
+ req->priority = NPC_MCAM_ANY_PRIO;
+ req->ref_entry = 0;
+ }
+ } else {
+ req->priority = NPC_MCAM_ANY_PRIO;
+ req->ref_entry = 0;
+ }
+
+ req->intf = intf;
+ req->enable_entry = 1;
+ memcpy(&req->entry_data, entry, sizeof(struct mcam_entry));
+
+ rc = otx2_mbox_process_msg(mbox, (void *)&rsp);
+ if (rc)
+ return rc;
+
+ return rsp->entry;
+}
+
+static int
+nix_vlan_rx_mkex_offset(uint64_t mask)
+{
+ int nib_count = 0;
+
+ while (mask) {
+ nib_count += mask & 1;
+ mask >>= 1;
+ }
+
+ return nib_count * 4;
+}
+
+static int
+nix_vlan_get_mkex_info(struct otx2_eth_dev *dev)
+{
+ struct vlan_mkex_info *mkex = &dev->vlan_info.mkex;
+ struct otx2_npc_flow_info *npc = &dev->npc_flow;
+ struct npc_xtract_info *x_info = NULL;
+ uint64_t rx_keyx;
+ otx2_dxcfg_t *p;
+ int rc = -EINVAL;
+
+ if (npc == NULL) {
+ otx2_err("Missing npc mkex configuration");
+ return rc;
+ }
+
+#define NPC_KEX_CHAN_NIBBLE_ENA 0x7ULL
+#define NPC_KEX_LB_LTYPE_NIBBLE_ENA 0x1000ULL
+#define NPC_KEX_LB_LTYPE_NIBBLE_MASK 0xFFFULL
+
+ rx_keyx = npc->keyx_supp_nmask[NPC_MCAM_RX];
+ if ((rx_keyx & NPC_KEX_CHAN_NIBBLE_ENA) != NPC_KEX_CHAN_NIBBLE_ENA)
+ return rc;
+
+ if ((rx_keyx & NPC_KEX_LB_LTYPE_NIBBLE_ENA) !=
+ NPC_KEX_LB_LTYPE_NIBBLE_ENA)
+ return rc;
+
+ mkex->lb_lt_offset =
+ nix_vlan_rx_mkex_offset(rx_keyx & NPC_KEX_LB_LTYPE_NIBBLE_MASK);
+
+ p = &npc->prx_dxcfg;
+ x_info = &(*p)[NPC_MCAM_RX][NPC_LID_LA][NPC_LT_LA_ETHER].xtract[0];
+ memcpy(&mkex->la_xtract, x_info, sizeof(struct npc_xtract_info));
+ x_info = &(*p)[NPC_MCAM_RX][NPC_LID_LB][NPC_LT_LB_CTAG].xtract[0];
+ memcpy(&mkex->lb_xtract, x_info, sizeof(struct npc_xtract_info));
+
+ return 0;
+}
+
+int
+otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev)
+{
+ struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+ int rc;
+
+ /* Port initialized for first time or restarted */
+ if (!dev->configured) {
+ rc = nix_vlan_get_mkex_info(dev);
+ if (rc) {
+ otx2_err("Failed to get vlan mkex info rc=%d", rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
+int
+otx2_nix_vlan_fini(__rte_unused struct rte_eth_dev *eth_dev)
+{
+ return 0;
+}