Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / net / ethernet / intel / ice / ice_switch.c
index fce2046..d4baae8 100644 (file)
  * byte 0 = 0x2: to identify it as locally administered DA MAC
  * byte 6 = 0x2: to identify it as locally administered SA MAC
  * byte 12 = 0x81 & byte 13 = 0x00:
- *     In case of VLAN filter first two bytes defines ether type (0x8100)
- *     and remaining two bytes are placeholder for programming a given VLAN ID
- *     In case of Ether type filter it is treated as header without VLAN tag
- *     and byte 12 and 13 is used to program a given Ether type instead
+ *      In case of VLAN filter first two bytes defines ether type (0x8100)
+ *      and remaining two bytes are placeholder for programming a given VLAN ID
+ *      In case of Ether type filter it is treated as header without VLAN tag
+ *      and byte 12 and 13 is used to program a given Ether type instead
  */
-#define DUMMY_ETH_HDR_LEN              16
 static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
                                                        0x2, 0, 0, 0, 0, 0,
                                                        0x81, 0, 0, 0};
@@ -42,6 +41,7 @@ enum {
        ICE_PKT_GTP_NOPAY       = BIT(8),
        ICE_PKT_KMALLOC         = BIT(9),
        ICE_PKT_PPPOE           = BIT(10),
+       ICE_PKT_L2TPV3          = BIT(11),
 };
 
 struct ice_dummy_pkt_offsets {
@@ -1258,6 +1258,65 @@ ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv6_udp) = {
        0x00, 0x00,             /* 2 bytes for 4 bytes alignment */
 };
 
+ICE_DECLARE_PKT_OFFSETS(ipv4_l2tpv3) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV4_OFOS,        14 },
+       { ICE_L2TPV3,           34 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(ipv4_l2tpv3) = {
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x08, 0x00,             /* ICE_ETYPE_OL 12 */
+
+       0x45, 0x00, 0x00, 0x20, /* ICE_IPV4_IL 14 */
+       0x00, 0x00, 0x40, 0x00,
+       0x40, 0x73, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 34 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,             /* 2 bytes for 4 bytes alignment */
+};
+
+ICE_DECLARE_PKT_OFFSETS(ipv6_l2tpv3) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV6_OFOS,        14 },
+       { ICE_L2TPV3,           54 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(ipv6_l2tpv3) = {
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x86, 0xDD,             /* ICE_ETYPE_OL 12 */
+
+       0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 14 */
+       0x00, 0x0c, 0x73, 0x40,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 54 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,             /* 2 bytes for 4 bytes alignment */
+};
+
 static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
        ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPU | ICE_PKT_OUTER_IPV6 |
                                  ICE_PKT_GTP_NOPAY),
@@ -1297,6 +1356,8 @@ static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
        ICE_PKT_PROFILE(udp_tun_ipv6_tcp, ICE_PKT_TUN_UDP |
                                          ICE_PKT_INNER_IPV6 |
                                          ICE_PKT_INNER_TCP),
+       ICE_PKT_PROFILE(ipv6_l2tpv3, ICE_PKT_L2TPV3 | ICE_PKT_OUTER_IPV6),
+       ICE_PKT_PROFILE(ipv4_l2tpv3, ICE_PKT_L2TPV3),
        ICE_PKT_PROFILE(udp_tun_tcp, ICE_PKT_TUN_UDP | ICE_PKT_INNER_TCP),
        ICE_PKT_PROFILE(udp_tun_ipv6_udp, ICE_PKT_TUN_UDP |
                                          ICE_PKT_INNER_IPV6),
@@ -1307,14 +1368,6 @@ static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
        ICE_PKT_PROFILE(tcp, 0),
 };
 
-#define ICE_SW_RULE_RX_TX_HDR_SIZE(s, l)       struct_size((s), hdr_data, (l))
-#define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s)      \
-       ICE_SW_RULE_RX_TX_HDR_SIZE((s), DUMMY_ETH_HDR_LEN)
-#define ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s)       \
-       ICE_SW_RULE_RX_TX_HDR_SIZE((s), 0)
-#define ICE_SW_RULE_LG_ACT_SIZE(s, n)          struct_size((s), act, (n))
-#define ICE_SW_RULE_VSI_LIST_SIZE(s, n)                struct_size((s), vsi, (n))
-
 /* this is a recipe to profile association bitmap */
 static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES],
                          ICE_MAX_NUM_PROFILES);
@@ -1574,21 +1627,16 @@ ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi)
  */
 static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle)
 {
-       struct ice_vsi_ctx *vsi;
+       struct ice_vsi_ctx *vsi = ice_get_vsi_ctx(hw, vsi_handle);
        u8 i;
 
-       vsi = ice_get_vsi_ctx(hw, vsi_handle);
        if (!vsi)
                return;
        ice_for_each_traffic_class(i) {
-               if (vsi->lan_q_ctx[i]) {
-                       devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]);
-                       vsi->lan_q_ctx[i] = NULL;
-               }
-               if (vsi->rdma_q_ctx[i]) {
-                       devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]);
-                       vsi->rdma_q_ctx[i] = NULL;
-               }
+               devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]);
+               vsi->lan_q_ctx[i] = NULL;
+               devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]);
+               vsi->rdma_q_ctx[i] = NULL;
        }
 }
 
@@ -1718,18 +1766,36 @@ ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
 int
 ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
 {
-       struct ice_vsi_ctx *ctx;
+       struct ice_vsi_ctx *ctx, *cached_ctx;
+       int status;
+
+       cached_ctx = ice_get_vsi_ctx(hw, vsi_handle);
+       if (!cached_ctx)
+               return -ENOENT;
 
-       ctx = ice_get_vsi_ctx(hw, vsi_handle);
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
-               return -EIO;
+               return -ENOMEM;
+
+       ctx->info.q_opt_rss = cached_ctx->info.q_opt_rss;
+       ctx->info.q_opt_tc = cached_ctx->info.q_opt_tc;
+       ctx->info.q_opt_flags = cached_ctx->info.q_opt_flags;
+
+       ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
 
        if (enable)
                ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
        else
                ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
 
-       return ice_update_vsi(hw, vsi_handle, ctx, NULL);
+       status = ice_update_vsi(hw, vsi_handle, ctx, NULL);
+       if (!status) {
+               cached_ctx->info.q_opt_flags = ctx->info.q_opt_flags;
+               cached_ctx->info.valid_sections |= ctx->info.valid_sections;
+       }
+
+       kfree(ctx);
+       return status;
 }
 
 /**
@@ -1746,15 +1812,11 @@ ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
                           enum ice_sw_lkup_type lkup_type,
                           enum ice_adminq_opc opc)
 {
-       struct ice_aqc_alloc_free_res_elem *sw_buf;
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
+       u16 buf_len = __struct_size(sw_buf);
        struct ice_aqc_res_elem *vsi_ele;
-       u16 buf_len;
        int status;
 
-       buf_len = struct_size(sw_buf, elem, 1);
-       sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL);
-       if (!sw_buf)
-               return -ENOMEM;
        sw_buf->num_elems = cpu_to_le16(1);
 
        if (lkup_type == ICE_SW_LKUP_MAC ||
@@ -1766,28 +1828,30 @@ ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
            lkup_type == ICE_SW_LKUP_DFLT) {
                sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP);
        } else if (lkup_type == ICE_SW_LKUP_VLAN) {
-               sw_buf->res_type =
-                       cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
+               if (opc == ice_aqc_opc_alloc_res)
+                       sw_buf->res_type =
+                               cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE |
+                                           ICE_AQC_RES_TYPE_FLAG_SHARED);
+               else
+                       sw_buf->res_type =
+                               cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
        } else {
-               status = -EINVAL;
-               goto ice_aq_alloc_free_vsi_list_exit;
+               return -EINVAL;
        }
 
        if (opc == ice_aqc_opc_free_res)
                sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id);
 
-       status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL);
+       status = ice_aq_alloc_free_res(hw, sw_buf, buf_len, opc);
        if (status)
-               goto ice_aq_alloc_free_vsi_list_exit;
+               return status;
 
        if (opc == ice_aqc_opc_alloc_res) {
                vsi_ele = &sw_buf->elem[0];
                *vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp);
        }
 
-ice_aq_alloc_free_vsi_list_exit:
-       devm_kfree(ice_hw_to_dev(hw), sw_buf);
-       return status;
+       return 0;
 }
 
 /**
@@ -1835,7 +1899,7 @@ ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
  *
  * Add(0x0290)
  */
