common/cnxk: support dual VLAN insert and strip actions
authorSatheesh Paul <psatheesh@marvell.com>
Mon, 19 Jul 2021 05:41:57 +0000 (11:11 +0530)
committerJerin Jacob <jerinj@marvell.com>
Thu, 16 Sep 2021 14:28:02 +0000 (16:28 +0200)
Add ROC API to configure dual VLAN tag addition and removal.

Signed-off-by: Satheesh Paul <psatheesh@marvell.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
doc/guides/rel_notes/release_21_11.rst
drivers/common/cnxk/roc_npc.c
drivers/common/cnxk/roc_npc.h
drivers/common/cnxk/roc_npc_priv.h

index 1d56fa9..68b6405 100644 (file)
@@ -62,6 +62,10 @@ New Features
   * Added bus-level parsing of the devargs syntax.
   * Kept compatibility with the legacy syntax as parsing fallback.
 
+* **Updated Marvell cnxk ethdev driver.**
+
+  * Added rte_flow support for dual VLAN insert and strip actions.
+
 * **Updated Marvell cnxk crypto PMD.**
 
   * Added AES-CBC SHA1-HMAC support in lookaside protocol (IPsec) for CN10K.
index aff4eef..52a54b3 100644 (file)
@@ -10,7 +10,7 @@ roc_npc_vtag_actions_get(struct roc_npc *roc_npc)
 {
        struct npc *npc = roc_npc_to_npc_priv(roc_npc);
 
-       return npc->vtag_actions;
+       return npc->vtag_strip_actions;
 }
 
 int
@@ -18,8 +18,8 @@ roc_npc_vtag_actions_sub_return(struct roc_npc *roc_npc, uint32_t count)
 {
        struct npc *npc = roc_npc_to_npc_priv(roc_npc);
 
-       npc->vtag_actions -= count;
-       return npc->vtag_actions;
+       npc->vtag_strip_actions -= count;
+       return npc->vtag_strip_actions;
 }
 
 int
@@ -481,6 +481,23 @@ npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
                        goto err_exit;
                }
 
+               if (req_act &
+                   ~(ROC_NPC_ACTION_TYPE_VLAN_INSERT |
+                     ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT |
+                     ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT |
+                     ROC_NPC_ACTION_TYPE_DROP | ROC_NPC_ACTION_TYPE_COUNT)) {
+                       plt_err("Only VLAN insert, drop, count supported on Egress");
+                       errcode = NPC_ERR_ACTION_NOTSUP;
+                       goto err_exit;
+               }
+
+               if (vlan_insert_action &&
+                   (req_act & ROC_NPC_ACTION_TYPE_DROP)) {
+                       plt_err("Both VLAN insert and drop actions cannot be supported");
+                       errcode = NPC_ERR_ACTION_NOTSUP;
+                       goto err_exit;
+               }
+
                if (req_act & ROC_NPC_ACTION_TYPE_DROP) {
                        flow->npc_action = NIX_TX_ACTIONOP_DROP;
                } else if ((req_act & ROC_NPC_ACTION_TYPE_COUNT) ||
@@ -526,14 +543,14 @@ npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
        }
 
        if (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP)
-               npc->vtag_actions++;
-
-       /* Only VLAN action is provided */
-       if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
-               flow->npc_action = NIX_RX_ACTIONOP_UCAST;
+               npc->vtag_strip_actions++;
 
        /* Set NIX_RX_ACTIONOP */
