From: Vivek Sharma <viveksha...@marvell.com>

Support setting up VLAN filters so as to allow tagged
packet's reception after VLAN HW Filter offload is enabled.

Signed-off-by: Vivek Sharma <viveksha...@marvell.com>
---
 doc/guides/nics/features/octeontx2.ini     |   1 +
 doc/guides/nics/features/octeontx2_vec.ini |   1 +
 doc/guides/nics/features/octeontx2_vf.ini  |   1 +
 drivers/net/octeontx2/otx2_ethdev.c        |   2 +
 drivers/net/octeontx2/otx2_ethdev.h        |   5 +-
 drivers/net/octeontx2/otx2_vlan.c          | 147 ++++++++++++++++++++-
 6 files changed, 154 insertions(+), 3 deletions(-)

diff --git a/doc/guides/nics/features/octeontx2.ini 
b/doc/guides/nics/features/octeontx2.ini
index f811c38e3..3567e3f63 100644
--- a/doc/guides/nics/features/octeontx2.ini
+++ b/doc/guides/nics/features/octeontx2.ini
@@ -21,6 +21,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Inner RSS            = Y
+VLAN filter          = Y
 Flow control         = Y
 Flow API             = Y
 VLAN offload         = Y
diff --git a/doc/guides/nics/features/octeontx2_vec.ini 
b/doc/guides/nics/features/octeontx2_vec.ini
index 77c3a5637..7edc80348 100644
--- a/doc/guides/nics/features/octeontx2_vec.ini
+++ b/doc/guides/nics/features/octeontx2_vec.ini
@@ -21,6 +21,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Inner RSS            = Y
+VLAN filter          = Y
 Flow control         = Y
 Flow API             = Y
 VLAN offload         = Y
diff --git a/doc/guides/nics/features/octeontx2_vf.ini 
b/doc/guides/nics/features/octeontx2_vf.ini
index 4571a1e78..fcc1ddc03 100644
--- a/doc/guides/nics/features/octeontx2_vf.ini
+++ b/doc/guides/nics/features/octeontx2_vf.ini
@@ -17,6 +17,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Inner RSS            = Y
+VLAN filter          = Y
 Flow API             = Y
 VLAN offload         = Y
 QinQ offload         = Y
diff --git a/drivers/net/octeontx2/otx2_ethdev.c 
b/drivers/net/octeontx2/otx2_ethdev.c
index 362e46941..175e80e44 100644
--- a/drivers/net/octeontx2/otx2_ethdev.c
+++ b/drivers/net/octeontx2/otx2_ethdev.c
@@ -1345,6 +1345,8 @@ static const struct eth_dev_ops otx2_eth_dev_ops = {
        .timesync_read_time       = otx2_nix_timesync_read_time,
        .timesync_write_time      = otx2_nix_timesync_write_time,
        .vlan_offload_set         = otx2_nix_vlan_offload_set,
+       .vlan_filter_set          = otx2_nix_vlan_filter_set,
+       .vlan_strip_queue_set     = otx2_nix_vlan_strip_queue_set,
 };
 
 static inline int
diff --git a/drivers/net/octeontx2/otx2_ethdev.h 
b/drivers/net/octeontx2/otx2_ethdev.h
index 816371c37..a3babe51a 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -469,6 +469,9 @@ int otx2_eth_dev_ptp_info_update(struct otx2_dev *dev, bool 
ptp_en);
 int otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev);
 int otx2_nix_vlan_fini(struct rte_eth_dev *eth_dev);
 int otx2_nix_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask);
-
+int otx2_nix_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id,
+                            int on);
+void otx2_nix_vlan_strip_queue_set(struct rte_eth_dev *dev,
+                                  uint16_t queue, int on);
 
 #endif /* __OTX2_ETHDEV_H__ */
diff --git a/drivers/net/octeontx2/otx2_vlan.c 
b/drivers/net/octeontx2/otx2_vlan.c
index d9880d069..3e60da099 100644
--- a/drivers/net/octeontx2/otx2_vlan.c
+++ b/drivers/net/octeontx2/otx2_vlan.c
@@ -21,8 +21,8 @@ enum vtag_cfg_dir {
 };
 
 static int
-__rte_unused nix_vlan_mcam_enb_dis(struct otx2_eth_dev *dev,
-                                  uint32_t entry, const int enable)
+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;
@@ -366,6 +366,8 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const 
uint8_t enable,
                   uint16_t vlan_id)
 {
        struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+       struct otx2_vlan_info *vlan = &dev->vlan_info;
+       struct vlan_entry *entry;
        int rc = -EINVAL;
 
        if (!vlan_id && enable) {
@@ -379,6 +381,24 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const 
uint8_t enable,
                return 0;
        }
 
+       /* Enable/disable existing vlan filter entries */
+       TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
+               if (vlan_id) {
+                       if (entry->vlan_id == vlan_id) {
+                               rc = nix_vlan_mcam_enb_dis(dev,
+                                                          entry->mcam_idx,
+                                                          enable);
+                               if (rc)
+                                       return rc;
+                       }
+               } else {
+                       rc = nix_vlan_mcam_enb_dis(dev, entry->mcam_idx,
+                                                  enable);
+                       if (rc)
+                               return rc;
+               }
+       }
+
        if (!vlan_id && !enable) {
                rc = nix_vlan_handle_default_rx_entry(eth_dev, false, true,
                                                      enable);
@@ -393,6 +413,80 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const 
uint8_t enable,
        return 0;
 }
 