-static int
+int
 ice_aq_add_recipe(struct ice_hw *hw,
                  struct ice_aqc_recipe_data_elem *s_recipe_list,
                  u16 num_recipes, struct ice_sq_cd *cd)
@@ -1872,7 +1936,7 @@ ice_aq_add_recipe(struct ice_hw *hw,
  * The caller must supply enough space in s_recipe_list to hold all possible
  * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES.
  */
-static int
+int
 ice_aq_get_recipe(struct ice_hw *hw,
                  struct ice_aqc_recipe_data_elem *s_recipe_list,
                  u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd)
@@ -1965,7 +2029,7 @@ error_out:
  * @cd: pointer to command details structure or NULL
  * Recipe to profile association (0x0291)
  */
-static int
+int
 ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
                             struct ice_sq_cd *cd)
 {
@@ -1991,7 +2055,7 @@ ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
  * @cd: pointer to command details structure or NULL
  * Associate profile ID with given recipe (0x0293)
  */
-static int
+int
 ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
                             struct ice_sq_cd *cd)
 {
@@ -2015,26 +2079,20 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
  * @hw: pointer to the hardware structure
  * @rid: recipe ID returned as response to AQ call
  */
-static int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
+int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
 {
-       struct ice_aqc_alloc_free_res_elem *sw_buf;
-       u16 buf_len;
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
+       u16 buf_len = __struct_size(sw_buf);
        int status;
 
-       buf_len = struct_size(sw_buf, elem, 1);
-       sw_buf = kzalloc(buf_len, GFP_KERNEL);
-       if (!sw_buf)
-               return -ENOMEM;
-
        sw_buf->num_elems = cpu_to_le16(1);
        sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE <<
                                        ICE_AQC_RES_TYPE_S) |
                                        ICE_AQC_RES_TYPE_FLAG_SHARED);
-       status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len,
-                                      ice_aqc_opc_alloc_res, NULL);
+       status = ice_aq_alloc_free_res(hw, sw_buf, buf_len,
+                                      ice_aqc_opc_alloc_res);
        if (!status)
                *rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp);
-       kfree(sw_buf);
 
        return status;
 }
@@ -2197,6 +2255,10 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
                /* Propagate some data to the recipe database */
                recps[idx].is_root = !!is_root;
                recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
+               recps[idx].need_pass_l2 = root_bufs.content.act_ctrl &
+                                         ICE_AQ_RECIPE_ACT_NEED_PASS_L2;
+               recps[idx].allow_pass_l2 = root_bufs.content.act_ctrl &
+                                          ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
                bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS);
                if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) {
                        recps[idx].chain_idx = root_bufs.content.result_indx &
@@ -2274,9 +2336,7 @@ int ice_get_initial_sw_cfg(struct ice_hw *hw)
        int status;
        u16 i;
 
-       rbuf = devm_kzalloc(ice_hw_to_dev(hw), ICE_SW_CFG_MAX_BUF_LEN,
-                           GFP_KERNEL);
-
+       rbuf = kzalloc(ICE_SW_CFG_MAX_BUF_LEN, GFP_KERNEL);
        if (!rbuf)
                return -ENOMEM;
 
@@ -2324,7 +2384,7 @@ int ice_get_initial_sw_cfg(struct ice_hw *hw)
                }
        } while (req_desc && !status);
 
-       devm_kfree(ice_hw_to_dev(hw), rbuf);
+       kfree(rbuf);
        return status;
 }
 
@@ -2386,6 +2446,15 @@ static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
        }
 }
 
+/**
+ * ice_fill_eth_hdr - helper to copy dummy_eth_hdr into supplied buffer
+ * @eth_hdr: pointer to buffer to populate
+ */
+void ice_fill_eth_hdr(u8 *eth_hdr)
+{
+       memcpy(eth_hdr, dummy_eth_header, DUMMY_ETH_HDR_LEN);
+}
+
 /**
  * ice_fill_sw_rule - Helper function to fill switch rule structure
  * @hw: pointer to the hardware structure
@@ -2423,25 +2492,24 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
 
        switch (f_info->fltr_act) {
        case ICE_FWD_TO_VSI:
-               act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
-                       ICE_SINGLE_ACT_VSI_ID_M;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+                                 f_info->fwd_id.hw_vsi_id);
                if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
                        act |= ICE_SINGLE_ACT_VSI_FORWARDING |
                                ICE_SINGLE_ACT_VALID_BIT;
                break;
        case ICE_FWD_TO_VSI_LIST:
                act |= ICE_SINGLE_ACT_VSI_LIST;
-               act |= (f_info->fwd_id.vsi_list_id <<
-                       ICE_SINGLE_ACT_VSI_LIST_ID_S) &
-                       ICE_SINGLE_ACT_VSI_LIST_ID_M;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_LIST_ID_M,
+                                 f_info->fwd_id.vsi_list_id);
                if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
                        act |= ICE_SINGLE_ACT_VSI_FORWARDING |
                                ICE_SINGLE_ACT_VALID_BIT;
                break;
        case ICE_FWD_TO_Q:
                act |= ICE_SINGLE_ACT_TO_Q;
-               act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
-                       ICE_SINGLE_ACT_Q_INDEX_M;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+                                 f_info->fwd_id.q_id);
                break;
        case ICE_DROP_PACKET:
                act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
@@ -2451,10 +2519,9 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
                q_rgn = f_info->qgrp_size > 0 ?
                        (u8)ilog2(f_info->qgrp_size) : 0;
                act |= ICE_SINGLE_ACT_TO_Q;
-               act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
-                       ICE_SINGLE_ACT_Q_INDEX_M;
-               act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
-                       ICE_SINGLE_ACT_Q_REGION_M;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+                                 f_info->fwd_id.q_id);
+               act |= FIELD_PREP(ICE_SINGLE_ACT_Q_REGION_M, q_rgn);
                break;
        default:
                return;
@@ -2580,7 +2647,7 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
                m_ent->fltr_info.fwd_id.hw_vsi_id;
 
        act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
-       act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M;
+       act |= FIELD_PREP(ICE_LG_ACT_VSI_LIST_ID_M, id);
        if (m_ent->vsi_count > 1)
                act |= ICE_LG_ACT_VSI_LIST;
        lg_act->act[0] = cpu_to_le32(act);
@@ -2588,16 +2655,15 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
        /* Second action descriptor type */
        act = ICE_LG_ACT_GENERIC;
 