-       if (req_act & (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
+       if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
+               /* Only VLAN action is provided */
+               flow->npc_action = NIX_RX_ACTIONOP_UCAST;
+       } else if (req_act &
+                  (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
                flow->npc_action = NIX_RX_ACTIONOP_UCAST;
                if (req_act & ROC_NPC_ACTION_TYPE_QUEUE)
                        flow->npc_action |= (uint64_t)rq << 20;
@@ -872,6 +889,11 @@ npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
        vtag_cfg->tx.vtag0_idx = tx_vtag_action.act.vtag0_def;
        vtag_cfg->tx.free_vtag0 = true;
 
+       if (flow->vtag_insert_count == 2) {
+               vtag_cfg->tx.vtag1_idx = tx_vtag_action.act.vtag1_def;
+               vtag_cfg->tx.free_vtag1 = true;
+       }
+
        rc = mbox_process_msg(mbox, (void *)&rsp);
        if (rc)
                return rc;
@@ -880,120 +902,271 @@ npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
 }
 
 static int
-npc_vtag_action_program(struct roc_npc *roc_npc,
-                       const struct roc_npc_action actions[],
-                       struct roc_npc_flow *flow)
+npc_vtag_insert_action_parse(const struct roc_npc_action actions[],
+                            struct roc_npc_flow *flow,
+                            struct npc_action_vtag_info *vlan_info,
+                            int *parsed_cnt)
 {
-       uint16_t vlan_id = 0, vlan_ethtype = ROC_ETHER_TYPE_VLAN;
-       struct npc *npc = roc_npc_to_npc_priv(roc_npc);
-       struct roc_nix *roc_nix = roc_npc->roc_nix;
-       struct nix_vtag_config *vtag_cfg;
-       struct nix_vtag_config_rsp *rsp;
-       uint64_t rx_vtag_action = 0;
-       uint8_t vlan_pcp = 0;
-       struct mbox *mbox;
-       struct nix *nix;
-       int rc;
-
-       union {
-               uint64_t reg;
-               struct nix_tx_vtag_action_s act;
-       } tx_vtag_action;
-
-       nix = roc_nix_to_nix_priv(roc_nix);
-       mbox = (&nix->dev)->mbox;
-
-       flow->vtag_insert_enabled = false;
-
-       for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
-               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
-                       if (npc->vtag_actions == 1) {
-                               vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+       bool vlan_id_found = false, ethtype_found = false, pcp_found = false;
+       int count = 0;
 
-                               if (vtag_cfg == NULL)
-                                       return -ENOSPC;
+       *parsed_cnt = 0;
 
-                               vtag_cfg->cfg_type = VTAG_RX;
-                               vtag_cfg->rx.strip_vtag = 1;
-                               /* Always capture */
-                               vtag_cfg->rx.capture_vtag = 1;
-                               vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
-                               vtag_cfg->rx.vtag_type = 0;
+       /* This function parses parameters of one VLAN. When a parameter is
+        * found repeated, it treats it as the end of first VLAN's parameters
+        * and returns. The caller calls again to parse the parameters of the
+        * second VLAN.
+        */
 
-                               rc = mbox_process(mbox);
-                               if (rc)
-                                       return rc;
-                       }
+       for (; count < NPC_ACTION_MAX_VLAN_PARAMS; count++, actions++) {
+               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
+                       if (vlan_id_found)
+                               return 0;
 
-                       rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
-                       rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
-                       rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
-                       flow->vtag_action = rx_vtag_action;
-               } else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
                        const struct roc_npc_action_of_set_vlan_vid *vtag =
                                (const struct roc_npc_action_of_set_vlan_vid *)
                                        actions->conf;
-                       vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
-                       if (vlan_id > 0xfff) {
+
+                       vlan_info->vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
+
+                       if (vlan_info->vlan_id > 0xfff) {
                                plt_err("Invalid vlan_id for set vlan action");
                                return -EINVAL;
                        }
+
                        flow->vtag_insert_enabled = true;
+                       (*parsed_cnt)++;
+                       vlan_id_found = true;
                } else if (actions->type ==
                           ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT) {
+                       if (ethtype_found)
+                               return 0;
+
                        const struct roc_npc_action_of_push_vlan *ethtype =
                                (const struct roc_npc_action_of_push_vlan *)
                                        actions->conf;
-                       vlan_ethtype = plt_be_to_cpu_16(ethtype->ethertype);
-                       if (vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
-                           vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
+                       vlan_info->vlan_ethtype =
+                               plt_be_to_cpu_16(ethtype->ethertype);
+                       if (vlan_info->vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
+                           vlan_info->vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
                                plt_err("Invalid ethtype specified for push"
                                        " vlan action");
                                return -EINVAL;
                        }
                        flow->vtag_insert_enabled = true;
+                       (*parsed_cnt)++;
+                       ethtype_found = true;
                } else if (actions->type ==
                           ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
+                       if (pcp_found)
+                               return 0;
                        const struct roc_npc_action_of_set_vlan_pcp *pcp =
                                (const struct roc_npc_action_of_set_vlan_pcp *)
                                        actions->conf;
-                       vlan_pcp = pcp->vlan_pcp;
-                       if (vlan_pcp > 0x7) {
+                       vlan_info->vlan_pcp = pcp->vlan_pcp;
+                       if (vlan_info->vlan_pcp > 0x7) {
                                plt_err("Invalid PCP value for pcp action");
                                return -EINVAL;
                        }
                        flow->vtag_insert_enabled = true;
+                       (*parsed_cnt)++;
+                       pcp_found = true;
+               } else {
+                       return 0;
                }
        }
 
-       if (flow->vtag_insert_enabled) {
-               vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+       return 0;
+}
 
-               if (vtag_cfg == NULL)
-                       return -ENOSPC;
+static int
+npc_vtag_insert_action_configure(struct mbox *mbox, struct roc_npc_flow *flow,
+                                struct npc_action_vtag_info *vlan_info)
+{
+       struct nix_vtag_config *vtag_cfg;
+       struct nix_vtag_config_rsp *rsp;
+       int rc = 0;
 
-               vtag_cfg->cfg_type = VTAG_TX;
-               vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
-               vtag_cfg->tx.vtag0 =
-                       ((vlan_ethtype << 16) | (vlan_pcp << 13) | vlan_id);
+       union {
+               uint64_t reg;
+               struct nix_tx_vtag_action_s act;
+       } tx_vtag_action;
 
-               vtag_cfg->tx.cfg_vtag0 = 1;
-               rc = mbox_process_msg(mbox, (void *)&rsp);
-               if (rc)
-                       return rc;
+       vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
 
-               if (rsp->vtag0_idx < 0) {
-                       plt_err("Failed to config TX VTAG action");
-                       return -EINVAL;
-               }
+       if (vtag_cfg == NULL)
+               return -ENOSPC;
+
+       vtag_cfg->cfg_type = VTAG_TX;
+       vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
+       vtag_cfg->tx.vtag0 =
+               ((vlan_info[0].vlan_ethtype << 16) |
+                (vlan_info[0].vlan_pcp << 13) | vlan_info[0].vlan_id);
+
+       vtag_cfg->tx.cfg_vtag0 = 1;
+
+       if (flow->vtag_insert_count == 2) {
+               vtag_cfg->tx.vtag1 =
+                       ((vlan_info[1].vlan_ethtype << 16) |
+                        (vlan_info[1].vlan_pcp << 13) | vlan_info[1].vlan_id);
+
+               vtag_cfg->tx.cfg_vtag1 = 1;
+       }
+
+       rc = mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               return rc;
+
+       if (rsp->vtag0_idx < 0 ||
+           ((flow->vtag_insert_count == 2) && (rsp->vtag1_idx < 0))) {
+               plt_err("Failed to config TX VTAG action");
+               return -EINVAL;
+       }
 
-               tx_vtag_action.reg = 0;
-               tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
-               tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
-               tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
-               tx_vtag_action.act.vtag0_relptr =
+       tx_vtag_action.reg = 0;
+       tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
+       tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
+       tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
+       tx_vtag_action.act.vtag0_relptr = NIX_TX_VTAGACTION_VTAG0_RELPTR;
+
+       if (flow->vtag_insert_count == 2) {
+               tx_vtag_action.act.vtag1_def = rsp->vtag1_idx;
+               tx_vtag_action.act.vtag1_lid = NPC_LID_LA;
+               tx_vtag_action.act.vtag1_op = NIX_TX_VTAGOP_INSERT;
+               /* NIX_TX_VTAG_ACTION_S
+                *  If Vtag 0 is inserted, hardware adjusts the Vtag 1 byte
+                *  offset accordingly. Thus, if the two offsets are equal in
+                *  the structure, hardware inserts Vtag 1 immediately after
+                *  Vtag 0 in the packet.
+                */
+               tx_vtag_action.act.vtag1_relptr =
                        NIX_TX_VTAGACTION_VTAG0_RELPTR;
-               flow->vtag_action = tx_vtag_action.reg;
+       }
+
+       flow->vtag_action = tx_vtag_action.reg;
+
+       return 0;
+}
+
+static int
+npc_vtag_strip_action_configure(struct mbox *mbox,
+                               const struct roc_npc_action actions[],
+                               struct roc_npc_flow *flow, int *strip_cnt)
+{
+       struct nix_vtag_config *vtag_cfg;
+       uint64_t rx_vtag_action = 0;
+       int count = 0, rc = 0;
+
+       *strip_cnt = 0;
+
+       for (; count < NPC_ACTION_MAX_VLANS_STRIPPED; count++, actions++) {
+               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
+                       (*strip_cnt)++;
+       }
+
+       vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+
+       if (vtag_cfg == NULL)
+               return -ENOSPC;
+
+       vtag_cfg->cfg_type = VTAG_RX;
+       vtag_cfg->rx.strip_vtag = 1;
+       /* Always capture */
+       vtag_cfg->rx.capture_vtag = 1;
+       vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
+       vtag_cfg->rx.vtag_type = 0;
+
+       rc = mbox_process(mbox);
+       if (rc)
+               return rc;
+
+       rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
+       rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
+       rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
+
+       if (*strip_cnt == 2) {
+               rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 47);
+               rx_vtag_action |= ((uint64_t)NPC_LID_LB << 40);
+               rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR << 32;
+       }
+       flow->vtag_action = rx_vtag_action;
+
+       return 0;
+}
+
+static int
+npc_vtag_action_program(struct roc_npc *roc_npc,
+                       const struct roc_npc_action actions[],
+                       struct roc_npc_flow *flow)
+{
+       bool vlan_strip_parsed = false, vlan_insert_parsed = false;
+       const struct roc_npc_action *insert_actions;
+       struct roc_nix *roc_nix = roc_npc->roc_nix;
+       struct npc_action_vtag_info vlan_info[2];
+       int parsed_cnt = 0, strip_cnt = 0;
+       int tot_vlan_params = 0;
+       struct mbox *mbox;
+       struct nix *nix;
+       int i, rc;
+
+       nix = roc_nix_to_nix_priv(roc_nix);
+       mbox = (&nix->dev)->mbox;
+
+       memset(vlan_info, 0, sizeof(vlan_info));
+
+       flow->vtag_insert_enabled = false;
+
+       for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
+               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
+                       if (vlan_strip_parsed) {
+                               plt_err("Incorrect VLAN strip actions");
+                               return -EINVAL;
+                       }
+                       rc = npc_vtag_strip_action_configure(mbox, actions,
+                                                            flow, &strip_cnt);
+                       if (rc)
+                               return rc;
+
+                       if (strip_cnt == 2)
+                               actions++;
+
+                       vlan_strip_parsed = true;
+               } else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT ||
+                          actions->type ==
+                                  ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT ||
+                          actions->type ==
+                                  ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
+                       if (vlan_insert_parsed) {
+                               plt_err("Incorrect VLAN insert actions");
+                               return -EINVAL;
+                       }
+
+                       insert_actions = actions;
+
+                       for (i = 0; i < 2; i++) {
+                               rc = npc_vtag_insert_action_parse(
+                                       insert_actions, flow, &vlan_info[i],
+                                       &parsed_cnt);
+
+                               if (rc)
+                                       return rc;
+
+                               if (parsed_cnt) {
+                                       insert_actions += parsed_cnt;
+                                       tot_vlan_params += parsed_cnt;
+                                       flow->vtag_insert_count++;
+                               }
+                       }
+                       actions += tot_vlan_params - 1;
+                       vlan_insert_parsed = true;
+               }
+       }
+
+       if (flow->vtag_insert_enabled) {
+               rc = npc_vtag_insert_action_configure(mbox, flow, vlan_info);
+
+               if (rc)
+                       return rc;
        }
        return 0;
 }
