net/cxgbe: add option to keep outer VLAN tag in QinQ
authorShagun Agrawal <shaguna@chelsio.com>
Wed, 4 Apr 2018 03:53:36 +0000 (09:23 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 13 Apr 2018 22:40:21 +0000 (00:40 +0200)
Add devargs option to keep outer VLAN tag in Q-in-Q packets.

Signed-off-by: Shagun Agrawal <shaguna@chelsio.com>
Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
doc/guides/nics/cxgbe.rst
drivers/net/cxgbe/base/t4_regs.h
drivers/net/cxgbe/cxgbe_main.c
drivers/net/cxgbe/sge.c

index a4a7c94..38d4348 100644 (file)
@@ -127,6 +127,22 @@ enabling debugging options may affect system performance.
 
   Toggle behaviour to prefer Throughput or Latency.
 
+Runtime Options
+~~~~~~~~~~~~~~~
+
+The following ``devargs`` options can be enabled at runtime. They must
+be passed as part of EAL arguments. For example,
+
+.. code-block:: console
+
+   testpmd -w 02:00.4,keep_ovlan=1 -- -i
+
+- ``keep_ovlan`` (default **0**)
+
+  Toggle behaviour to keep/strip outer VLAN in Q-in-Q packets. If
+  enabled, the outer VLAN tag is preserved in Q-in-Q packets. Otherwise,
+  the outer VLAN tag is stripped in Q-in-Q packets.
+
 .. _driver-compilation:
 
 Driver compilation and testing
index 28ff219..c0d6ddc 100644 (file)
 #define V_CSUM_HAS_PSEUDO_HDR(x) ((x) << S_CSUM_HAS_PSEUDO_HDR)
 #define F_CSUM_HAS_PSEUDO_HDR    V_CSUM_HAS_PSEUDO_HDR(1U)
 
+#define S_RM_OVLAN     9
+#define V_RM_OVLAN(x)  ((x) << S_RM_OVLAN)
+
 /* registers for module MPS */
 #define MPS_BASE_ADDR 0x9000
 #define T4VF_MPS_BASE_ADDR 0x0100
 #define A_MPS_VF_STAT_RX_VF_UCAST_FRAMES_L 0xf0
 #define A_MPS_VF_STAT_RX_VF_ERR_FRAMES_L 0xf8
 
+#define A_MPS_PORT0_RX_IVLAN   0x3011c
+
+#define S_IVLAN_ETYPE          0
+#define M_IVLAN_ETYPE          0xffffU
+#define V_IVLAN_ETYPE(x)       ((x) << S_IVLAN_ETYPE)
+
+#define MPS_PORT_RX_IVLAN_STRIDE       0x4000
+#define MPS_PORT_RX_IVLAN(idx)         \
+       (A_MPS_PORT0_RX_IVLAN + (idx) * MPS_PORT_RX_IVLAN_STRIDE)
+
+#define A_MPS_PORT0_RX_OVLAN0  0x30120
+
+#define S_OVLAN_MASK   16
+#define M_OVLAN_MASK   0xffffU
+#define V_OVLAN_MASK(x)        ((x) << S_OVLAN_MASK)
+
+#define S_OVLAN_ETYPE          0
+#define M_OVLAN_ETYPE          0xffffU
+#define V_OVLAN_ETYPE(x)       ((x) << S_OVLAN_ETYPE)
+
+#define MPS_PORT_RX_OVLAN_STRIDE       0x4000
+#define MPS_PORT_RX_OVLAN_BASE(idx)    \
+(A_MPS_PORT0_RX_OVLAN0 + (idx) * MPS_PORT_RX_OVLAN_STRIDE)
+#define MPS_PORT_RX_OVLAN_REG(idx, reg)        (MPS_PORT_RX_OVLAN_BASE(idx) + (reg))
+
+#define A_RX_OVLAN0    0x0
+#define A_RX_OVLAN1    0x4
+#define A_RX_OVLAN2    0x8
+
+#define A_MPS_PORT0_RX_CTL     0x30100
+
+#define S_OVLAN_EN0    0
+#define V_OVLAN_EN0(x) ((x) << S_OVLAN_EN0)
+#define F_OVLAN_EN0    V_OVLAN_EN0(1)
+
+#define S_OVLAN_EN1    1
+#define V_OVLAN_EN1(x) ((x) << S_OVLAN_EN1)
+#define F_OVLAN_EN1    V_OVLAN_EN1(1)
+
+#define S_OVLAN_EN2    2
+#define V_OVLAN_EN2(x) ((x) << S_OVLAN_EN2)
+#define F_OVLAN_EN2    V_OVLAN_EN2(1)
+
+#define S_IVLAN_EN     4
+#define V_IVLAN_EN(x)  ((x) << S_IVLAN_EN)
+#define F_IVLAN_EN     V_IVLAN_EN(1)
+
+#define MPS_PORT_RX_CTL_STRIDE 0x4000
+#define MPS_PORT_RX_CTL(idx)   \
+       (A_MPS_PORT0_RX_CTL + (idx) * MPS_PORT_RX_CTL_STRIDE)
+
 /* registers for module ULP_RX */
 #define ULP_RX_BASE_ADDR 0x19150
 
index 01a80ac..c786a1a 100644 (file)
 #include <rte_malloc.h>
 #include <rte_random.h>
 #include <rte_dev.h>
+#include <rte_kvargs.h>
 
 #include "common.h"
 #include "t4_regs.h"
 #include "t4_msg.h"
 #include "cxgbe.h"
 
+#define CXGBE_DEVARG_KEEP_OVLAN "keep_ovlan"
+
 /*
  * Response queue handler for the FW event queue.
  */
@@ -392,6 +395,84 @@ void print_port_info(struct adapter *adap)
        }
 }
 