-       act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;
+       act |= FIELD_PREP(ICE_LG_ACT_GENERIC_VALUE_M, 1);
        lg_act->act[1] = cpu_to_le32(act);
 
-       act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<
-              ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;
+       act = FIELD_PREP(ICE_LG_ACT_GENERIC_OFFSET_M,
+                        ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX);
 
        /* Third action Marker value */
        act |= ICE_LG_ACT_GENERIC;
-       act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &
-               ICE_LG_ACT_GENERIC_VALUE_M;
+       act |= FIELD_PREP(ICE_LG_ACT_GENERIC_VALUE_M, sw_marker);
 
        lg_act->act[2] = cpu_to_le32(act);
 
@@ -2606,9 +2672,9 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
                         ice_aqc_opc_update_sw_rules);
 
        /* Update the action to point to the large action ID */
-       rx_tx->act = cpu_to_le32(ICE_SINGLE_ACT_PTR |
-                                ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &
-                                 ICE_SINGLE_ACT_PTR_VAL_M));
+       act = ICE_SINGLE_ACT_PTR;
+       act |= FIELD_PREP(ICE_SINGLE_ACT_PTR_VAL_M, l_id);
+       rx_tx->act = cpu_to_le32(act);
 
        /* Use the filter rule ID of the previously created rule with single
         * act. Once the update happens, hardware will treat this as large
@@ -3045,7 +3111,7 @@ ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)
  * handle element. This can be extended further to search VSI list with more
  * than 1 vsi_count. Returns pointer to VSI list entry if found.
  */
-static struct ice_vsi_list_map_info *
+struct ice_vsi_list_map_info *
 ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
                        u16 *vsi_list_id)
 {
@@ -3056,7 +3122,7 @@ ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
 
        list_head = &sw->recp_list[recp_id].filt_rules;
        list_for_each_entry(list_itr, list_head, list_entry) {
-               if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) {
+               if (list_itr->vsi_list_info) {
                        map_info = list_itr->vsi_list_info;
                        if (test_bit(vsi_handle, map_info->vsi_map)) {
                                *vsi_list_id = map_info->vsi_list_id;
@@ -3326,54 +3392,6 @@ exit:
        return status;
 }
 
-/**
- * ice_mac_fltr_exist - does this MAC filter exist for given VSI
- * @hw: pointer to the hardware structure
- * @mac: MAC address to be checked (for MAC filter)
- * @vsi_handle: check MAC filter for this VSI
- */
-bool ice_mac_fltr_exist(struct ice_hw *hw, u8 *mac, u16 vsi_handle)
-{
-       struct ice_fltr_mgmt_list_entry *entry;
-       struct list_head *rule_head;
-       struct ice_switch_info *sw;
-       struct mutex *rule_lock; /* Lock to protect filter rule list */
-       u16 hw_vsi_id;
-
-       if (!ice_is_vsi_valid(hw, vsi_handle))
-               return false;
-
-       hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
-       sw = hw->switch_info;
-       rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
-       if (!rule_head)
-               return false;
-
-       rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
-       mutex_lock(rule_lock);
-       list_for_each_entry(entry, rule_head, list_entry) {
-               struct ice_fltr_info *f_info = &entry->fltr_info;
-               u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
-
-               if (is_zero_ether_addr(mac_addr))
-                       continue;
-
-               if (f_info->flag != ICE_FLTR_TX ||
-                   f_info->src_id != ICE_SRC_ID_VSI ||
-                   f_info->lkup_type != ICE_SW_LKUP_MAC ||
-                   f_info->fltr_act != ICE_FWD_TO_VSI ||
-                   hw_vsi_id != f_info->fwd_id.hw_vsi_id)
-                       continue;
-
-               if (ether_addr_equal(mac, mac_addr)) {
-                       mutex_unlock(rule_lock);
-                       return true;
-               }
-       }
-       mutex_unlock(rule_lock);
-       return false;
-}
-
 /**
  * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI
  * @hw: pointer to the hardware structure
@@ -3449,31 +3467,15 @@ bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle)
  * ice_add_mac - Add a MAC address based filter rule
  * @hw: pointer to the hardware structure
  * @m_list: list of MAC addresses and forwarding information
- *
- * IMPORTANT: When the ucast_shared flag is set to false and m_list has
- * multiple unicast addresses, the function assumes that all the
- * addresses are unique in a given add_mac call. It doesn't
- * check for duplicates in this case, removing duplicates from a given
- * list should be taken care of in the caller of this function.
  */
 int ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
 {
-       struct ice_sw_rule_lkup_rx_tx *s_rule, *r_iter;
        struct ice_fltr_list_entry *m_list_itr;
-       struct list_head *rule_head;
-       u16 total_elem_left, s_rule_size;
-       struct ice_switch_info *sw;
-       struct mutex *rule_lock; /* Lock to protect filter rule list */
-       u16 num_unicast = 0;
        int status = 0;
-       u8 elem_sent;
 
        if (!m_list || !hw)
                return -EINVAL;
 
-       s_rule = NULL;
-       sw = hw->switch_info;
-       rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
        list_for_each_entry(m_list_itr, m_list, list_entry) {
                u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
                u16 vsi_handle;
@@ -3492,106 +3494,13 @@ int ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
                if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||
                    is_zero_ether_addr(add))
                        return -EINVAL;
-               if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
-                       /* Don't overwrite the unicast address */
-                       mutex_lock(rule_lock);
-                       if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC,
-                                               &m_list_itr->fltr_info)) {
-                               mutex_unlock(rule_lock);
-                               return -EEXIST;
-                       }
-                       mutex_unlock(rule_lock);
-                       num_unicast++;
-               } else if (is_multicast_ether_addr(add) ||
-                          (is_unicast_ether_addr(add) && hw->ucast_shared)) {
-                       m_list_itr->status =
-                               ice_add_rule_internal(hw, ICE_SW_LKUP_MAC,
-                                                     m_list_itr);
-                       if (m_list_itr->status)
-                               return m_list_itr->status;
-               }
-       }
-
-       mutex_lock(rule_lock);
-       /* Exit if no suitable entries were found for adding bulk switch rule */
-       if (!num_unicast) {
-               status = 0;
-               goto ice_add_mac_exit;
-       }
-
-       rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
 
-       /* Allocate switch rule buffer for the bulk update for unicast */
-       s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule);
-       s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,
-                             GFP_KERNEL);
-       if (!s_rule) {
-               status = -ENOMEM;
-               goto ice_add_mac_exit;
-       }
-
-       r_iter = s_rule;
-       list_for_each_entry(m_list_itr, m_list, list_entry) {
-               struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
-               u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
-
-               if (is_unicast_ether_addr(mac_addr)) {
-                       ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter,
-                                        ice_aqc_opc_add_sw_rules);
-                       r_iter = (typeof(s_rule))((u8 *)r_iter + s_rule_size);
-               }
-       }
-
-       /* Call AQ bulk switch rule update for all unicast addresses */
-       r_iter = s_rule;
-       /* Call AQ switch rule in AQ_MAX chunk */
-       for (total_elem_left = num_unicast; total_elem_left > 0;
-            total_elem_left -= elem_sent) {
-               struct ice_sw_rule_lkup_rx_tx *entry = r_iter;
-
-               elem_sent = min_t(u8, total_elem_left,
-                                 (ICE_AQ_MAX_BUF_LEN / s_rule_size));
-               status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size,
-                                        elem_sent, ice_aqc_opc_add_sw_rules,
-                                        NULL);
-               if (status)
-                       goto ice_add_mac_exit;
-               r_iter = (typeof(s_rule))
-                       ((u8 *)r_iter + (elem_sent * s_rule_size));
+               m_list_itr->status = ice_add_rule_internal(hw, ICE_SW_LKUP_MAC,
+                                                          m_list_itr);
+               if (m_list_itr->status)
+                       return m_list_itr->status;
        }
 