index bab25fd..4d6f8f8 100644 (file)
@@ -135,6 +135,7 @@ struct roc_npc_flow {
        uint64_t npc_action;
        uint64_t vtag_action;
        bool vtag_insert_enabled;
+       uint8_t vtag_insert_count;
 #define ROC_NPC_MAX_FLOW_PATTERNS 32
        struct roc_npc_flow_dump_data dump_data[ROC_NPC_MAX_FLOW_PATTERNS];
        uint16_t num_patterns;
index 5b884e3..b11f5b5 100644 (file)
        (NPC_NIXLF_MAX * NPC_MCAME_PER_LF +                                    \
         (NPC_RVUPF_MAX_10XX - 1) * NPC_MCAME_PER_PF)
 
+#define NPC_ACTION_MAX_VLAN_PARAMS    3
+#define NPC_ACTION_MAX_VLANS_STRIPPED 2
+
+struct npc_action_vtag_info {
+       uint16_t vlan_id;
+       uint16_t vlan_ethtype;
+       uint8_t vlan_pcp;
+};
+
 enum npc_err_status {
        NPC_ERR_PARAM = -1024,
        NPC_ERR_NO_MEM,
@@ -351,7 +360,7 @@ struct npc {
        uint16_t flow_max_priority;             /* Max priority for flow */
        uint16_t switch_header_type; /* Suppprted switch header type */
        uint32_t mark_actions;       /* Number of mark actions */
-       uint32_t vtag_actions;       /* vtag insert/strip actions */
+       uint32_t vtag_strip_actions; /* vtag insert/strip actions */
        uint16_t pf_func;            /* pf_func of device */
        npc_dxcfg_t prx_dxcfg;       /* intf, lid, lt, extract */
        npc_fxcfg_t prx_fxcfg;       /* Flag extract */