+static int
+check_devargs_handler(__rte_unused const char *key, const char *value,
+                     __rte_unused void *opaque)
+{
+       if (strcmp(value, "1"))
+               return -1;
+
+       return 0;
+}
+
+static int cxgbe_get_devargs(struct rte_devargs *devargs, const char *key)
+{
+       struct rte_kvargs *kvlist;
+
+       if (!devargs)
+               return 0;
+
+       kvlist = rte_kvargs_parse(devargs->args, NULL);
+       if (!kvlist)
+               return 0;
+
+       if (!rte_kvargs_count(kvlist, key)) {
+               rte_kvargs_free(kvlist);
+               return 0;
+       }
+
+       if (rte_kvargs_process(kvlist, key,
+                              check_devargs_handler, NULL) < 0) {
+               rte_kvargs_free(kvlist);
+               return 0;
+       }
+       rte_kvargs_free(kvlist);
+
+       return 1;
+}
+
+static void configure_vlan_types(struct adapter *adapter)
+{
+       struct rte_pci_device *pdev = adapter->pdev;
+       int i;
+
+       for_each_port(adapter, i) {
+               /* OVLAN Type 0x88a8 */
+               t4_set_reg_field(adapter, MPS_PORT_RX_OVLAN_REG(i, A_RX_OVLAN0),
+                                V_OVLAN_MASK(M_OVLAN_MASK) |
+                                V_OVLAN_ETYPE(M_OVLAN_ETYPE),
+                                V_OVLAN_MASK(M_OVLAN_MASK) |
+                                V_OVLAN_ETYPE(0x88a8));
+               /* OVLAN Type 0x9100 */
+               t4_set_reg_field(adapter, MPS_PORT_RX_OVLAN_REG(i, A_RX_OVLAN1),
+                                V_OVLAN_MASK(M_OVLAN_MASK) |
+                                V_OVLAN_ETYPE(M_OVLAN_ETYPE),
+                                V_OVLAN_MASK(M_OVLAN_MASK) |
+                                V_OVLAN_ETYPE(0x9100));
+               /* OVLAN Type 0x8100 */
+               t4_set_reg_field(adapter, MPS_PORT_RX_OVLAN_REG(i, A_RX_OVLAN2),
+                                V_OVLAN_MASK(M_OVLAN_MASK) |
+                                V_OVLAN_ETYPE(M_OVLAN_ETYPE),
+                                V_OVLAN_MASK(M_OVLAN_MASK) |
+                                V_OVLAN_ETYPE(0x8100));
+
+               /* IVLAN 0X8100 */
+               t4_set_reg_field(adapter, MPS_PORT_RX_IVLAN(i),
+                                V_IVLAN_ETYPE(M_IVLAN_ETYPE),
+                                V_IVLAN_ETYPE(0x8100));
+
+               t4_set_reg_field(adapter, MPS_PORT_RX_CTL(i),
+                                F_OVLAN_EN0 | F_OVLAN_EN1 |
+                                F_OVLAN_EN2 | F_IVLAN_EN,
+                                F_OVLAN_EN0 | F_OVLAN_EN1 |
+                                F_OVLAN_EN2 | F_IVLAN_EN);
+       }
+
+       if (cxgbe_get_devargs(pdev->device.devargs, CXGBE_DEVARG_KEEP_OVLAN))
+               t4_tp_wr_bits_indirect(adapter, A_TP_INGRESS_CONFIG,
+                                      V_RM_OVLAN(1), V_RM_OVLAN(0));
+}
+
 static void configure_pcie_ext_tag(struct adapter *adapter)
 {
        u16 v;
@@ -808,6 +889,7 @@ static int adap_init0(struct adapter *adap)
        t4_init_sge_params(adap);
        t4_init_tp_params(adap);
        configure_pcie_ext_tag(adap);
+       configure_vlan_types(adap);
 
        adap->params.drv_memwin = MEMWIN_NIC;
        adap->flags |= FW_OK;
index 85846fc..a274151 100644 (file)
@@ -1597,7 +1597,8 @@ static int process_responses(struct sge_rspq *q, int budget,
                                }
 
                                if (cpl->vlan_ex) {
-                                       pkt->ol_flags |= PKT_RX_VLAN;
+                                       pkt->ol_flags |= PKT_RX_VLAN |
+                                                        PKT_RX_VLAN_STRIPPED;
                                        pkt->vlan_tci = ntohs(cpl->vlan);
                                }