-       /* Fill up rule ID based on the value returned from FW */
-       r_iter = s_rule;
-       list_for_each_entry(m_list_itr, m_list, list_entry) {
-               struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
-               u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
-               struct ice_fltr_mgmt_list_entry *fm_entry;
-
-               if (is_unicast_ether_addr(mac_addr)) {
-                       f_info->fltr_rule_id = le16_to_cpu(r_iter->index);
-                       f_info->fltr_act = ICE_FWD_TO_VSI;
-                       /* Create an entry to track this MAC address */
-                       fm_entry = devm_kzalloc(ice_hw_to_dev(hw),
-                                               sizeof(*fm_entry), GFP_KERNEL);
-                       if (!fm_entry) {
-                               status = -ENOMEM;
-                               goto ice_add_mac_exit;
-                       }
-                       fm_entry->fltr_info = *f_info;
-                       fm_entry->vsi_count = 1;
-                       /* The book keeping entries will get removed when
-                        * base driver calls remove filter AQ command
-                        */
-
-                       list_add(&fm_entry->list_entry, rule_head);
-                       r_iter = (typeof(s_rule))((u8 *)r_iter + s_rule_size);
-               }
-       }
-
-ice_add_mac_exit:
-       mutex_unlock(rule_lock);
-       if (s_rule)
-               devm_kfree(ice_hw_to_dev(hw), s_rule);
        return status;
 }
 
@@ -3978,38 +3887,6 @@ ice_check_if_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle,
        return ret;
 }
 
-/**
- * ice_find_ucast_rule_entry - Search for a unicast MAC filter rule entry
- * @hw: pointer to the hardware structure
- * @recp_id: lookup type for which the specified rule needs to be searched
- * @f_info: rule information
- *
- * Helper function to search for a unicast rule entry - this is to be used
- * to remove unicast MAC filter that is not shared with other VSIs on the
- * PF switch.
- *
- * Returns pointer to entry storing the rule if found
- */
-static struct ice_fltr_mgmt_list_entry *
-ice_find_ucast_rule_entry(struct ice_hw *hw, u8 recp_id,
-                         struct ice_fltr_info *f_info)
-{
-       struct ice_switch_info *sw = hw->switch_info;
-       struct ice_fltr_mgmt_list_entry *list_itr;
-       struct list_head *list_head;
-
-       list_head = &sw->recp_list[recp_id].filt_rules;
-       list_for_each_entry(list_itr, list_head, list_entry) {
-               if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
-                           sizeof(f_info->l_data)) &&
-                   f_info->fwd_id.hw_vsi_id ==
-                   list_itr->fltr_info.fwd_id.hw_vsi_id &&
-                   f_info->flag == list_itr->fltr_info.flag)
-                       return list_itr;
-       }
-       return NULL;
-}
-
 /**
  * ice_remove_mac - remove a MAC address based filter rule
  * @hw: pointer to the hardware structure
@@ -4026,15 +3903,12 @@ ice_find_ucast_rule_entry(struct ice_hw *hw, u8 recp_id,
 int ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
 {
        struct ice_fltr_list_entry *list_itr, *tmp;
-       struct mutex *rule_lock; /* Lock to protect filter rule list */
 
        if (!m_list)
                return -EINVAL;
 
-       rule_lock = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
        list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) {
                enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;
-               u8 *add = &list_itr->fltr_info.l_data.mac.mac_addr[0];
                u16 vsi_handle;
 
                if (l_type != ICE_SW_LKUP_MAC)
@@ -4046,19 +3920,7 @@ int ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
 
                list_itr->fltr_info.fwd_id.hw_vsi_id =
                                        ice_get_hw_vsi_num(hw, vsi_handle);
-               if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
-                       /* Don't remove the unicast address that belongs to
-                        * another VSI on the switch, since it is not being
-                        * shared...
-                        */
-                       mutex_lock(rule_lock);
-                       if (!ice_find_ucast_rule_entry(hw, ICE_SW_LKUP_MAC,
-                                                      &list_itr->fltr_info)) {
-                               mutex_unlock(rule_lock);
-                               return -ENOENT;
-                       }
-                       mutex_unlock(rule_lock);
-               }
+
                list_itr->status = ice_remove_rule_internal(hw,
                                                            ICE_SW_LKUP_MAC,
                                                            list_itr);
@@ -4445,6 +4307,13 @@ ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
                goto free_fltr_list;
 
        list_for_each_entry(list_itr, &vsi_list_head, list_entry) {
+               /* Avoid enabling or disabling VLAN zero twice when in double
+                * VLAN mode
+                */
+               if (ice_is_dvm_ena(hw) &&
+                   list_itr->fltr_info.l_data.vlan.tpid == 0)
+                       continue;
+
                vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
                if (rm_vlan_promisc)
                        status = ice_clear_vsi_promisc(hw, vsi_handle,
@@ -4452,7 +4321,7 @@ ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
                else
                        status = ice_set_vsi_promisc(hw, vsi_handle,
                                                     promisc_mask, vlan_id);
-               if (status)
+               if (status && status != -EEXIST)
                        break;
        }
 
@@ -4549,29 +4418,19 @@ int
 ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
                   u16 *counter_id)
 {
-       struct ice_aqc_alloc_free_res_elem *buf;
-       u16 buf_len;
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+       u16 buf_len = __struct_size(buf);
        int status;
 
-       /* Allocate resource */
-       buf_len = struct_size(buf, elem, 1);
-       buf = kzalloc(buf_len, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
        buf->num_elems = cpu_to_le16(num_items);
-       buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
-                                     ICE_AQC_RES_TYPE_M) | alloc_shared);
+       buf->res_type = cpu_to_le16(FIELD_PREP(ICE_AQC_RES_TYPE_M, type) |
+                                   alloc_shared);
 
-       status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
-                                      ice_aqc_opc_alloc_res, NULL);
+       status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_alloc_res);
        if (status)
-               goto exit;
+               return status;
 
        *counter_id = le16_to_cpu(buf->elem[0].e.sw_resp);
-
-exit:
-       kfree(buf);
        return status;
 }
 
@@ -4587,27 +4446,54 @@ int
 ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
                  u16 counter_id)
 {
-       struct ice_aqc_alloc_free_res_elem *buf;
-       u16 buf_len;
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+       u16 buf_len = __struct_size(buf);
        int status;
 
-       /* Free resource */
-       buf_len = struct_size(buf, elem, 1);
-       buf = kzalloc(buf_len, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
        buf->num_elems = cpu_to_le16(num_items);
-       buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
-                                     ICE_AQC_RES_TYPE_M) | alloc_shared);
+       buf->res_type = cpu_to_le16(FIELD_PREP(ICE_AQC_RES_TYPE_M, type) |
+                                   alloc_shared);
        buf->elem[0].e.sw_resp = cpu_to_le16(counter_id);
 
-       status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
-                                      ice_aqc_opc_free_res, NULL);
+       status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_free_res);
        if (status)
                ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n");
 