+/* Enable/disable vlan filtering for the given vlan_id */
+int
+otx2_nix_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id,
+                        int on)
+{
+       struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+       struct otx2_vlan_info *vlan = &dev->vlan_info;
+       struct vlan_entry *entry;
+       int entry_exists = 0;
+       int rc = -EINVAL;
+       int mcam_idx;
+
+       if (!vlan_id) {
+               otx2_err("Vlan Id can't be zero");
+               return rc;
+       }
+
+       if (!vlan->def_rx_mcam_idx) {
+               otx2_err("Vlan Filtering is disabled, enable it first");
+               return rc;
+       }
+
+       if (on) {
+               TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
+                       if (entry->vlan_id == vlan_id) {
+                               /* Vlan entry already exists */
+                               entry_exists = 1;
+                               /* mcam entry already allocated */
+                               if (entry->mcam_idx) {
+                                       rc = nix_vlan_hw_filter(eth_dev, on,
+                                                               vlan_id);
+                                       return rc;
+                               }
+                       }
+               }
+
+               if (!entry_exists) {
+                       entry = rte_zmalloc("otx2_nix_vlan_entry",
+                                           sizeof(struct vlan_entry), 0);
+                       if (!entry) {
+                               otx2_err("Failed to allocate memory");
+                               return -ENOMEM;
+                       }
+               }
+
+               /* Enables vlan_id & mac address based filtering */
+               mcam_idx = nix_vlan_mcam_config(eth_dev, vlan_id,
+                                               VLAN_ID_MATCH |
+                                               MAC_ADDR_MATCH);
+               if (mcam_idx < 0) {
+                       otx2_err("Failed to config vlan mcam");
+                       TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
+                       rte_free(entry);
+                       return mcam_idx;
+               }
+
+               entry->mcam_idx = mcam_idx;
+               if (!entry_exists) {
+                       entry->vlan_id  = vlan_id;
+                       TAILQ_INSERT_HEAD(&vlan->fltr_tbl, entry, next);
+               }
+       } else {
+               TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
+                       if (entry->vlan_id == vlan_id) {
+                               nix_vlan_mcam_free(dev, entry->mcam_idx);
+                               TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
+                               rte_free(entry);
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
 /* Configure double vlan(qinq) on or off */
 static int
 otx2_nix_config_double_vlan(struct rte_eth_dev *eth_dev,
@@ -497,6 +591,13 @@ otx2_nix_vlan_offload_set(struct rte_eth_dev *eth_dev, int 
mask)
        return rc;
 }
 
+void otx2_nix_vlan_strip_queue_set(__rte_unused struct rte_eth_dev *dev,
+                                  __rte_unused uint16_t queue,
+                                  __rte_unused int on)
+{
+       otx2_err("Not Supported");
+}
+
 static int
 nix_vlan_rx_mkex_offset(uint64_t mask)
 {
@@ -549,6 +650,27 @@ nix_vlan_get_mkex_info(struct otx2_eth_dev *dev)
        return 0;
 }
 
+static void nix_vlan_reinstall_vlan_filters(struct rte_eth_dev *eth_dev)
+{
+       struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+       struct vlan_entry *entry;
+       int rc;
+
+       /* VLAN filters can't be set without setting filtern on */
+       rc = nix_vlan_handle_default_rx_entry(eth_dev, false, true, true);
+       if (rc) {
+               otx2_err("Failed to reinstall vlan filters");
+               return;
+       }
+
+       while ((entry = TAILQ_FIRST(&dev->vlan_info.fltr_tbl)) != NULL) {
+               rc = otx2_nix_vlan_filter_set(eth_dev, entry->vlan_id, true);
+               if (rc)
+                       otx2_err("Failed to reinstall filter for vlan:%d",
+                                entry->vlan_id);
+       }
+}
+
 int
 otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev)
 {
@@ -564,6 +686,11 @@ otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev)
                }
 
                TAILQ_INIT(&dev->vlan_info.fltr_tbl);
+       } else {
+               /* Reinstall all mcam entries now if filter offload is set */
+               if (eth_dev->data->dev_conf.rxmode.offloads &
+                   DEV_RX_OFFLOAD_VLAN_FILTER)
+                       nix_vlan_reinstall_vlan_filters(eth_dev);
        }
 
        mask =
@@ -582,8 +709,24 @@ otx2_nix_vlan_fini(struct rte_eth_dev *eth_dev)
 {
        struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
        struct otx2_vlan_info *vlan = &dev->vlan_info;
+       struct vlan_entry *entry;
        int rc;
 
+       while ((entry = TAILQ_FIRST(&vlan->fltr_tbl)) != NULL) {
+               if (!dev->configured) {
+                       rc = nix_vlan_mcam_free(dev, entry->mcam_idx);
+                       if (rc)
+                               return rc;
+                       TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
+                       rte_free(entry);
+               } else {
+                       /* MCAM entries freed by flow_fini & lf_free on
+                        * port stop.
+                        */
+                       entry->mcam_idx = 0;
+               }
+       }
+
        if (!dev->configured) {
                if (vlan->def_rx_mcam_idx) {
                        rc = nix_vlan_mcam_free(dev, vlan->def_rx_mcam_idx);
-- 
2.21.0

Reply via email to