-       kfree(buf);
+       return status;
+}
+
+#define ICE_PROTOCOL_ENTRY(id, ...) {          \
+       .prot_type      = id,                   \
+       .offs           = {__VA_ARGS__},        \
+}
+
+/**
+ * ice_share_res - set a resource as shared or dedicated
+ * @hw: hw struct of original owner of resource
+ * @type: resource type
+ * @shared: is the resource being set to shared
+ * @res_id: resource id (descriptor)
+ */
+int ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id)
+{
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+       u16 buf_len = __struct_size(buf);
+       u16 res_type;
+       int status;
+
+       buf->num_elems = cpu_to_le16(1);
+       res_type = FIELD_PREP(ICE_AQC_RES_TYPE_M, type);
+       if (shared)
+               res_type |= ICE_AQC_RES_TYPE_FLAG_SHARED;
+
+       buf->res_type = cpu_to_le16(res_type);
+       buf->elem[0].e.sw_resp = cpu_to_le16(res_id);
+       status = ice_aq_alloc_free_res(hw, buf, buf_len,
+                                      ice_aqc_opc_share_res);
+       if (status)
+               ice_debug(hw, ICE_DBG_SW, "Could not set resource type %u id %u to %s\n",
+                         type, res_id, shared ? "SHARED" : "DEDICATED");
+
        return status;
 }
 
@@ -4621,28 +4507,38 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
  * structure is added to that union.
  */
 static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
-       { ICE_MAC_OFOS,         { 0, 2, 4, 6, 8, 10, 12 } },
-       { ICE_MAC_IL,           { 0, 2, 4, 6, 8, 10, 12 } },
-       { ICE_ETYPE_OL,         { 0 } },
-       { ICE_ETYPE_IL,         { 0 } },
-       { ICE_VLAN_OFOS,        { 2, 0 } },
-       { ICE_IPV4_OFOS,        { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
-       { ICE_IPV4_IL,          { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
-       { ICE_IPV6_OFOS,        { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
-                                26, 28, 30, 32, 34, 36, 38 } },
-       { ICE_IPV6_IL,          { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
-                                26, 28, 30, 32, 34, 36, 38 } },
-       { ICE_TCP_IL,           { 0, 2 } },
-       { ICE_UDP_OF,           { 0, 2 } },
-       { ICE_UDP_ILOS,         { 0, 2 } },
-       { ICE_VXLAN,            { 8, 10, 12, 14 } },
-       { ICE_GENEVE,           { 8, 10, 12, 14 } },
-       { ICE_NVGRE,            { 0, 2, 4, 6 } },
-       { ICE_GTP,              { 8, 10, 12, 14, 16, 18, 20, 22 } },
-       { ICE_GTP_NO_PAY,       { 8, 10, 12, 14 } },
-       { ICE_PPPOE,            { 0, 2, 4, 6 } },
-       { ICE_VLAN_EX,          { 2, 0 } },
-       { ICE_VLAN_IN,          { 2, 0 } },
+       ICE_PROTOCOL_ENTRY(ICE_MAC_OFOS, 0, 2, 4, 6, 8, 10, 12),
+       ICE_PROTOCOL_ENTRY(ICE_MAC_IL, 0, 2, 4, 6, 8, 10, 12),
+       ICE_PROTOCOL_ENTRY(ICE_ETYPE_OL, 0),
+       ICE_PROTOCOL_ENTRY(ICE_ETYPE_IL, 0),
+       ICE_PROTOCOL_ENTRY(ICE_VLAN_OFOS, 2, 0),
+       ICE_PROTOCOL_ENTRY(ICE_IPV4_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18),
+       ICE_PROTOCOL_ENTRY(ICE_IPV4_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18),
+       ICE_PROTOCOL_ENTRY(ICE_IPV6_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
+                          20, 22, 24, 26, 28, 30, 32, 34, 36, 38),
+       ICE_PROTOCOL_ENTRY(ICE_IPV6_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
+                          22, 24, 26, 28, 30, 32, 34, 36, 38),
+       ICE_PROTOCOL_ENTRY(ICE_TCP_IL, 0, 2),
+       ICE_PROTOCOL_ENTRY(ICE_UDP_OF, 0, 2),
+       ICE_PROTOCOL_ENTRY(ICE_UDP_ILOS, 0, 2),
+       ICE_PROTOCOL_ENTRY(ICE_VXLAN, 8, 10, 12, 14),
+       ICE_PROTOCOL_ENTRY(ICE_GENEVE, 8, 10, 12, 14),
+       ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6),
+       ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22),
+       ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14),
+       ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6),
+       ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10),
+       ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0),
+       ICE_PROTOCOL_ENTRY(ICE_VLAN_IN, 2, 0),
+       ICE_PROTOCOL_ENTRY(ICE_HW_METADATA,
+                          ICE_SOURCE_PORT_MDID_OFFSET,
+                          ICE_PTYPE_MDID_OFFSET,
+                          ICE_PACKET_LENGTH_MDID_OFFSET,
+                          ICE_SOURCE_VSI_MDID_OFFSET,
+                          ICE_PKT_VLAN_MDID_OFFSET,
+                          ICE_PKT_TUNNEL_MDID_OFFSET,
+                          ICE_PKT_TCP_MDID_OFFSET,
+                          ICE_PKT_ERROR_MDID_OFFSET),
 };
 
 static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
@@ -4664,21 +4560,23 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
        { ICE_GTP,              ICE_UDP_OF_HW },
        { ICE_GTP_NO_PAY,       ICE_UDP_ILOS_HW },
        { ICE_PPPOE,            ICE_PPPOE_HW },
+       { ICE_L2TPV3,           ICE_L2TPV3_HW },
        { ICE_VLAN_EX,          ICE_VLAN_OF_HW },
        { ICE_VLAN_IN,          ICE_VLAN_OL_HW },
+       { ICE_HW_METADATA,      ICE_META_DATA_ID_HW },
 };
 
 /**
  * ice_find_recp - find a recipe
  * @hw: pointer to the hardware structure
  * @lkup_exts: extension sequence to match
- * @tun_type: type of recipe tunnel
+ * @rinfo: information regarding the rule e.g. priority and action info
  *
  * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
  */
 static u16
 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
-             enum ice_sw_tunnel_type tun_type)
+             const struct ice_adv_rule_info *rinfo)
 {
        bool refresh_required = true;
        struct ice_sw_recipe *recp;
@@ -4739,9 +4637,12 @@ ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
                        }
                        /* If for "i"th recipe the found was never set to false
                         * then it means we found our match
-                        * Also tun type of recipe needs to be checked
+                        * Also tun type and *_pass_l2 of recipe needs to be
+                        * checked
                         */
-                       if (found && recp[i].tun_type == tun_type)
+                       if (found && recp[i].tun_type == rinfo->tun_type &&
+                           recp[i].need_pass_l2 == rinfo->need_pass_l2 &&
+                           recp[i].allow_pass_l2 == rinfo->allow_pass_l2)
                                return i; /* Return the recipe ID */
                }
        }
@@ -4971,7 +4872,7 @@ ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles,
        bitmap_zero(recipes, ICE_MAX_NUM_RECIPES);
        bitmap_zero(used_idx, ICE_MAX_FV_WORDS);
 
-       bitmap_set(possible_idx, 0, ICE_MAX_FV_WORDS);
+       bitmap_fill(possible_idx, ICE_MAX_FV_WORDS);
 
        /* For each profile we are going to associate the recipe with, add the
         * recipes that are associated with that profile. This will give us
@@ -5011,6 +4912,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                  unsigned long *profiles)
 {
        DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
+       struct ice_aqc_recipe_content *content;
        struct ice_aqc_recipe_data_elem *tmp;
        struct ice_aqc_recipe_data_elem *buf;
        struct ice_recp_grp_entry *entry;
@@ -5071,6 +4973,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                if (status)
                        goto err_unroll;
 
+               content = &buf[recps].content;
+
                /* Clear the result index of the located recipe, as this will be
                 * updated, if needed, later in the recipe creation process.
                 */
@@ -5081,26 +4985,24 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                /* if the recipe is a non-root recipe RID should be programmed
                 * as 0 for the rules to be applied correctly.
                 */
-               buf[recps].content.rid = 0;
-               memset(&buf[recps].content.lkup_indx, 0,
-                      sizeof(buf[recps].content.lkup_indx));
+               content->rid = 0;
+               memset(&content->lkup_indx, 0,
+                      sizeof(content->lkup_indx));
 
                /* All recipes use look-up index 0 to match switch ID. */
-               buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
-               buf[recps].content.mask[0] =
-                       cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
+               content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
+               content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
                /* Setup lkup_indx 1..4 to INVALID/ignore and set the mask
                 * to be 0
                 */
                for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
-                       buf[recps].content.lkup_indx[i] = 0x80;
-                       buf[recps].content.mask[i] = 0;
+                       content->lkup_indx[i] = 0x80;
+                       content->mask[i] = 0;
                }
 
                for (i = 0; i < entry->r_group.n_val_pairs; i++) {
-                       buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i];
-                       buf[recps].content.mask[i + 1] =
-                               cpu_to_le16(entry->fv_mask[i]);
+                       content->lkup_indx[i + 1] = entry->fv_idx[i];
+                       content->mask[i + 1] = cpu_to_le16(entry->fv_mask[i]);
                }
 
                if (rm->n_grp_count > 1) {
@@ -5114,10 +5016,10 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                        }
 
                        entry->chain_idx = chain_idx;
-                       buf[recps].content.result_indx =
+                       content->result_indx =
                                ICE_AQ_RECIPE_RESULT_EN |
-                               ((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
-                                ICE_AQ_RECIPE_RESULT_DATA_M);
+                               FIELD_PREP(ICE_AQ_RECIPE_RESULT_DATA_M,
+                                          chain_idx);
                        clear_bit(chain_idx, result_idx_bm);
                        chain_idx = find_first_bit(result_idx_bm,
                                                   ICE_MAX_FV_WORDS);
@@ -5128,7 +5030,13 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                            ICE_MAX_NUM_RECIPES);
                set_bit(buf[recps].recipe_indx,
                        (unsigned long *)buf[recps].recipe_bitmap);
-               buf[recps].content.act_ctrl_fwd_priority = rm->priority;
+               content->act_ctrl_fwd_priority = rm->priority;
+
+               if (rm->need_pass_l2)
+                       content->act_ctrl |= ICE_AQ_RECIPE_ACT_NEED_PASS_L2;
+
+               if (rm->allow_pass_l2)
+                       content->act_ctrl |= ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
                recps++;
        }
 
@@ -5166,9 +5074,11 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                if (status)
                        goto err_unroll;
 
+               content = &buf[recps].content;
+
                buf[recps].recipe_indx = (u8)rid;
-               buf[recps].content.rid = (u8)rid;
-               buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
+               content->rid = (u8)rid;
+               content->rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
                /* the new entry created should also be part of rg_list to
                 * make sure we have complete recipe
                 */
@@ -5180,16 +5090,13 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                        goto err_unroll;
                }
                last_chain_entry->rid = rid;
-               memset(&buf[recps].content.lkup_indx, 0,
-                      sizeof(buf[recps].content.lkup_indx));
+               memset(&content->lkup_indx, 0, sizeof(content->lkup_indx));
                /* All recipes use look-up index 0 to match switch ID. */
-               buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
-               buf[recps].content.mask[0] =
-                       cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
+               content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
+               content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
                for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
-                       buf[recps].content.lkup_indx[i] =
-                               ICE_AQ_RECIPE_LKUP_IGNORE;
-                       buf[recps].content.mask[i] = 0;
+                       content->lkup_indx[i] = ICE_AQ_RECIPE_LKUP_IGNORE;
+                       content->mask[i] = 0;
                }
 
                i = 1;
@@ -5201,8 +5108,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;
                list_for_each_entry(entry, &rm->rg_list, l_entry) {
                        last_chain_entry->fv_idx[i] = entry->chain_idx;
-                       buf[recps].content.lkup_indx[i] = entry->chain_idx;
-                       buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF);
+                       content->lkup_indx[i] = entry->chain_idx;
+                       content->mask[i++] = cpu_to_le16(0xFFFF);
                        set_bit(entry->rid, rm->r_bitmap);
                }
                list_add(&last_chain_entry->l_entry, &rm->rg_list);
@@ -5214,7 +5121,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                        status = -EINVAL;
                        goto err_unroll;
                }
-               buf[recps].content.act_ctrl_fwd_priority = rm->priority;
+               content->act_ctrl_fwd_priority = rm->priority;
 
                recps++;
                rm->root_rid = (u8)rid;
@@ -5279,6 +5186,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
                recp->n_grp_count = rm->n_grp_count;
                recp->tun_type = rm->tun_type;
+               recp->need_pass_l2 = rm->need_pass_l2;
+               recp->allow_pass_l2 = rm->allow_pass_l2;
                recp->recp_created = true;
        }
        rm->root_buf = buf;
@@ -5324,71 +5233,6 @@ ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm,
        return status;
 }
 
-/**
- * ice_tun_type_match_word - determine if tun type needs a match mask
- * @tun_type: tunnel type
- * @mask: mask to be used for the tunnel
- */
-static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask)
-{
-       switch (tun_type) {
-       case ICE_SW_TUN_GENEVE:
-       case ICE_SW_TUN_VXLAN:
-       case ICE_SW_TUN_NVGRE:
-       case ICE_SW_TUN_GTPU:
-       case ICE_SW_TUN_GTPC:
-               *mask = ICE_TUN_FLAG_MASK;
-               return true;
-
-       default:
-               *mask = 0;
-               return false;
-       }
-}
-
-/**
- * ice_add_special_words - Add words that are not protocols, such as metadata
- * @rinfo: other information regarding the rule e.g. priority and action info
- * @lkup_exts: lookup word structure
- * @dvm_ena: is double VLAN mode enabled
- */
-static int
-ice_add_special_words(struct ice_adv_rule_info *rinfo,
-                     struct ice_prot_lkup_ext *lkup_exts, bool dvm_ena)
-{
-       u16 mask;
-
-       /* If this is a tunneled packet, then add recipe index to match the
-        * tunnel bit in the packet metadata flags.
-        */
-       if (ice_tun_type_match_word(rinfo->tun_type, &mask)) {
-               if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) {
-                       u8 word = lkup_exts->n_val_words++;
-
-                       lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW;
-                       lkup_exts->fv_words[word].off = ICE_TUN_FLAG_MDID_OFF;
-                       lkup_exts->field_mask[word] = mask;
-               } else {
-                       return -ENOSPC;
-               }
-       }
-
-       if (rinfo->vlan_type != 0 && dvm_ena) {
-               if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) {
-                       u8 word = lkup_exts->n_val_words++;
-
-                       lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW;
-                       lkup_exts->fv_words[word].off = ICE_VLAN_FLAG_MDID_OFF;
-                       lkup_exts->field_mask[word] =
-                                       ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK;
-               } else {
-                       return -ENOSPC;
-               }
-       }
-
-       return 0;
-}
-
 /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule
  * @hw: pointer to hardware structure
  * @rinfo: other information regarding the rule e.g. priority and action info
@@ -5502,13 +5346,6 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        if (status)
                goto err_unroll;
 
-       /* Create any special protocol/offset pairs, such as looking at tunnel
-        * bits by extracting metadata
-        */
-       status = ice_add_special_words(rinfo, lkup_exts, ice_is_dvm_ena(hw));
-       if (status)
-               goto err_free_lkup_exts;
-
        /* Group match words into recipes using preferred recipe grouping
         * criteria.
         */
@@ -5519,6 +5356,9 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        /* set the recipe priority if specified */
        rm->priority = (u8)rinfo->priority;
 
+       rm->need_pass_l2 = rinfo->need_pass_l2;
+       rm->allow_pass_l2 = rinfo->allow_pass_l2;
+
        /* Find offsets from the field vector. Pick the first one for all the
         * recipes.
         */
@@ -5534,7 +5374,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        }
 
        /* Look for a recipe which matches our requested fv / mask list */
-       *rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type);
+       *rid = ice_find_recp(hw, lkup_exts, rinfo);
        if (*rid < ICE_MAX_NUM_RECIPES)
                /* Success if found a recipe that match the existing criteria */
                goto err_unroll;
@@ -5594,9 +5434,7 @@ err_unroll:
                devm_kfree(ice_hw_to_dev(hw), fvit);
        }
 
-       if (rm->root_buf)
-               devm_kfree(ice_hw_to_dev(hw), rm->root_buf);
-
+       devm_kfree(ice_hw_to_dev(hw), rm->root_buf);
        kfree(rm);
 
 err_free_lkup_exts:
@@ -5747,7 +5585,8 @@ ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                        if (lkups[i].h_u.pppoe_hdr.ppp_prot_id ==
                            htons(PPP_IPV6))
                                match |= ICE_PKT_OUTER_IPV6;
-               }
+               } else if (lkups[i].type == ICE_L2TPV3)
+                       match |= ICE_PKT_L2TPV3;
        }
 
        while (ret->match && (match & ret->match) != ret->match)
@@ -5793,6 +5632,10 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                 * was already checked when search for the dummy packet
                 */
                type = lkups[i].type;
+               /* metadata isn't present in the packet */
+               if (type == ICE_HW_METADATA)
+                       continue;
+
                for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) {
                        if (type == offsets[j].type) {
                                offset = offsets[j].offset;
@@ -5848,6 +5691,9 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                case ICE_PPPOE:
                        len = sizeof(struct ice_pppoe_hdr);
                        break;
+               case ICE_L2TPV3:
+                       len = sizeof(struct ice_l2tpv3_sess_hdr);
+                       break;
                default:
                        return -EINVAL;
                }
@@ -5925,16 +5771,21 @@ ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type,
 
 /**
  * ice_fill_adv_packet_vlan - fill dummy packet with VLAN tag type
+ * @hw: pointer to hw structure
  * @vlan_type: VLAN tag type
  * @pkt: dummy packet to fill in
  * @offsets: offset info for the dummy packet
  */
 static int
-ice_fill_adv_packet_vlan(u16 vlan_type, u8 *pkt,
+ice_fill_adv_packet_vlan(struct ice_hw *hw, u16 vlan_type, u8 *pkt,
                         const struct ice_dummy_pkt_offsets *offsets)
 {
        u16 i;
 
+       /* Check if there is something to do */
+       if (!vlan_type || !ice_is_dvm_ena(hw))
+               return 0;
+
        /* Find VLAN header and insert VLAN TPID */
        for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) {
                if (offsets[i].type == ICE_VLAN_OFOS ||
@@ -5953,6 +5804,17 @@ ice_fill_adv_packet_vlan(u16 vlan_type, u8 *pkt,
        return -EIO;
 }
 
+static bool ice_rules_equal(const struct ice_adv_rule_info *first,
+                           const struct ice_adv_rule_info *second)
+{
+       return first->sw_act.flag == second->sw_act.flag &&
+              first->tun_type == second->tun_type &&
+              first->vlan_type == second->vlan_type &&
+              first->src_vsi == second->src_vsi &&
+              first->need_pass_l2 == second->need_pass_l2 &&
+              first->allow_pass_l2 == second->allow_pass_l2;
+}
+
 /**
  * ice_find_adv_rule_entry - Search a rule entry
  * @hw: pointer to the hardware structure
@@ -5986,9 +5848,7 @@ ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                                lkups_matched = false;
                                break;
                        }
-               if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag &&
-                   rinfo->tun_type == list_itr->rule_info.tun_type &&
-                   rinfo->vlan_type == list_itr->rule_info.vlan_type &&
+               if (ice_rules_equal(rinfo, &list_itr->rule_info) &&
                    lkups_matched)
                        return list_itr;
        }
@@ -6104,6 +5964,33 @@ ice_adv_add_update_vsi_list(struct ice_hw *hw,
        return status;
 }
 
+void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup)
+{
+       lkup->type = ICE_HW_METADATA;
+       lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID21] |=
+               cpu_to_be16(ICE_PKT_TUNNEL_MASK);
+}
+
+void ice_rule_add_direction_metadata(struct ice_adv_lkup_elem *lkup)
+{
+       lkup->type = ICE_HW_METADATA;
+       lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |=
+               cpu_to_be16(ICE_PKT_FROM_NETWORK);
+}
+
+void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup)
+{
+       lkup->type = ICE_HW_METADATA;
+       lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |=
+               cpu_to_be16(ICE_PKT_VLAN_MASK);
+}
+
+void ice_rule_add_src_vsi_metadata(struct ice_adv_lkup_elem *lkup)
+{
+       lkup->type = ICE_HW_METADATA;
+       lkup->m_u.metadata.source_vsi = cpu_to_be16(ICE_MDID_SOURCE_VSI_MASK);
+}
+
 /**
  * ice_add_adv_rule - helper function to create an advanced switch rule
  * @hw: pointer to the hardware structure
@@ -6171,7 +6058,9 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
              rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
              rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
-             rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) {
+             rinfo->sw_act.fltr_act == ICE_DROP_PACKET ||
+             rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET ||
+             rinfo->sw_act.fltr_act == ICE_NOP)) {
                status = -EIO;
                goto free_pkt_profile;
        }
@@ -6182,10 +6071,16 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                goto free_pkt_profile;
        }
 
-       if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
+       if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
+           rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET ||
+           rinfo->sw_act.fltr_act == ICE_NOP) {
                rinfo->sw_act.fwd_id.hw_vsi_id =
                        ice_get_hw_vsi_num(hw, vsi_handle);
-       if (rinfo->sw_act.flag & ICE_FLTR_TX)
+       }
+
+       if (rinfo->src_vsi)
+               rinfo->sw_act.src = ice_get_hw_vsi_num(hw, rinfo->src_vsi);
+       else
                rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle);
 
        status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid);
@@ -6217,56 +6112,69 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                status = -ENOMEM;
                goto free_pkt_profile;
        }
-       if (!rinfo->flags_info.act_valid) {
-               act |= ICE_SINGLE_ACT_LAN_ENABLE;
-               act |= ICE_SINGLE_ACT_LB_ENABLE;
-       } else {
-               act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
-                                               ICE_SINGLE_ACT_LB_ENABLE);
+
+       if (rinfo->sw_act.fltr_act != ICE_MIRROR_PACKET) {
+               if (!rinfo->flags_info.act_valid) {
+                       act |= ICE_SINGLE_ACT_LAN_ENABLE;
+                       act |= ICE_SINGLE_ACT_LB_ENABLE;
+               } else {
+                       act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
+                                                       ICE_SINGLE_ACT_LB_ENABLE);
+               }
        }
 
        switch (rinfo->sw_act.fltr_act) {
        case ICE_FWD_TO_VSI:
-               act |= (rinfo->sw_act.fwd_id.hw_vsi_id <<
-                       ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+                                 rinfo->sw_act.fwd_id.hw_vsi_id);
                act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT;
                break;
        case ICE_FWD_TO_Q:
                act |= ICE_SINGLE_ACT_TO_Q;
-               act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
-                      ICE_SINGLE_ACT_Q_INDEX_M;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+                                 rinfo->sw_act.fwd_id.q_id);
                break;
        case ICE_FWD_TO_QGRP:
                q_rgn = rinfo->sw_act.qgrp_size > 0 ?
                        (u8)ilog2(rinfo->sw_act.qgrp_size) : 0;
                act |= ICE_SINGLE_ACT_TO_Q;
-               act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
-                      ICE_SINGLE_ACT_Q_INDEX_M;
-               act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
-                      ICE_SINGLE_ACT_Q_REGION_M;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+                                 rinfo->sw_act.fwd_id.q_id);
+               act |= FIELD_PREP(ICE_SINGLE_ACT_Q_REGION_M, q_rgn);
                break;
        case ICE_DROP_PACKET:
                act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
                       ICE_SINGLE_ACT_VALID_BIT;
                break;
+       case ICE_MIRROR_PACKET:
+               act |= ICE_SINGLE_ACT_OTHER_ACTS;
+               act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+                                 rinfo->sw_act.fwd_id.hw_vsi_id);
+               break;
+       case ICE_NOP:
+               act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+                                 rinfo->sw_act.fwd_id.hw_vsi_id);
+               act &= ~ICE_SINGLE_ACT_VALID_BIT;
+               break;
        default:
                status = -EIO;
                goto err_ice_add_adv_rule;
        }
 
-       /* set the rule LOOKUP type based on caller specified 'Rx'
-        * instead of hardcoding it to be either LOOKUP_TX/RX
+       /* If there is no matching criteria for direction there
+        * is only one difference between Rx and Tx:
+        * - get switch id base on VSI number from source field (Tx)
+        * - get switch id base on port number (Rx)
         *
-        * for 'Rx' set the source to be the port number
-        * for 'Tx' set the source to be the source HW VSI number (determined
-        * by caller)
+        * If matching on direction metadata is chose rule direction is
+        * extracted from type value set here.
         */
-       if (rinfo->rx) {
-               s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
-               s_rule->src = cpu_to_le16(hw->port_info->lport);
-       } else {
+       if (rinfo->sw_act.flag & ICE_FLTR_TX) {
                s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
                s_rule->src = cpu_to_le16(rinfo->sw_act.src);
+       } else {
+               s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
+               s_rule->src = cpu_to_le16(hw->port_info->lport);
        }
 
        s_rule->recipe_id = cpu_to_le16(rid);
@@ -6276,22 +6184,16 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        if (status)
                goto err_ice_add_adv_rule;
 
-       if (rinfo->tun_type != ICE_NON_TUN &&
-           rinfo->tun_type != ICE_SW_TUN_AND_NON_TUN) {
-               status = ice_fill_adv_packet_tun(hw, rinfo->tun_type,
-                                                s_rule->hdr_data,
-                                                profile->offsets);
-               if (status)
-                       goto err_ice_add_adv_rule;
-       }
+       status = ice_fill_adv_packet_tun(hw, rinfo->tun_type, s_rule->hdr_data,
+                                        profile->offsets);
+       if (status)
+               goto err_ice_add_adv_rule;
 
-       if (rinfo->vlan_type != 0 && ice_is_dvm_ena(hw)) {
-               status = ice_fill_adv_packet_vlan(rinfo->vlan_type,
-                                                 s_rule->hdr_data,
-                                                 profile->offsets);
-               if (status)
-                       goto err_ice_add_adv_rule;
-       }
+       status = ice_fill_adv_packet_vlan(hw, rinfo->vlan_type,
+                                         s_rule->hdr_data,
+                                         profile->offsets);
+       if (status)
+               goto err_ice_add_adv_rule;
 
        status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
                                 rule_buf_sz, 1, ice_aqc_opc_add_sw_rules,
@@ -6534,14 +6436,7 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                        return -EIO;
        }
 
-       /* Create any special protocol/offset pairs, such as looking at tunnel
-        * bits by extracting metadata
-        */
-       status = ice_add_special_words(rinfo, &lkup_exts, ice_is_dvm_ena(hw));
-       if (status)
-               return status;
-
-       rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type);
+       rid = ice_find_recp(hw, &lkup_exts, rinfo);
        /* If did not find a recipe that match the existing criteria */
        if (rid == ICE_MAX_NUM_RECIPES)
                return -EINVAL;
@@ -6634,59 +6529,6 @@ ice_rem_adv_rule_by_id(struct ice_hw *hw,
        return -ENOENT;
 }
 
-/**
- * ice_rem_adv_rule_for_vsi - removes existing advanced switch rules for a
- *                            given VSI handle
- * @hw: pointer to the hardware structure
- * @vsi_handle: VSI handle for which we are supposed to remove all the rules.
- *
- * This function is used to remove all the rules for a given VSI and as soon
- * as removing a rule fails, it will return immediately with the error code,
- * else it will return success.
- */
-int ice_rem_adv_rule_for_vsi(struct ice_hw *hw, u16 vsi_handle)
-{
-       struct ice_adv_fltr_mgmt_list_entry *list_itr, *tmp_entry;
-       struct ice_vsi_list_map_info *map_info;
-       struct ice_adv_rule_info rinfo;
-       struct list_head *list_head;
-       struct ice_switch_info *sw;
-       int status;
-       u8 rid;
-
-       sw = hw->switch_info;
-       for (rid = 0; rid < ICE_MAX_NUM_RECIPES; rid++) {
-               if (!sw->recp_list[rid].recp_created)
-                       continue;
-               if (!sw->recp_list[rid].adv_rule)
-                       continue;
-
-               list_head = &sw->recp_list[rid].filt_rules;
-               list_for_each_entry_safe(list_itr, tmp_entry, list_head,
-                                        list_entry) {
-                       rinfo = list_itr->rule_info;
-
-                       if (rinfo.sw_act.fltr_act == ICE_FWD_TO_VSI_LIST) {
-                               map_info = list_itr->vsi_list_info;
-                               if (!map_info)
-                                       continue;
-
-                               if (!test_bit(vsi_handle, map_info->vsi_map))
-                                       continue;
-                       } else if (rinfo.sw_act.vsi_handle != vsi_handle) {
-                               continue;
-                       }
-
-                       rinfo.sw_act.vsi_handle = vsi_handle;
-                       status = ice_rem_adv_rule(hw, list_itr->lkups,
-                                                 list_itr->lkups_cnt, &rinfo);
-                       if (status)
-                               return status;
-               }
-       }
-       return 0;
-}
-
 /**
  * ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI
  * @hw: pointer to the hardware structure