get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/54664/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 54664,
    "url": "http://patches.dpdk.org/api/patches/54664/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20190611155221.2703-8-leyi.rong@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20190611155221.2703-8-leyi.rong@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20190611155221.2703-8-leyi.rong@intel.com",
    "date": "2019-06-11T15:51:22",
    "name": "[v2,07/66] net/ice/base: programming a new switch recipe",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "4a79a650232a20195af5a14437d3a3bfa6913801",
    "submitter": {
        "id": 1204,
        "url": "http://patches.dpdk.org/api/people/1204/?format=api",
        "name": "Leyi Rong",
        "email": "leyi.rong@intel.com"
    },
    "delegate": {
        "id": 1540,
        "url": "http://patches.dpdk.org/api/users/1540/?format=api",
        "username": "qzhan15",
        "first_name": "Qi",
        "last_name": "Zhang",
        "email": "qi.z.zhang@intel.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20190611155221.2703-8-leyi.rong@intel.com/mbox/",
    "series": [
        {
            "id": 4981,
            "url": "http://patches.dpdk.org/api/series/4981/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=4981",
            "date": "2019-06-11T15:51:15",
            "name": "shared code update",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/4981/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/54664/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/54664/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 94DAD1C476;\n\tTue, 11 Jun 2019 17:53:57 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 2B5611C452\n\tfor <dev@dpdk.org>; Tue, 11 Jun 2019 17:53:46 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t11 Jun 2019 08:53:46 -0700",
            "from lrong-srv-03.sh.intel.com ([10.67.119.177])\n\tby orsmga001.jf.intel.com with ESMTP; 11 Jun 2019 08:53:44 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "From": "Leyi Rong <leyi.rong@intel.com>",
        "To": "qi.z.zhang@intel.com",
        "Cc": "dev@dpdk.org, Leyi Rong <leyi.rong@intel.com>,\n\tGrishma Kotecha <grishma.kotecha@intel.com>,\n\tPaul M Stillwell Jr <paul.m.stillwell.jr@intel.com>",
        "Date": "Tue, 11 Jun 2019 23:51:22 +0800",
        "Message-Id": "<20190611155221.2703-8-leyi.rong@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20190611155221.2703-1-leyi.rong@intel.com>",
        "References": "<20190604054248.68510-1-leyi.rong@intel.com>\n\t<20190611155221.2703-1-leyi.rong@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v2 07/66] net/ice/base: programming a new switch\n\trecipe",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "1. Added an interface to support adding advanced switch rules.\n2. Advanced rules are provided in a form of protocol headers and values\nto match in addition to actions (limited actions are current supported).\n3. Retrieve field vectors for ICE configuration package to determine\nextracted fields and extracted locations for recipe creation.\n4. Chain multiple recipes together to match multiple protocol headers.\n5. Add structure to manage the dynamic recipes.\n\nSigned-off-by: Grishma Kotecha <grishma.kotecha@intel.com>\nSigned-off-by: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>\nSigned-off-by: Leyi Rong <leyi.rong@intel.com>\n---\n drivers/net/ice/base/ice_flex_pipe.c |   33 +-\n drivers/net/ice/base/ice_flex_pipe.h |    7 +-\n drivers/net/ice/base/ice_switch.c    | 1640 ++++++++++++++++++++++++++\n drivers/net/ice/base/ice_switch.h    |   21 +\n 4 files changed, 1698 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/drivers/net/ice/base/ice_flex_pipe.c b/drivers/net/ice/base/ice_flex_pipe.c\nindex 14e632fab..babad94f8 100644\n--- a/drivers/net/ice/base/ice_flex_pipe.c\n+++ b/drivers/net/ice/base/ice_flex_pipe.c\n@@ -734,7 +734,7 @@ static void ice_release_global_cfg_lock(struct ice_hw *hw)\n  *\n  * This function will request ownership of the change lock.\n  */\n-static enum ice_status\n+enum ice_status\n ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)\n {\n \tice_debug(hw, ICE_DBG_TRACE, \"ice_acquire_change_lock\");\n@@ -749,7 +749,7 @@ ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)\n  *\n  * This function will release the change lock using the proper Admin Command.\n  */\n-static void ice_release_change_lock(struct ice_hw *hw)\n+void ice_release_change_lock(struct ice_hw *hw)\n {\n \tice_debug(hw, ICE_DBG_TRACE, \"ice_release_change_lock\");\n \n@@ -1801,6 +1801,35 @@ void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)\n \tice_free(hw, bld);\n }\n \n+/**\n+ * ice_find_prot_off - find prot ID and offset pair, based on prof and FV index\n+ * @hw: pointer to the hardware structure\n+ * @blk: hardware block\n+ * @prof: profile ID\n+ * @fv_idx: field vector word index\n+ * @prot: variable to receive the protocol ID\n+ * @off: variable to receive the protocol offset\n+ */\n+enum ice_status\n+ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u8 fv_idx,\n+\t\t  u8 *prot, u16 *off)\n+{\n+\tstruct ice_fv_word *fv_ext;\n+\n+\tif (prof >= hw->blk[blk].es.count)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tif (fv_idx >= hw->blk[blk].es.fvw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tfv_ext = hw->blk[blk].es.t + (prof * hw->blk[blk].es.fvw);\n+\n+\t*prot = fv_ext[fv_idx].prot_id;\n+\t*off = fv_ext[fv_idx].off;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n /* PTG Management */\n \n /**\ndiff --git a/drivers/net/ice/base/ice_flex_pipe.h b/drivers/net/ice/base/ice_flex_pipe.h\nindex 00c2b6682..2710dded6 100644\n--- a/drivers/net/ice/base/ice_flex_pipe.h\n+++ b/drivers/net/ice/base/ice_flex_pipe.h\n@@ -15,7 +15,12 @@\n \n enum ice_status\n ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count);\n-\n+enum ice_status\n+ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access);\n+void ice_release_change_lock(struct ice_hw *hw);\n+enum ice_status\n+ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u8 fv_idx,\n+\t\t  u8 *prot, u16 *off);\n struct ice_generic_seg_hdr *\n ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,\n \t\t    struct ice_pkg_hdr *pkg_hdr);\ndiff --git a/drivers/net/ice/base/ice_switch.c b/drivers/net/ice/base/ice_switch.c\nindex b84a07459..c53021aed 100644\n--- a/drivers/net/ice/base/ice_switch.c\n+++ b/drivers/net/ice/base/ice_switch.c\n@@ -53,6 +53,210 @@ static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,\n \t sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi) + \\\n \t ((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi)))\n \n+static const\n+u8 dummy_gre_packet[] = { 0, 0, 0, 0,\t\t/* Ether starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0x08, 0,\t\t/* Ether ends */\n+\t\t\t  0x45, 0, 0, 0x3E,\t/* IP starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0x2F, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\t\t/* IP ends */\n+\t\t\t  0x80, 0, 0x65, 0x58,\t/* GRE starts */\n+\t\t\t  0, 0, 0, 0,\t\t/* GRE ends */\n+\t\t\t  0, 0, 0, 0,\t\t/* Ether starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0x08, 0,\t\t/* Ether ends */\n+\t\t\t  0x45, 0, 0, 0x14,\t/* IP starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0\t\t/* IP ends */\n+\t\t\t};\n+\n+static const u8\n+dummy_udp_tun_packet[] = {0, 0, 0, 0,\t\t/* Ether starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0x08, 0,\t\t/* Ether ends */\n+\t\t\t  0x45, 0, 0, 0x32,\t/* IP starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0x11, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\t\t/* IP ends */\n+\t\t\t  0, 0, 0x12, 0xB5,\t/* UDP start*/\n+\t\t\t  0, 0x1E, 0, 0,\t/* UDP end*/\n+\t\t\t  0, 0, 0, 0,\t\t/* VXLAN start */\n+\t\t\t  0, 0, 0, 0,\t\t/* VXLAN end*/\n+\t\t\t  0, 0, 0, 0,\t\t/* Ether starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0\t\t\t/* Ether ends */\n+\t\t\t};\n+\n+static const u8\n+dummy_tcp_tun_packet[] = {0, 0, 0, 0,\t\t/* Ether starts */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0x08, 0,              /* Ether ends */\n+\t\t\t  0x45, 0, 0, 0x28,     /* IP starts */\n+\t\t\t  0, 0x01, 0, 0,\n+\t\t\t  0x40, 0x06, 0xF5, 0x69,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,   /* IP ends */\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0, 0, 0, 0,\n+\t\t\t  0x50, 0x02, 0x20,\n+\t\t\t  0, 0x9, 0x79, 0, 0,\n+\t\t\t  0, 0 /* 2 bytes padding for 4 byte alignment*/\n+\t\t\t};\n+\n+/* this is a recipe to profile bitmap association */\n+static ice_declare_bitmap(recipe_to_profile[ICE_MAX_NUM_RECIPES],\n+\t\t\t  ICE_MAX_NUM_PROFILES);\n+static ice_declare_bitmap(available_result_ids, ICE_CHAIN_FV_INDEX_START + 1);\n+\n+/**\n+ * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries\n+ * @hw: pointer to hardware structure\n+ * @recps: struct that we need to populate\n+ * @rid: recipe ID that we are populating\n+ *\n+ * This function is used to populate all the necessary entries into our\n+ * bookkeeping so that we have a current list of all the recipes that are\n+ * programmed in the firmware.\n+ */\n+static enum ice_status\n+ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid)\n+{\n+\tu16 i, sub_recps, fv_word_idx = 0, result_idx = 0;\n+\tice_declare_bitmap(r_bitmap, ICE_MAX_NUM_PROFILES);\n+\tu16 result_idxs[ICE_MAX_CHAIN_RECIPE] = { 0 };\n+\tstruct ice_aqc_recipe_data_elem *tmp;\n+\tu16 num_recps = ICE_MAX_NUM_RECIPES;\n+\tstruct ice_prot_lkup_ext *lkup_exts;\n+\tenum ice_status status;\n+\n+\t/* we need a buffer big enough to accommodate all the recipes */\n+\ttmp = (struct ice_aqc_recipe_data_elem *)ice_calloc(hw,\n+\t\tICE_MAX_NUM_RECIPES, sizeof(*tmp));\n+\tif (!tmp)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\ttmp[0].recipe_indx = rid;\n+\tstatus = ice_aq_get_recipe(hw, tmp, &num_recps, rid, NULL);\n+\t/* non-zero status meaning recipe doesn't exist */\n+\tif (status)\n+\t\tgoto err_unroll;\n+\tlkup_exts = &recps[rid].lkup_exts;\n+\t/* start populating all the entries for recps[rid] based on lkups from\n+\t * firmware\n+\t */\n+\tfor (sub_recps = 0; sub_recps < num_recps; sub_recps++) {\n+\t\tstruct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps];\n+\t\tstruct ice_recp_grp_entry *rg_entry;\n+\t\tu8 prof_id, prot = 0;\n+\t\tu16 off = 0;\n+\n+\t\trg_entry = (struct ice_recp_grp_entry *)\n+\t\t\tice_malloc(hw, sizeof(*rg_entry));\n+\t\tif (!rg_entry) {\n+\t\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\t\tgoto err_unroll;\n+\t\t}\n+\t\t/* Avoid 8th bit since its result enable bit */\n+\t\tresult_idxs[result_idx] = root_bufs.content.result_indx &\n+\t\t\t~ICE_AQ_RECIPE_RESULT_EN;\n+\t\t/* Check if result enable bit is set */\n+\t\tif (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN)\n+\t\t\tice_clear_bit(ICE_CHAIN_FV_INDEX_START -\n+\t\t\t\t      result_idxs[result_idx++],\n+\t\t\t\t      available_result_ids);\n+\t\tice_memcpy(r_bitmap,\n+\t\t\t   recipe_to_profile[tmp[sub_recps].recipe_indx],\n+\t\t\t   sizeof(r_bitmap), ICE_NONDMA_TO_NONDMA);\n+\t\t/* get the first profile that is associated with rid */\n+\t\tprof_id = ice_find_first_bit(r_bitmap, ICE_MAX_NUM_PROFILES);\n+\t\tfor (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) {\n+\t\t\tu8 lkup_indx = root_bufs.content.lkup_indx[i + 1];\n+\n+\t\t\trg_entry->fv_idx[i] = lkup_indx;\n+\t\t\t/* If the recipe is a chained recipe then all its\n+\t\t\t * child recipe's result will have a result index.\n+\t\t\t * To fill fv_words we should not use those result\n+\t\t\t * index, we only need the protocol ids and offsets.\n+\t\t\t * We will skip all the fv_idx which stores result\n+\t\t\t * index in them. We also need to skip any fv_idx which\n+\t\t\t * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a\n+\t\t\t * valid offset value.\n+\t\t\t */\n+\t\t\tif (result_idxs[0] == rg_entry->fv_idx[i] ||\n+\t\t\t    result_idxs[1] == rg_entry->fv_idx[i] ||\n+\t\t\t    result_idxs[2] == rg_entry->fv_idx[i] ||\n+\t\t\t    result_idxs[3] == rg_entry->fv_idx[i] ||\n+\t\t\t    result_idxs[4] == rg_entry->fv_idx[i] ||\n+\t\t\t    rg_entry->fv_idx[i] == ICE_AQ_RECIPE_LKUP_IGNORE ||\n+\t\t\t    rg_entry->fv_idx[i] == 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\tice_find_prot_off(hw, ICE_BLK_SW, prof_id,\n+\t\t\t\t\t  rg_entry->fv_idx[i], &prot, &off);\n+\t\t\tlkup_exts->fv_words[fv_word_idx].prot_id = prot;\n+\t\t\tlkup_exts->fv_words[fv_word_idx].off = off;\n+\t\t\tfv_word_idx++;\n+\t\t}\n+\t\t/* populate rg_list with the data from the child entry of this\n+\t\t * recipe\n+\t\t */\n+\t\tLIST_ADD(&rg_entry->l_entry, &recps[rid].rg_list);\n+\t}\n+\tlkup_exts->n_val_words = fv_word_idx;\n+\trecps[rid].n_grp_count = num_recps;\n+\trecps[rid].root_buf = (struct ice_aqc_recipe_data_elem *)\n+\t\tice_calloc(hw, recps[rid].n_grp_count,\n+\t\t\t   sizeof(struct ice_aqc_recipe_data_elem));\n+\tif (!recps[rid].root_buf)\n+\t\tgoto err_unroll;\n+\n+\tice_memcpy(recps[rid].root_buf, tmp, recps[rid].n_grp_count *\n+\t\t   sizeof(*recps[rid].root_buf), ICE_NONDMA_TO_NONDMA);\n+\trecps[rid].recp_created = true;\n+\tif (tmp[sub_recps].content.rid & ICE_AQ_RECIPE_ID_IS_ROOT)\n+\t\trecps[rid].root_rid = rid;\n+err_unroll:\n+\tice_free(hw, tmp);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_get_recp_to_prof_map - updates recipe to profile mapping\n+ * @hw: pointer to hardware structure\n+ *\n+ * This function is used to populate recipe_to_profile matrix where index to\n+ * this array is the recipe ID and the element is the mapping of which profiles\n+ * is this recipe mapped to.\n+ */\n+static void\n+ice_get_recp_to_prof_map(struct ice_hw *hw)\n+{\n+\tice_declare_bitmap(r_bitmap, ICE_MAX_NUM_RECIPES);\n+\tu16 i;\n+\n+\tfor (i = 0; i < ICE_MAX_NUM_PROFILES; i++) {\n+\t\tu16 j;\n+\n+\t\tice_zero_bitmap(r_bitmap, ICE_MAX_NUM_RECIPES);\n+\t\tif (ice_aq_get_recipe_to_profile(hw, i, (u8 *)r_bitmap, NULL))\n+\t\t\tcontinue;\n+\n+\t\tfor (j = 0; j < ICE_MAX_NUM_RECIPES; j++)\n+\t\t\tif (ice_is_bit_set(r_bitmap, j))\n+\t\t\t\tice_set_bit(i, recipe_to_profile[j]);\n+\t}\n+}\n \n /**\n  * ice_init_def_sw_recp - initialize the recipe book keeping tables\n@@ -1018,6 +1222,35 @@ ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,\n \treturn ice_aq_send_cmd(hw, &desc, NULL, 0, cd);\n }\n \n+/**\n+ * ice_aq_get_recipe_to_profile - Map recipe to packet profile\n+ * @hw: pointer to the HW struct\n+ * @profile_id: package profile ID to associate the recipe with\n+ * @r_bitmap: Recipe bitmap filled in and need to be returned as response\n+ * @cd: pointer to command details structure or NULL\n+ * Associate profile ID with given recipe (0x0293)\n+ */\n+enum ice_status\n+ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,\n+\t\t\t     struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_recipe_to_profile *cmd;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\n+\tice_debug(hw, ICE_DBG_TRACE, \"ice_aq_get_recipe_to_prof\");\n+\tcmd = &desc.params.recipe_to_profile;\n+\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe_to_profile);\n+\tcmd->profile_id = CPU_TO_LE16(profile_id);\n+\n+\tstatus = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);\n+\tif (!status)\n+\t\tice_memcpy(r_bitmap, cmd->recipe_assoc,\n+\t\t\t   sizeof(cmd->recipe_assoc), ICE_NONDMA_TO_NONDMA);\n+\n+\treturn status;\n+}\n+\n /**\n  * ice_alloc_recipe - add recipe resource\n  * @hw: pointer to the hardware structure\n@@ -3899,6 +4132,1413 @@ ice_add_mac_with_counter(struct ice_hw *hw, struct ice_fltr_info *f_info)\n \treturn ret;\n }\n \n+/* This is mapping table entry that maps every word within a given protocol\n+ * structure to the real byte offset as per the specification of that\n+ * protocol header.\n+ * for example dst address is 3 words in ethertype header and corresponding\n+ * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8\n+ * IMPORTANT: Every structure part of \"ice_prot_hdr\" union should have a\n+ * matching entry describing its field. This needs to be updated if new\n+ * structure is added to that union.\n+ */\n+static const struct ice_prot_ext_tbl_entry ice_prot_ext[] = {\n+\t{ ICE_MAC_OFOS,\t\t{ 0, 2, 4, 6, 8, 10, 12 } },\n+\t{ ICE_MAC_IL,\t\t{ 0, 2, 4, 6, 8, 10, 12 } },\n+\t{ ICE_IPV4_OFOS,\t{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },\n+\t{ ICE_IPV4_IL,\t\t{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },\n+\t{ ICE_IPV6_IL,\t\t{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,\n+\t\t\t\t 26, 28, 30, 32, 34, 36, 38 } },\n+\t{ ICE_IPV6_OFOS,\t{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,\n+\t\t\t\t 26, 28, 30, 32, 34, 36, 38 } },\n+\t{ ICE_TCP_IL,\t\t{ 0, 2 } },\n+\t{ ICE_UDP_ILOS,\t\t{ 0, 2 } },\n+\t{ ICE_SCTP_IL,\t\t{ 0, 2 } },\n+\t{ ICE_VXLAN,\t\t{ 8, 10, 12 } },\n+\t{ ICE_GENEVE,\t\t{ 8, 10, 12 } },\n+\t{ ICE_VXLAN_GPE,\t{ 0, 2, 4 } },\n+\t{ ICE_NVGRE,\t\t{ 0, 2 } },\n+\t{ ICE_PROTOCOL_LAST,\t{ 0 } }\n+};\n+\n+/* The following table describes preferred grouping of recipes.\n+ * If a recipe that needs to be programmed is a superset or matches one of the\n+ * following combinations, then the recipe needs to be chained as per the\n+ * following policy.\n+ */\n+static const struct ice_pref_recipe_group ice_recipe_pack[] = {\n+\t{3, { { ICE_MAC_OFOS_HW, 0, 0 }, { ICE_MAC_OFOS_HW, 2, 0 },\n+\t      { ICE_MAC_OFOS_HW, 4, 0 } } },\n+\t{4, { { ICE_MAC_IL_HW, 0, 0 }, { ICE_MAC_IL_HW, 2, 0 },\n+\t      { ICE_MAC_IL_HW, 4, 0 }, { ICE_META_DATA_ID_HW, 44, 0 } } },\n+\t{2, { { ICE_IPV4_IL_HW, 0, 0 }, { ICE_IPV4_IL_HW, 2, 0 } } },\n+\t{2, { { ICE_IPV4_IL_HW, 12, 0 }, { ICE_IPV4_IL_HW, 14, 0 } } },\n+};\n+\n+static const struct ice_protocol_entry ice_prot_id_tbl[] = {\n+\t{ ICE_MAC_OFOS,\t\tICE_MAC_OFOS_HW },\n+\t{ ICE_MAC_IL,\t\tICE_MAC_IL_HW },\n+\t{ ICE_IPV4_OFOS,\tICE_IPV4_OFOS_HW },\n+\t{ ICE_IPV4_IL,\t\tICE_IPV4_IL_HW },\n+\t{ ICE_IPV6_OFOS,\tICE_IPV6_OFOS_HW },\n+\t{ ICE_IPV6_IL,\t\tICE_IPV6_IL_HW },\n+\t{ ICE_TCP_IL,\t\tICE_TCP_IL_HW },\n+\t{ ICE_UDP_ILOS,\t\tICE_UDP_ILOS_HW },\n+\t{ ICE_SCTP_IL,\t\tICE_SCTP_IL_HW },\n+\t{ ICE_VXLAN,\t\tICE_UDP_OF_HW },\n+\t{ ICE_GENEVE,\t\tICE_UDP_OF_HW },\n+\t{ ICE_VXLAN_GPE,\tICE_UDP_OF_HW },\n+\t{ ICE_NVGRE,\t\tICE_GRE_OF_HW },\n+\t{ ICE_PROTOCOL_LAST,\t0 }\n+};\n+\n+/**\n+ * ice_find_recp - find a recipe\n+ * @hw: pointer to the hardware structure\n+ * @lkup_exts: extension sequence to match\n+ *\n+ * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.\n+ */\n+static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts)\n+{\n+\tstruct ice_sw_recipe *recp;\n+\tu16 i;\n+\n+\tice_get_recp_to_prof_map(hw);\n+\t/* Initialize available_result_ids which tracks available result idx */\n+\tfor (i = 0; i <= ICE_CHAIN_FV_INDEX_START; i++)\n+\t\tice_set_bit(ICE_CHAIN_FV_INDEX_START - i,\n+\t\t\t    available_result_ids);\n+\n+\t/* Walk through existing recipes to find a match */\n+\trecp = hw->switch_info->recp_list;\n+\tfor (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {\n+\t\t/* If recipe was not created for this ID, in SW bookkeeping,\n+\t\t * check if FW has an entry for this recipe. If the FW has an\n+\t\t * entry update it in our SW bookkeeping and continue with the\n+\t\t * matching.\n+\t\t */\n+\t\tif (!recp[i].recp_created)\n+\t\t\tif (ice_get_recp_frm_fw(hw,\n+\t\t\t\t\t\thw->switch_info->recp_list, i))\n+\t\t\t\tcontinue;\n+\n+\t\t/* if number of words we are looking for match */\n+\t\tif (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) {\n+\t\t\tstruct ice_fv_word *a = lkup_exts->fv_words;\n+\t\t\tstruct ice_fv_word *b = recp[i].lkup_exts.fv_words;\n+\t\t\tbool found = true;\n+\t\t\tu8 p, q;\n+\n+\t\t\tfor (p = 0; p < lkup_exts->n_val_words; p++) {\n+\t\t\t\tfor (q = 0; q < recp[i].lkup_exts.n_val_words;\n+\t\t\t\t     q++) {\n+\t\t\t\t\tif (a[p].off == b[q].off &&\n+\t\t\t\t\t    a[p].prot_id == b[q].prot_id)\n+\t\t\t\t\t\t/* Found the \"p\"th word in the\n+\t\t\t\t\t\t * given recipe\n+\t\t\t\t\t\t */\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\t/* After walking through all the words in the\n+\t\t\t\t * \"i\"th recipe if \"p\"th word was not found then\n+\t\t\t\t * this recipe is not what we are looking for.\n+\t\t\t\t * So break out from this loop and try the next\n+\t\t\t\t * recipe\n+\t\t\t\t */\n+\t\t\t\tif (q >= recp[i].lkup_exts.n_val_words) {\n+\t\t\t\t\tfound = false;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\t/* If for \"i\"th recipe the found was never set to false\n+\t\t\t * then it means we found our match\n+\t\t\t */\n+\t\t\tif (found)\n+\t\t\t\treturn i; /* Return the recipe ID */\n+\t\t}\n+\t}\n+\treturn ICE_MAX_NUM_RECIPES;\n+}\n+\n+/**\n+ * ice_prot_type_to_id - get protocol ID from protocol type\n+ * @type: protocol type\n+ * @id: pointer to variable that will receive the ID\n+ *\n+ * Returns true if found, false otherwise\n+ */\n+static bool ice_prot_type_to_id(enum ice_protocol_type type, u16 *id)\n+{\n+\tu16 i;\n+\n+\tfor (i = 0; ice_prot_id_tbl[i].type != ICE_PROTOCOL_LAST; i++)\n+\t\tif (ice_prot_id_tbl[i].type == type) {\n+\t\t\t*id = ice_prot_id_tbl[i].protocol_id;\n+\t\t\treturn true;\n+\t\t}\n+\treturn false;\n+}\n+\n+/**\n+ * ice_find_valid_words - count valid words\n+ * @rule: advanced rule with lookup information\n+ * @lkup_exts: byte offset extractions of the words that are valid\n+ *\n+ * calculate valid words in a lookup rule using mask value\n+ */\n+static u16\n+ice_fill_valid_words(struct ice_adv_lkup_elem *rule,\n+\t\t     struct ice_prot_lkup_ext *lkup_exts)\n+{\n+\tu16 j, word = 0;\n+\tu16 prot_id;\n+\tu16 ret_val;\n+\n+\tif (!ice_prot_type_to_id(rule->type, &prot_id))\n+\t\treturn 0;\n+\n+\tword = lkup_exts->n_val_words;\n+\n+\tfor (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++)\n+\t\tif (((u16 *)&rule->m_u)[j] == 0xffff &&\n+\t\t    rule->type < ARRAY_SIZE(ice_prot_ext)) {\n+\t\t\t/* No more space to accommodate */\n+\t\t\tif (word >= ICE_MAX_CHAIN_WORDS)\n+\t\t\t\treturn 0;\n+\t\t\tlkup_exts->fv_words[word].off =\n+\t\t\t\tice_prot_ext[rule->type].offs[j];\n+\t\t\tlkup_exts->fv_words[word].prot_id =\n+\t\t\t\tice_prot_id_tbl[rule->type].protocol_id;\n+\t\t\tword++;\n+\t\t}\n+\n+\tret_val = word - lkup_exts->n_val_words;\n+\tlkup_exts->n_val_words = word;\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * ice_find_prot_off_ind - check for specific ID and offset in rule\n+ * @lkup_exts: an array of protocol header extractions\n+ * @prot_type: protocol type to check\n+ * @off: expected offset of the extraction\n+ *\n+ * Check if the prot_ext has given protocol ID and offset\n+ */\n+static u8\n+ice_find_prot_off_ind(struct ice_prot_lkup_ext *lkup_exts, u8 prot_type,\n+\t\t      u16 off)\n+{\n+\tu8 j;\n+\n+\tfor (j = 0; j < lkup_exts->n_val_words; j++)\n+\t\tif (lkup_exts->fv_words[j].off == off &&\n+\t\t    lkup_exts->fv_words[j].prot_id == prot_type)\n+\t\t\treturn j;\n+\n+\treturn ICE_MAX_CHAIN_WORDS;\n+}\n+\n+/**\n+ * ice_is_recipe_subset - check if recipe group policy is a subset of lookup\n+ * @lkup_exts: an array of protocol header extractions\n+ * @r_policy: preferred recipe grouping policy\n+ *\n+ * Helper function to check if given recipe group is subset we need to check if\n+ * all the words described by the given recipe group exist in the advanced rule\n+ * look up information\n+ */\n+static bool\n+ice_is_recipe_subset(struct ice_prot_lkup_ext *lkup_exts,\n+\t\t     const struct ice_pref_recipe_group *r_policy)\n+{\n+\tu8 ind[ICE_NUM_WORDS_RECIPE];\n+\tu8 count = 0;\n+\tu8 i;\n+\n+\t/* check if everything in the r_policy is part of the entire rule */\n+\tfor (i = 0; i < r_policy->n_val_pairs; i++) {\n+\t\tu8 j;\n+\n+\t\tj = ice_find_prot_off_ind(lkup_exts, r_policy->pairs[i].prot_id,\n+\t\t\t\t\t  r_policy->pairs[i].off);\n+\t\tif (j >= ICE_MAX_CHAIN_WORDS)\n+\t\t\treturn false;\n+\n+\t\t/* store the indexes temporarily found by the find function\n+\t\t * this will be used to mark the words as 'done'\n+\t\t */\n+\t\tind[count++] = j;\n+\t}\n+\n+\t/* If the entire policy recipe was a true match, then mark the fields\n+\t * that are covered by the recipe as 'done' meaning that these words\n+\t * will be clumped together in one recipe.\n+\t * \"Done\" here means in our searching if certain recipe group\n+\t * matches or is subset of the given rule, then we mark all\n+\t * the corresponding offsets as found. So the remaining recipes should\n+\t * be created with whatever words that were left.\n+\t */\n+\tfor (i = 0; i < count; i++) {\n+\t\tu8 in = ind[i];\n+\n+\t\tice_set_bit(in, lkup_exts->done);\n+\t}\n+\treturn true;\n+}\n+\n+/**\n+ * ice_create_first_fit_recp_def - Create a recipe grouping\n+ * @hw: pointer to the hardware structure\n+ * @lkup_exts: an array of protocol header extractions\n+ * @rg_list: pointer to a list that stores new recipe groups\n+ * @recp_cnt: pointer to a variable that stores returned number of recipe groups\n+ *\n+ * Using first fit algorithm, take all the words that are still not done\n+ * and start grouping them in 4-word groups. Each group makes up one\n+ * recipe.\n+ */\n+static enum ice_status\n+ice_create_first_fit_recp_def(struct ice_hw *hw,\n+\t\t\t      struct ice_prot_lkup_ext *lkup_exts,\n+\t\t\t      struct LIST_HEAD_TYPE *rg_list,\n+\t\t\t      u8 *recp_cnt)\n+{\n+\tstruct ice_pref_recipe_group *grp = NULL;\n+\tu8 j;\n+\n+\t*recp_cnt = 0;\n+\n+\t/* Walk through every word in the rule to check if it is not done. If so\n+\t * then this word needs to be part of a new recipe.\n+\t */\n+\tfor (j = 0; j < lkup_exts->n_val_words; j++)\n+\t\tif (!ice_is_bit_set(lkup_exts->done, j)) {\n+\t\t\tif (!grp ||\n+\t\t\t    grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) {\n+\t\t\t\tstruct ice_recp_grp_entry *entry;\n+\n+\t\t\t\tentry = (struct ice_recp_grp_entry *)\n+\t\t\t\t\tice_malloc(hw, sizeof(*entry));\n+\t\t\t\tif (!entry)\n+\t\t\t\t\treturn ICE_ERR_NO_MEMORY;\n+\t\t\t\tLIST_ADD(&entry->l_entry, rg_list);\n+\t\t\t\tgrp = &entry->r_group;\n+\t\t\t\t(*recp_cnt)++;\n+\t\t\t}\n+\n+\t\t\tgrp->pairs[grp->n_val_pairs].prot_id =\n+\t\t\t\tlkup_exts->fv_words[j].prot_id;\n+\t\t\tgrp->pairs[grp->n_val_pairs].off =\n+\t\t\t\tlkup_exts->fv_words[j].off;\n+\t\t\tgrp->n_val_pairs++;\n+\t\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_fill_fv_word_index - fill in the field vector indices for a recipe group\n+ * @hw: pointer to the hardware structure\n+ * @fv_list: field vector with the extraction sequence information\n+ * @rg_list: recipe groupings with protocol-offset pairs\n+ *\n+ * Helper function to fill in the field vector indices for protocol-offset\n+ * pairs. These indexes are then ultimately programmed into a recipe.\n+ */\n+static void\n+ice_fill_fv_word_index(struct ice_hw *hw, struct LIST_HEAD_TYPE *fv_list,\n+\t\t       struct LIST_HEAD_TYPE *rg_list)\n+{\n+\tstruct ice_sw_fv_list_entry *fv;\n+\tstruct ice_recp_grp_entry *rg;\n+\tstruct ice_fv_word *fv_ext;\n+\n+\tif (LIST_EMPTY(fv_list))\n+\t\treturn;\n+\n+\tfv = LIST_FIRST_ENTRY(fv_list, struct ice_sw_fv_list_entry, list_entry);\n+\tfv_ext = fv->fv_ptr->ew;\n+\n+\tLIST_FOR_EACH_ENTRY(rg, rg_list, ice_recp_grp_entry, l_entry) {\n+\t\tu8 i;\n+\n+\t\tfor (i = 0; i < rg->r_group.n_val_pairs; i++) {\n+\t\t\tstruct ice_fv_word *pr;\n+\t\t\tu8 j;\n+\n+\t\t\tpr = &rg->r_group.pairs[i];\n+\t\t\tfor (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)\n+\t\t\t\tif (fv_ext[j].prot_id == pr->prot_id &&\n+\t\t\t\t    fv_ext[j].off == pr->off) {\n+\t\t\t\t\t/* Store index of field vector */\n+\t\t\t\t\trg->fv_idx[i] = j;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * ice_add_sw_recipe - function to call AQ calls to create switch recipe\n+ * @hw: pointer to hardware structure\n+ * @rm: recipe management list entry\n+ * @match_tun: if field vector index for tunnel needs to be programmed\n+ */\n+static enum ice_status\n+ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,\n+\t\t  bool match_tun)\n+{\n+\tstruct ice_aqc_recipe_data_elem *tmp;\n+\tstruct ice_aqc_recipe_data_elem *buf;\n+\tstruct ice_recp_grp_entry *entry;\n+\tenum ice_status status;\n+\tu16 recipe_count;\n+\tu8 chain_idx;\n+\tu8 recps = 0;\n+\n+\t/* When more than one recipe are required, another recipe is needed to\n+\t * chain them together. Matching a tunnel metadata ID takes up one of\n+\t * the match fields in the chaining recipe reducing the number of\n+\t * chained recipes by one.\n+\t */\n+\tif (rm->n_grp_count > 1)\n+\t\trm->n_grp_count++;\n+\tif (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE ||\n+\t    (match_tun && rm->n_grp_count > (ICE_MAX_CHAIN_RECIPE - 1)))\n+\t\treturn ICE_ERR_MAX_LIMIT;\n+\n+\ttmp = (struct ice_aqc_recipe_data_elem *)ice_calloc(hw,\n+\t\t\t\t\t\t\t    ICE_MAX_NUM_RECIPES,\n+\t\t\t\t\t\t\t    sizeof(*tmp));\n+\tif (!tmp)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tbuf = (struct ice_aqc_recipe_data_elem *)\n+\t\tice_calloc(hw, rm->n_grp_count, sizeof(*buf));\n+\tif (!buf) {\n+\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\tgoto err_mem;\n+\t}\n+\n+\tice_zero_bitmap(rm->r_bitmap, ICE_MAX_NUM_RECIPES);\n+\trecipe_count = ICE_MAX_NUM_RECIPES;\n+\tstatus = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC,\n+\t\t\t\t   NULL);\n+\tif (status || recipe_count == 0)\n+\t\tgoto err_unroll;\n+\n+\t/* Allocate the recipe resources, and configure them according to the\n+\t * match fields from protocol headers and extracted field vectors.\n+\t */\n+\tchain_idx = ICE_CHAIN_FV_INDEX_START -\n+\t\tice_find_first_bit(available_result_ids,\n+\t\t\t\t   ICE_CHAIN_FV_INDEX_START + 1);\n+\tLIST_FOR_EACH_ENTRY(entry, &rm->rg_list, ice_recp_grp_entry, l_entry) {\n+\t\tu8 i;\n+\n+\t\tstatus = ice_alloc_recipe(hw, &entry->rid);\n+\t\tif (status)\n+\t\t\tgoto err_unroll;\n+\n+\t\t/* Clear the result index of the located recipe, as this will be\n+\t\t * updated, if needed, later in the recipe creation process.\n+\t\t */\n+\t\ttmp[0].content.result_indx = 0;\n+\n+\t\tbuf[recps] = tmp[0];\n+\t\tbuf[recps].recipe_indx = (u8)entry->rid;\n+\t\t/* if the recipe is a non-root recipe RID should be programmed\n+\t\t * as 0 for the rules to be applied correctly.\n+\t\t */\n+\t\tbuf[recps].content.rid = 0;\n+\t\tice_memset(&buf[recps].content.lkup_indx, 0,\n+\t\t\t   sizeof(buf[recps].content.lkup_indx),\n+\t\t\t   ICE_NONDMA_MEM);\n+\n+\t\t/* All recipes use look-up field index 0 to match switch ID. */\n+\t\tbuf[recps].content.lkup_indx[0] = 0;\n+\t\tbuf[recps].content.mask[0] =\n+\t\t\tCPU_TO_LE16(ICE_AQ_SW_ID_LKUP_MASK);\n+\t\t/* Setup lkup_indx 1..4 to INVALID/ignore and set the mask\n+\t\t * to be 0\n+\t\t */\n+\t\tfor (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {\n+\t\t\tbuf[recps].content.lkup_indx[i] = 0x80;\n+\t\t\tbuf[recps].content.mask[i] = 0;\n+\t\t}\n+\n+\t\tfor (i = 0; i < entry->r_group.n_val_pairs; i++) {\n+\t\t\tbuf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i];\n+\t\t\tbuf[recps].content.mask[i + 1] = CPU_TO_LE16(0xFFFF);\n+\t\t}\n+\n+\t\tif (rm->n_grp_count > 1) {\n+\t\t\tentry->chain_idx = chain_idx;\n+\t\t\tbuf[recps].content.result_indx =\n+\t\t\t\tICE_AQ_RECIPE_RESULT_EN |\n+\t\t\t\t((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &\n+\t\t\t\t ICE_AQ_RECIPE_RESULT_DATA_M);\n+\t\t\tice_clear_bit(ICE_CHAIN_FV_INDEX_START - chain_idx,\n+\t\t\t\t      available_result_ids);\n+\t\t\tchain_idx = ICE_CHAIN_FV_INDEX_START -\n+\t\t\t\tice_find_first_bit(available_result_ids,\n+\t\t\t\t\t\t   ICE_CHAIN_FV_INDEX_START +\n+\t\t\t\t\t\t   1);\n+\t\t}\n+\n+\t\t/* fill recipe dependencies */\n+\t\tice_zero_bitmap((ice_bitmap_t *)buf[recps].recipe_bitmap,\n+\t\t\t\tICE_MAX_NUM_RECIPES);\n+\t\tice_set_bit(buf[recps].recipe_indx,\n+\t\t\t    (ice_bitmap_t *)buf[recps].recipe_bitmap);\n+\t\tbuf[recps].content.act_ctrl_fwd_priority = rm->priority;\n+\t\trecps++;\n+\t}\n+\n+\tif (rm->n_grp_count == 1) {\n+\t\trm->root_rid = buf[0].recipe_indx;\n+\t\tice_set_bit(buf[0].recipe_indx, rm->r_bitmap);\n+\t\tbuf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT;\n+\t\tif (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) {\n+\t\t\tice_memcpy(buf[0].recipe_bitmap, rm->r_bitmap,\n+\t\t\t\t   sizeof(buf[0].recipe_bitmap),\n+\t\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\t\t} else {\n+\t\t\tstatus = ICE_ERR_BAD_PTR;\n+\t\t\tgoto err_unroll;\n+\t\t}\n+\t\t/* Applicable only for ROOT_RECIPE, set the fwd_priority for\n+\t\t * the recipe which is getting created if specified\n+\t\t * by user. Usually any advanced switch filter, which results\n+\t\t * into new extraction sequence, ended up creating a new recipe\n+\t\t * of type ROOT and usually recipes are associated with profiles\n+\t\t * Switch rule referreing newly created recipe, needs to have\n+\t\t * either/or 'fwd' or 'join' priority, otherwise switch rule\n+\t\t * evaluation will not happen correctly. In other words, if\n+\t\t * switch rule to be evaluated on priority basis, then recipe\n+\t\t * needs to have priority, otherwise it will be evaluated last.\n+\t\t */\n+\t\tbuf[0].content.act_ctrl_fwd_priority = rm->priority;\n+\t} else {\n+\t\tstruct ice_recp_grp_entry *last_chain_entry;\n+\t\tu16 rid, i = 0;\n+\n+\t\t/* Allocate the last recipe that will chain the outcomes of the\n+\t\t * other recipes together\n+\t\t */\n+\t\tstatus = ice_alloc_recipe(hw, &rid);\n+\t\tif (status)\n+\t\t\tgoto err_unroll;\n+\n+\t\tbuf[recps].recipe_indx = (u8)rid;\n+\t\tbuf[recps].content.rid = (u8)rid;\n+\t\tbuf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT;\n+\t\t/* the new entry created should also be part of rg_list to\n+\t\t * make sure we have complete recipe\n+\t\t */\n+\t\tlast_chain_entry = (struct ice_recp_grp_entry *)ice_malloc(hw,\n+\t\t\tsizeof(*last_chain_entry));\n+\t\tif (!last_chain_entry) {\n+\t\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\t\tgoto err_unroll;\n+\t\t}\n+\t\tlast_chain_entry->rid = rid;\n+\t\tice_memset(&buf[recps].content.lkup_indx, 0,\n+\t\t\t   sizeof(buf[recps].content.lkup_indx),\n+\t\t\t   ICE_NONDMA_MEM);\n+\t\tbuf[recps].content.lkup_indx[i] = hw->port_info->sw_id;\n+\t\tbuf[recps].content.mask[i] =\n+\t\t\tCPU_TO_LE16(ICE_AQ_SW_ID_LKUP_MASK);\n+\t\tfor (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {\n+\t\t\tbuf[recps].content.lkup_indx[i] =\n+\t\t\t\tICE_AQ_RECIPE_LKUP_IGNORE;\n+\t\t\tbuf[recps].content.mask[i] = 0;\n+\t\t}\n+\n+\t\ti = 1;\n+\t\t/* update r_bitmap with the recp that is used for chaining */\n+\t\tice_set_bit(rid, rm->r_bitmap);\n+\t\t/* this is the recipe that chains all the other recipes so it\n+\t\t * should not have a chaining ID to indicate the same\n+\t\t */\n+\t\tlast_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;\n+\t\tLIST_FOR_EACH_ENTRY(entry, &rm->rg_list, ice_recp_grp_entry,\n+\t\t\t\t    l_entry) {\n+\t\t\tlast_chain_entry->fv_idx[i] = entry->chain_idx;\n+\t\t\tbuf[recps].content.lkup_indx[i] = entry->chain_idx;\n+\t\t\tbuf[recps].content.mask[i++] = CPU_TO_LE16(0xFFFF);\n+\t\t\tice_set_bit(entry->rid, rm->r_bitmap);\n+\t\t}\n+\t\tLIST_ADD(&last_chain_entry->l_entry, &rm->rg_list);\n+\t\tif (sizeof(buf[recps].recipe_bitmap) >=\n+\t\t    sizeof(rm->r_bitmap)) {\n+\t\t\tice_memcpy(buf[recps].recipe_bitmap, rm->r_bitmap,\n+\t\t\t\t   sizeof(buf[recps].recipe_bitmap),\n+\t\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\t\t} else {\n+\t\t\tstatus = ICE_ERR_BAD_PTR;\n+\t\t\tgoto err_unroll;\n+\t\t}\n+\t\tbuf[recps].content.act_ctrl_fwd_priority = rm->priority;\n+\n+\t\t/* To differentiate among different UDP tunnels, a meta data ID\n+\t\t * flag is used.\n+\t\t */\n+\t\tif (match_tun) {\n+\t\t\tbuf[recps].content.lkup_indx[i] = ICE_TUN_FLAG_FV_IND;\n+\t\t\tbuf[recps].content.mask[i] =\n+\t\t\t\tCPU_TO_LE16(ICE_TUN_FLAG_MASK);\n+\t\t}\n+\n+\t\trecps++;\n+\t\trm->root_rid = (u8)rid;\n+\t}\n+\tstatus = ice_acquire_change_lock(hw, ICE_RES_WRITE);\n+\tif (status)\n+\t\tgoto err_unroll;\n+\n+\tstatus = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL);\n+\tice_release_change_lock(hw);\n+\tif (status)\n+\t\tgoto err_unroll;\n+\n+\t/* Every recipe that just got created add it to the recipe\n+\t * book keeping list\n+\t */\n+\tLIST_FOR_EACH_ENTRY(entry, &rm->rg_list, ice_recp_grp_entry, l_entry) {\n+\t\tstruct ice_switch_info *sw = hw->switch_info;\n+\t\tstruct ice_sw_recipe *recp;\n+\n+\t\trecp = &sw->recp_list[entry->rid];\n+\t\trecp->root_rid = entry->rid;\n+\t\tice_memcpy(&recp->ext_words, entry->r_group.pairs,\n+\t\t\t   entry->r_group.n_val_pairs *\n+\t\t\t   sizeof(struct ice_fv_word),\n+\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\n+\t\trecp->n_ext_words = entry->r_group.n_val_pairs;\n+\t\trecp->chain_idx = entry->chain_idx;\n+\t\trecp->recp_created = true;\n+\t\trecp->big_recp = false;\n+\t}\n+\trm->root_buf = buf;\n+\tice_free(hw, tmp);\n+\treturn status;\n+\n+err_unroll:\n+err_mem:\n+\tice_free(hw, tmp);\n+\tice_free(hw, buf);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_create_recipe_group - creates recipe group\n+ * @hw: pointer to hardware structure\n+ * @rm: recipe management list entry\n+ * @lkup_exts: lookup elements\n+ */\n+static enum ice_status\n+ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm,\n+\t\t\tstruct ice_prot_lkup_ext *lkup_exts)\n+{\n+\tstruct ice_recp_grp_entry *entry;\n+\tstruct ice_recp_grp_entry *tmp;\n+\tenum ice_status status;\n+\tu8 recp_count = 0;\n+\tu16 groups, i;\n+\n+\trm->n_grp_count = 0;\n+\n+\t/* Each switch recipe can match up to 5 words or metadata. One word in\n+\t * each recipe is used to match the switch ID. Four words are left for\n+\t * matching other values. If the new advanced recipe requires more than\n+\t * 4 words, it needs to be split into multiple recipes which are chained\n+\t * together using the intermediate result that each produces as input to\n+\t * the other recipes in the sequence.\n+\t */\n+\tgroups = ARRAY_SIZE(ice_recipe_pack);\n+\n+\t/* Check if any of the preferred recipes from the grouping policy\n+\t * matches.\n+\t */\n+\tfor (i = 0; i < groups; i++)\n+\t\t/* Check if the recipe from the preferred grouping matches\n+\t\t * or is a subset of the fields that needs to be looked up.\n+\t\t */\n+\t\tif (ice_is_recipe_subset(lkup_exts, &ice_recipe_pack[i])) {\n+\t\t\t/* This recipe can be used by itself or grouped with\n+\t\t\t * other recipes.\n+\t\t\t */\n+\t\t\tentry = (struct ice_recp_grp_entry *)\n+\t\t\t\tice_malloc(hw, sizeof(*entry));\n+\t\t\tif (!entry) {\n+\t\t\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\t\t\tgoto err_unroll;\n+\t\t\t}\n+\t\t\tentry->r_group = ice_recipe_pack[i];\n+\t\t\tLIST_ADD(&entry->l_entry, &rm->rg_list);\n+\t\t\trm->n_grp_count++;\n+\t\t}\n+\n+\t/* Create recipes for words that are marked not done by packing them\n+\t * as best fit.\n+\t */\n+\tstatus = ice_create_first_fit_recp_def(hw, lkup_exts,\n+\t\t\t\t\t       &rm->rg_list, &recp_count);\n+\tif (!status) {\n+\t\trm->n_grp_count += recp_count;\n+\t\trm->n_ext_words = lkup_exts->n_val_words;\n+\t\tice_memcpy(&rm->ext_words, lkup_exts->fv_words,\n+\t\t\t   sizeof(rm->ext_words), ICE_NONDMA_TO_NONDMA);\n+\t\tgoto out;\n+\t}\n+\n+err_unroll:\n+\tLIST_FOR_EACH_ENTRY_SAFE(entry, tmp, &rm->rg_list, ice_recp_grp_entry,\n+\t\t\t\t l_entry) {\n+\t\tLIST_DEL(&entry->l_entry);\n+\t\tice_free(hw, entry);\n+\t}\n+\n+out:\n+\treturn status;\n+}\n+\n+/**\n+ * ice_get_fv - get field vectors/extraction sequences for spec. lookup types\n+ * @hw: pointer to hardware structure\n+ * @lkups: lookup elements or match criteria for the advanced recipe, one\n+ *\t   structure per protocol header\n+ * @lkups_cnt: number of protocols\n+ * @fv_list: pointer to a list that holds the returned field vectors\n+ */\n+static enum ice_status\n+ice_get_fv(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,\n+\t   struct LIST_HEAD_TYPE *fv_list)\n+{\n+\tenum ice_status status;\n+\tu16 *prot_ids;\n+\tu16 i;\n+\n+\tprot_ids = (u16 *)ice_calloc(hw, lkups_cnt, sizeof(*prot_ids));\n+\tif (!prot_ids)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tfor (i = 0; i < lkups_cnt; i++)\n+\t\tif (!ice_prot_type_to_id(lkups[i].type, &prot_ids[i])) {\n+\t\t\tstatus = ICE_ERR_CFG;\n+\t\t\tgoto free_mem;\n+\t\t}\n+\n+\t/* Find field vectors that include all specified protocol types */\n+\tstatus = ice_get_sw_fv_list(hw, prot_ids, lkups_cnt, fv_list);\n+\n+free_mem:\n+\tice_free(hw, prot_ids);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_add_adv_recipe - Add an advanced recipe that is not part of the default\n+ * @hw: pointer to hardware structure\n+ * @lkups: lookup elements or match criteria for the advanced recipe, one\n+ *  structure per protocol header\n+ * @lkups_cnt: number of protocols\n+ * @rinfo: other information regarding the rule e.g. priority and action info\n+ * @rid: return the recipe ID of the recipe created\n+ */\n+static enum ice_status\n+ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,\n+\t\t   u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid)\n+{\n+\tstruct ice_prot_lkup_ext *lkup_exts;\n+\tstruct ice_recp_grp_entry *r_entry;\n+\tstruct ice_sw_fv_list_entry *fvit;\n+\tstruct ice_recp_grp_entry *r_tmp;\n+\tstruct ice_sw_fv_list_entry *tmp;\n+\tenum ice_status status = ICE_SUCCESS;\n+\tstruct ice_sw_recipe *rm;\n+\tbool match_tun = false;\n+\tu8 i;\n+\n+\tif (!lkups_cnt)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tlkup_exts = (struct ice_prot_lkup_ext *)\n+\t\tice_malloc(hw, sizeof(*lkup_exts));\n+\tif (!lkup_exts)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t/* Determine the number of words to be matched and if it exceeds a\n+\t * recipe's restrictions\n+\t */\n+\tfor (i = 0; i < lkups_cnt; i++) {\n+\t\tu16 count;\n+\n+\t\tif (lkups[i].type >= ICE_PROTOCOL_LAST) {\n+\t\t\tstatus = ICE_ERR_CFG;\n+\t\t\tgoto err_free_lkup_exts;\n+\t\t}\n+\n+\t\tcount = ice_fill_valid_words(&lkups[i], lkup_exts);\n+\t\tif (!count) {\n+\t\t\tstatus = ICE_ERR_CFG;\n+\t\t\tgoto err_free_lkup_exts;\n+\t\t}\n+\t}\n+\n+\t*rid = ice_find_recp(hw, lkup_exts);\n+\tif (*rid < ICE_MAX_NUM_RECIPES)\n+\t\t/* Success if found a recipe that match the existing criteria */\n+\t\tgoto err_free_lkup_exts;\n+\n+\t/* Recipe we need does not exist, add a recipe */\n+\n+\trm = (struct ice_sw_recipe *)ice_malloc(hw, sizeof(*rm));\n+\tif (!rm) {\n+\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\tgoto err_free_lkup_exts;\n+\t}\n+\n+\t/* Get field vectors that contain fields extracted from all the protocol\n+\t * headers being programmed.\n+\t */\n+\tINIT_LIST_HEAD(&rm->fv_list);\n+\tINIT_LIST_HEAD(&rm->rg_list);\n+\n+\tstatus = ice_get_fv(hw, lkups, lkups_cnt, &rm->fv_list);\n+\tif (status)\n+\t\tgoto err_unroll;\n+\n+\t/* Group match words into recipes using preferred recipe grouping\n+\t * criteria.\n+\t */\n+\tstatus = ice_create_recipe_group(hw, rm, lkup_exts);\n+\tif (status)\n+\t\tgoto err_unroll;\n+\n+\t/* There is only profile for UDP tunnels. So, it is necessary to use a\n+\t * metadata ID flag to differentiate different tunnel types. A separate\n+\t * recipe needs to be used for the metadata.\n+\t */\n+\tif ((rinfo->tun_type == ICE_SW_TUN_VXLAN_GPE ||\n+\t     rinfo->tun_type == ICE_SW_TUN_GENEVE ||\n+\t     rinfo->tun_type == ICE_SW_TUN_VXLAN) && rm->n_grp_count > 1)\n+\t\tmatch_tun = true;\n+\n+\t/* set the recipe priority if specified */\n+\trm->priority = rinfo->priority ? rinfo->priority : 0;\n+\n+\t/* Find offsets from the field vector. Pick the first one for all the\n+\t * recipes.\n+\t */\n+\tice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list);\n+\tstatus = ice_add_sw_recipe(hw, rm, match_tun);\n+\tif (status)\n+\t\tgoto err_unroll;\n+\n+\t/* Associate all the recipes created with all the profiles in the\n+\t * common field vector.\n+\t */\n+\tLIST_FOR_EACH_ENTRY(fvit, &rm->fv_list, ice_sw_fv_list_entry,\n+\t\t\t    list_entry) {\n+\t\tice_declare_bitmap(r_bitmap, ICE_MAX_NUM_RECIPES);\n+\n+\t\tstatus = ice_aq_get_recipe_to_profile(hw, fvit->profile_id,\n+\t\t\t\t\t\t      (u8 *)r_bitmap, NULL);\n+\t\tif (status)\n+\t\t\tgoto err_unroll;\n+\n+\t\tice_or_bitmap(rm->r_bitmap, r_bitmap, rm->r_bitmap,\n+\t\t\t      ICE_MAX_NUM_RECIPES);\n+\t\tstatus = ice_acquire_change_lock(hw, ICE_RES_WRITE);\n+\t\tif (status)\n+\t\t\tgoto err_unroll;\n+\n+\t\tstatus = ice_aq_map_recipe_to_profile(hw, fvit->profile_id,\n+\t\t\t\t\t\t      (u8 *)rm->r_bitmap,\n+\t\t\t\t\t\t      NULL);\n+\t\tice_release_change_lock(hw);\n+\n+\t\tif (status)\n+\t\t\tgoto err_unroll;\n+\t}\n+\n+\t*rid = rm->root_rid;\n+\tice_memcpy(&hw->switch_info->recp_list[*rid].lkup_exts,\n+\t\t   lkup_exts, sizeof(*lkup_exts), ICE_NONDMA_TO_NONDMA);\n+err_unroll:\n+\tLIST_FOR_EACH_ENTRY_SAFE(r_entry, r_tmp, &rm->rg_list,\n+\t\t\t\t ice_recp_grp_entry, l_entry) {\n+\t\tLIST_DEL(&r_entry->l_entry);\n+\t\tice_free(hw, r_entry);\n+\t}\n+\n+\tLIST_FOR_EACH_ENTRY_SAFE(fvit, tmp, &rm->fv_list, ice_sw_fv_list_entry,\n+\t\t\t\t list_entry) {\n+\t\tLIST_DEL(&fvit->list_entry);\n+\t\tice_free(hw, fvit);\n+\t}\n+\n+\tif (rm->root_buf)\n+\t\tice_free(hw, rm->root_buf);\n+\n+\tice_free(hw, rm);\n+\n+err_free_lkup_exts:\n+\tice_free(hw, lkup_exts);\n+\n+\treturn status;\n+}\n+\n+#define ICE_MAC_HDR_OFFSET\t0\n+#define ICE_IP_HDR_OFFSET\t14\n+#define ICE_GRE_HDR_OFFSET\t34\n+#define ICE_MAC_IL_HDR_OFFSET\t42\n+#define ICE_IP_IL_HDR_OFFSET\t56\n+#define ICE_L4_HDR_OFFSET\t34\n+#define ICE_UDP_TUN_HDR_OFFSET\t42\n+\n+/**\n+ * ice_find_dummy_packet - find dummy packet with given match criteria\n+ *\n+ * @lkups: lookup elements or match criteria for the advanced recipe, one\n+ *\t   structure per protocol header\n+ * @lkups_cnt: number of protocols\n+ * @tun_type: tunnel type from the match criteria\n+ * @pkt: dummy packet to fill according to filter match criteria\n+ * @pkt_len: packet length of dummy packet\n+ */\n+static void\n+ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,\n+\t\t      enum ice_sw_tunnel_type tun_type, const u8 **pkt,\n+\t\t      u16 *pkt_len)\n+{\n+\tu16 i;\n+\n+\tif (tun_type == ICE_SW_TUN_NVGRE || tun_type == ICE_ALL_TUNNELS) {\n+\t\t*pkt = dummy_gre_packet;\n+\t\t*pkt_len = sizeof(dummy_gre_packet);\n+\t\treturn;\n+\t}\n+\n+\tif (tun_type == ICE_SW_TUN_VXLAN || tun_type == ICE_SW_TUN_GENEVE ||\n+\t    tun_type == ICE_SW_TUN_VXLAN_GPE) {\n+\t\t*pkt = dummy_udp_tun_packet;\n+\t\t*pkt_len = sizeof(dummy_udp_tun_packet);\n+\t\treturn;\n+\t}\n+\n+\tfor (i = 0; i < lkups_cnt; i++) {\n+\t\tif (lkups[i].type == ICE_UDP_ILOS) {\n+\t\t\t*pkt = dummy_udp_tun_packet;\n+\t\t\t*pkt_len = sizeof(dummy_udp_tun_packet);\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\n+\t*pkt = dummy_tcp_tun_packet;\n+\t*pkt_len = sizeof(dummy_tcp_tun_packet);\n+}\n+\n+/**\n+ * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria\n+ *\n+ * @lkups: lookup elements or match criteria for the advanced recipe, one\n+ *\t   structure per protocol header\n+ * @lkups_cnt: number of protocols\n+ * @tun_type: to know if the dummy packet is supposed to be tunnel packet\n+ * @s_rule: stores rule information from the match criteria\n+ * @dummy_pkt: dummy packet to fill according to filter match criteria\n+ * @pkt_len: packet length of dummy packet\n+ */\n+static void\n+ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,\n+\t\t\t  enum ice_sw_tunnel_type tun_type,\n+\t\t\t  struct ice_aqc_sw_rules_elem *s_rule,\n+\t\t\t  const u8 *dummy_pkt, u16 pkt_len)\n+{\n+\tu8 *pkt;\n+\tu16 i;\n+\n+\t/* Start with a packet with a pre-defined/dummy content. Then, fill\n+\t * in the header values to be looked up or matched.\n+\t */\n+\tpkt = s_rule->pdata.lkup_tx_rx.hdr;\n+\n+\tice_memcpy(pkt, dummy_pkt, pkt_len, ICE_NONDMA_TO_NONDMA);\n+\n+\tfor (i = 0; i < lkups_cnt; i++) {\n+\t\tu32 len, pkt_off, hdr_size, field_off;\n+\n+\t\tswitch (lkups[i].type) {\n+\t\tcase ICE_MAC_OFOS:\n+\t\tcase ICE_MAC_IL:\n+\t\t\tpkt_off = offsetof(struct ice_ether_hdr, dst_addr) +\n+\t\t\t\t((lkups[i].type == ICE_MAC_IL) ?\n+\t\t\t\t ICE_MAC_IL_HDR_OFFSET : 0);\n+\t\t\tlen = sizeof(lkups[i].h_u.eth_hdr.dst_addr);\n+\t\t\tif ((tun_type == ICE_SW_TUN_VXLAN ||\n+\t\t\t     tun_type == ICE_SW_TUN_GENEVE ||\n+\t\t\t     tun_type == ICE_SW_TUN_VXLAN_GPE) &&\n+\t\t\t     lkups[i].type == ICE_MAC_IL) {\n+\t\t\t\tpkt_off += sizeof(struct ice_udp_tnl_hdr);\n+\t\t\t}\n+\n+\t\t\tice_memcpy(&pkt[pkt_off],\n+\t\t\t\t   &lkups[i].h_u.eth_hdr.dst_addr, len,\n+\t\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\t\t\tpkt_off = offsetof(struct ice_ether_hdr, src_addr) +\n+\t\t\t\t((lkups[i].type == ICE_MAC_IL) ?\n+\t\t\t\t ICE_MAC_IL_HDR_OFFSET : 0);\n+\t\t\tlen = sizeof(lkups[i].h_u.eth_hdr.src_addr);\n+\t\t\tif ((tun_type == ICE_SW_TUN_VXLAN ||\n+\t\t\t     tun_type == ICE_SW_TUN_GENEVE ||\n+\t\t\t     tun_type == ICE_SW_TUN_VXLAN_GPE) &&\n+\t\t\t     lkups[i].type == ICE_MAC_IL) {\n+\t\t\t\tpkt_off += sizeof(struct ice_udp_tnl_hdr);\n+\t\t\t}\n+\t\t\tice_memcpy(&pkt[pkt_off],\n+\t\t\t\t   &lkups[i].h_u.eth_hdr.src_addr, len,\n+\t\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\t\t\tif (lkups[i].h_u.eth_hdr.ethtype_id) {\n+\t\t\t\tpkt_off = offsetof(struct ice_ether_hdr,\n+\t\t\t\t\t\t   ethtype_id) +\n+\t\t\t\t\t((lkups[i].type == ICE_MAC_IL) ?\n+\t\t\t\t\t ICE_MAC_IL_HDR_OFFSET : 0);\n+\t\t\t\tlen = sizeof(lkups[i].h_u.eth_hdr.ethtype_id);\n+\t\t\t\tif ((tun_type == ICE_SW_TUN_VXLAN ||\n+\t\t\t\t     tun_type == ICE_SW_TUN_GENEVE ||\n+\t\t\t\t     tun_type == ICE_SW_TUN_VXLAN_GPE) &&\n+\t\t\t\t     lkups[i].type == ICE_MAC_IL) {\n+\t\t\t\t\tpkt_off +=\n+\t\t\t\t\t\tsizeof(struct ice_udp_tnl_hdr);\n+\t\t\t\t}\n+\t\t\t\tice_memcpy(&pkt[pkt_off],\n+\t\t\t\t\t   &lkups[i].h_u.eth_hdr.ethtype_id,\n+\t\t\t\t\t   len, ICE_NONDMA_TO_NONDMA);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase ICE_IPV4_OFOS:\n+\t\t\thdr_size = sizeof(struct ice_ipv4_hdr);\n+\t\t\tif (lkups[i].h_u.ipv4_hdr.dst_addr) {\n+\t\t\t\tpkt_off = ICE_IP_HDR_OFFSET +\n+\t\t\t\t\t   offsetof(struct ice_ipv4_hdr,\n+\t\t\t\t\t\t    dst_addr);\n+\t\t\t\tfield_off = offsetof(struct ice_ipv4_hdr,\n+\t\t\t\t\t\t     dst_addr);\n+\t\t\t\tlen = hdr_size - field_off;\n+\t\t\t\tice_memcpy(&pkt[pkt_off],\n+\t\t\t\t\t   &lkups[i].h_u.ipv4_hdr.dst_addr,\n+\t\t\t\t\t   len, ICE_NONDMA_TO_NONDMA);\n+\t\t\t}\n+\t\t\tif (lkups[i].h_u.ipv4_hdr.src_addr) {\n+\t\t\t\tpkt_off = ICE_IP_HDR_OFFSET +\n+\t\t\t\t\t   offsetof(struct ice_ipv4_hdr,\n+\t\t\t\t\t\t    src_addr);\n+\t\t\t\tfield_off = offsetof(struct ice_ipv4_hdr,\n+\t\t\t\t\t\t     src_addr);\n+\t\t\t\tlen = hdr_size - field_off;\n+\t\t\t\tice_memcpy(&pkt[pkt_off],\n+\t\t\t\t\t   &lkups[i].h_u.ipv4_hdr.src_addr,\n+\t\t\t\t\t   len, ICE_NONDMA_TO_NONDMA);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase ICE_IPV4_IL:\n+\t\t\tbreak;\n+\t\tcase ICE_TCP_IL:\n+\t\tcase ICE_UDP_ILOS:\n+\t\tcase ICE_SCTP_IL:\n+\t\t\thdr_size = sizeof(struct ice_udp_tnl_hdr);\n+\t\t\tif (lkups[i].h_u.l4_hdr.dst_port) {\n+\t\t\t\tpkt_off = ICE_L4_HDR_OFFSET +\n+\t\t\t\t\t   offsetof(struct ice_l4_hdr,\n+\t\t\t\t\t\t    dst_port);\n+\t\t\t\tfield_off = offsetof(struct ice_l4_hdr,\n+\t\t\t\t\t\t     dst_port);\n+\t\t\t\tlen =  hdr_size - field_off;\n+\t\t\t\tice_memcpy(&pkt[pkt_off],\n+\t\t\t\t\t   &lkups[i].h_u.l4_hdr.dst_port,\n+\t\t\t\t\t   len, ICE_NONDMA_TO_NONDMA);\n+\t\t\t}\n+\t\t\tif (lkups[i].h_u.l4_hdr.src_port) {\n+\t\t\t\tpkt_off = ICE_L4_HDR_OFFSET +\n+\t\t\t\t\toffsetof(struct ice_l4_hdr, src_port);\n+\t\t\t\tfield_off = offsetof(struct ice_l4_hdr,\n+\t\t\t\t\t\t     src_port);\n+\t\t\t\tlen =  hdr_size - field_off;\n+\t\t\t\tice_memcpy(&pkt[pkt_off],\n+\t\t\t\t\t   &lkups[i].h_u.l4_hdr.src_port,\n+\t\t\t\t\t   len, ICE_NONDMA_TO_NONDMA);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase ICE_VXLAN:\n+\t\tcase ICE_GENEVE:\n+\t\tcase ICE_VXLAN_GPE:\n+\t\t\tpkt_off = ICE_UDP_TUN_HDR_OFFSET +\n+\t\t\t\t   offsetof(struct ice_udp_tnl_hdr, vni);\n+\t\t\tfield_off = offsetof(struct ice_udp_tnl_hdr, vni);\n+\t\t\tlen =  sizeof(struct ice_udp_tnl_hdr) - field_off;\n+\t\t\tice_memcpy(&pkt[pkt_off], &lkups[i].h_u.tnl_hdr.vni,\n+\t\t\t\t   len, ICE_NONDMA_TO_NONDMA);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\ts_rule->pdata.lkup_tx_rx.hdr_len = CPU_TO_LE16(pkt_len);\n+}\n+\n+/**\n+ * ice_find_adv_rule_entry - Search a rule entry\n+ * @hw: pointer to the hardware structure\n+ * @lkups: lookup elements or match criteria for the advanced recipe, one\n+ *\t   structure per protocol header\n+ * @lkups_cnt: number of protocols\n+ * @recp_id: recipe ID for which we are finding the rule\n+ * @rinfo: other information regarding the rule e.g. priority and action info\n+ *\n+ * Helper function to search for a given advance rule entry\n+ * Returns pointer to entry storing the rule if found\n+ */\n+static struct ice_adv_fltr_mgmt_list_entry *\n+ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,\n+\t\t\tu16 lkups_cnt, u8 recp_id,\n+\t\t\tstruct ice_adv_rule_info *rinfo)\n+{\n+\tstruct ice_adv_fltr_mgmt_list_entry *list_itr;\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tint i;\n+\n+\tLIST_FOR_EACH_ENTRY(list_itr, &sw->recp_list[recp_id].filt_rules,\n+\t\t\t    ice_adv_fltr_mgmt_list_entry, list_entry) {\n+\t\tbool lkups_matched = true;\n+\n+\t\tif (lkups_cnt != list_itr->lkups_cnt)\n+\t\t\tcontinue;\n+\t\tfor (i = 0; i < list_itr->lkups_cnt; i++)\n+\t\t\tif (memcmp(&list_itr->lkups[i], &lkups[i],\n+\t\t\t\t   sizeof(*lkups))) {\n+\t\t\t\tlkups_matched = false;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\tif (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag &&\n+\t\t    rinfo->tun_type == list_itr->rule_info.tun_type &&\n+\t\t    lkups_matched)\n+\t\t\treturn list_itr;\n+\t}\n+\treturn NULL;\n+}\n+\n+/**\n+ * ice_adv_add_update_vsi_list\n+ * @hw: pointer to the hardware structure\n+ * @m_entry: pointer to current adv filter management list entry\n+ * @cur_fltr: filter information from the book keeping entry\n+ * @new_fltr: filter information with the new VSI to be added\n+ *\n+ * Call AQ command to add or update previously created VSI list with new VSI.\n+ *\n+ * Helper function to do book keeping associated with adding filter information\n+ * The algorithm to do the booking keeping is described below :\n+ * When a VSI needs to subscribe to a given advanced filter\n+ *\tif only one VSI has been added till now\n+ *\t\tAllocate a new VSI list and add two VSIs\n+ *\t\tto this list using switch rule command\n+ *\t\tUpdate the previously created switch rule with the\n+ *\t\tnewly created VSI list ID\n+ *\tif a VSI list was previously created\n+ *\t\tAdd the new VSI to the previously created VSI list set\n+ *\t\tusing the update switch rule command\n+ */\n+static enum ice_status\n+ice_adv_add_update_vsi_list(struct ice_hw *hw,\n+\t\t\t    struct ice_adv_fltr_mgmt_list_entry *m_entry,\n+\t\t\t    struct ice_adv_rule_info *cur_fltr,\n+\t\t\t    struct ice_adv_rule_info *new_fltr)\n+{\n+\tenum ice_status status;\n+\tu16 vsi_list_id = 0;\n+\n+\tif (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||\n+\t    cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP)\n+\t\treturn ICE_ERR_NOT_IMPL;\n+\n+\tif (cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET &&\n+\t    new_fltr->sw_act.fltr_act == ICE_DROP_PACKET)\n+\t\treturn ICE_ERR_ALREADY_EXISTS;\n+\n+\tif ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q ||\n+\t     new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) &&\n+\t    (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI ||\n+\t     cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST))\n+\t\treturn ICE_ERR_NOT_IMPL;\n+\n+\tif (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {\n+\t\t /* Only one entry existed in the mapping and it was not already\n+\t\t  * a part of a VSI list. So, create a VSI list with the old and\n+\t\t  * new VSIs.\n+\t\t  */\n+\t\tstruct ice_fltr_info tmp_fltr;\n+\t\tu16 vsi_handle_arr[2];\n+\n+\t\t/* A rule already exists with the new VSI being added */\n+\t\tif (cur_fltr->sw_act.fwd_id.hw_vsi_id ==\n+\t\t    new_fltr->sw_act.fwd_id.hw_vsi_id)\n+\t\t\treturn ICE_ERR_ALREADY_EXISTS;\n+\n+\t\tvsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle;\n+\t\tvsi_handle_arr[1] = new_fltr->sw_act.vsi_handle;\n+\t\tstatus = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,\n+\t\t\t\t\t\t  &vsi_list_id,\n+\t\t\t\t\t\t  ICE_SW_LKUP_LAST);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\ttmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;\n+\t\ttmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;\n+\t\ttmp_fltr.fwd_id.vsi_list_id = vsi_list_id;\n+\t\t/* Update the previous switch rule of \"forward to VSI\" to\n+\t\t * \"fwd to VSI list\"\n+\t\t */\n+\t\tstatus = ice_update_pkt_fwd_rule(hw, &tmp_fltr);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\tcur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id;\n+\t\tcur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST;\n+\t\tm_entry->vsi_list_info =\n+\t\t\tice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,\n+\t\t\t\t\t\tvsi_list_id);\n+\t} else {\n+\t\tu16 vsi_handle = new_fltr->sw_act.vsi_handle;\n+\n+\t\tif (!m_entry->vsi_list_info)\n+\t\t\treturn ICE_ERR_CFG;\n+\n+\t\t/* A rule already exists with the new VSI being added */\n+\t\tif (ice_is_bit_set(m_entry->vsi_list_info->vsi_map, vsi_handle))\n+\t\t\treturn ICE_SUCCESS;\n+\n+\t\t/* Update the previously created VSI list set with\n+\t\t * the new VSI ID passed in\n+\t\t */\n+\t\tvsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id;\n+\n+\t\tstatus = ice_update_vsi_list_rule(hw, &vsi_handle, 1,\n+\t\t\t\t\t\t  vsi_list_id, false,\n+\t\t\t\t\t\t  ice_aqc_opc_update_sw_rules,\n+\t\t\t\t\t\t  ICE_SW_LKUP_LAST);\n+\t\t/* update VSI list mapping info with new VSI ID */\n+\t\tif (!status)\n+\t\t\tice_set_bit(vsi_handle,\n+\t\t\t\t    m_entry->vsi_list_info->vsi_map);\n+\t}\n+\tif (!status)\n+\t\tm_entry->vsi_count++;\n+\treturn status;\n+}\n+\n+/**\n+ * ice_add_adv_rule - create an advanced switch rule\n+ * @hw: pointer to the hardware structure\n+ * @lkups: information on the words that needs to be looked up. All words\n+ * together makes one recipe\n+ * @lkups_cnt: num of entries in the lkups array\n+ * @rinfo: other information related to the rule that needs to be programmed\n+ * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be\n+ *               ignored is case of error.\n+ *\n+ * This function can program only 1 rule at a time. The lkups is used to\n+ * describe the all the words that forms the \"lookup\" portion of the recipe.\n+ * These words can span multiple protocols. Callers to this function need to\n+ * pass in a list of protocol headers with lookup information along and mask\n+ * that determines which words are valid from the given protocol header.\n+ * rinfo describes other information related to this rule such as forwarding\n+ * IDs, priority of this rule, etc.\n+ */\n+enum ice_status\n+ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,\n+\t\t u16 lkups_cnt, struct ice_adv_rule_info *rinfo,\n+\t\t struct ice_rule_query_data *added_entry)\n+{\n+\tstruct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL;\n+\tu16 rid = 0, i, pkt_len, rule_buf_sz, vsi_handle;\n+\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\tstruct LIST_HEAD_TYPE *rule_head;\n+\tstruct ice_switch_info *sw;\n+\tenum ice_status status;\n+\tconst u8 *pkt = NULL;\n+\tu32 act = 0;\n+\n+\tif (!lkups_cnt)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tfor (i = 0; i < lkups_cnt; i++) {\n+\t\tu16 j, *ptr;\n+\n+\t\t/* Validate match masks to make sure they match complete 16-bit\n+\t\t * words.\n+\t\t */\n+\t\tptr = (u16 *)&lkups->m_u;\n+\t\tfor (j = 0; j < sizeof(lkups->m_u) / sizeof(u16); j++)\n+\t\t\tif (ptr[j] != 0 && ptr[j] != 0xffff)\n+\t\t\t\treturn ICE_ERR_PARAM;\n+\t}\n+\n+\tif (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||\n+\t      rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||\n+\t      rinfo->sw_act.fltr_act == ICE_DROP_PACKET))\n+\t\treturn ICE_ERR_CFG;\n+\n+\tvsi_handle = rinfo->sw_act.vsi_handle;\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tif (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)\n+\t\trinfo->sw_act.fwd_id.hw_vsi_id =\n+\t\t\tice_get_hw_vsi_num(hw, vsi_handle);\n+\tif (rinfo->sw_act.flag & ICE_FLTR_TX)\n+\t\trinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle);\n+\n+\tstatus = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid);\n+\tif (status)\n+\t\treturn status;\n+\tm_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);\n+\tif (m_entry) {\n+\t\t/* we have to add VSI to VSI_LIST and increment vsi_count.\n+\t\t * Also Update VSI list so that we can change forwarding rule\n+\t\t * if the rule already exists, we will check if it exists with\n+\t\t * same vsi_id, if not then add it to the VSI list if it already\n+\t\t * exists if not then create a VSI list and add the existing VSI\n+\t\t * ID and the new VSI ID to the list\n+\t\t * We will add that VSI to the list\n+\t\t */\n+\t\tstatus = ice_adv_add_update_vsi_list(hw, m_entry,\n+\t\t\t\t\t\t     &m_entry->rule_info,\n+\t\t\t\t\t\t     rinfo);\n+\t\tif (added_entry) {\n+\t\t\tadded_entry->rid = rid;\n+\t\t\tadded_entry->rule_id = m_entry->rule_info.fltr_rule_id;\n+\t\t\tadded_entry->vsi_handle = rinfo->sw_act.vsi_handle;\n+\t\t}\n+\t\treturn status;\n+\t}\n+\tice_find_dummy_packet(lkups, lkups_cnt, rinfo->tun_type, &pkt,\n+\t\t\t      &pkt_len);\n+\trule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE + pkt_len;\n+\ts_rule = (struct ice_aqc_sw_rules_elem *)ice_malloc(hw, rule_buf_sz);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\tact |= ICE_SINGLE_ACT_LB_ENABLE | ICE_SINGLE_ACT_LAN_ENABLE;\n+\tswitch (rinfo->sw_act.fltr_act) {\n+\tcase ICE_FWD_TO_VSI:\n+\t\tact |= (rinfo->sw_act.fwd_id.hw_vsi_id <<\n+\t\t\tICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M;\n+\t\tact |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT;\n+\t\tbreak;\n+\tcase ICE_FWD_TO_Q:\n+\t\tact |= ICE_SINGLE_ACT_TO_Q;\n+\t\tact |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &\n+\t\t       ICE_SINGLE_ACT_Q_INDEX_M;\n+\t\tbreak;\n+\tcase ICE_DROP_PACKET:\n+\t\tact |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |\n+\t\t       ICE_SINGLE_ACT_VALID_BIT;\n+\t\tbreak;\n+\tdefault:\n+\t\tstatus = ICE_ERR_CFG;\n+\t\tgoto err_ice_add_adv_rule;\n+\t}\n+\n+\t/* set the rule LOOKUP type based on caller specified 'RX'\n+\t * instead of hardcoding it to be either LOOKUP_TX/RX\n+\t *\n+\t * for 'RX' set the source to be the port number\n+\t * for 'TX' set the source to be the source HW VSI number (determined\n+\t * by caller)\n+\t */\n+\tif (rinfo->rx) {\n+\t\ts_rule->type = CPU_TO_LE16(ICE_AQC_SW_RULES_T_LKUP_RX);\n+\t\ts_rule->pdata.lkup_tx_rx.src =\n+\t\t\tCPU_TO_LE16(hw->port_info->lport);\n+\t} else {\n+\t\ts_rule->type = CPU_TO_LE16(ICE_AQC_SW_RULES_T_LKUP_TX);\n+\t\ts_rule->pdata.lkup_tx_rx.src = CPU_TO_LE16(rinfo->sw_act.src);\n+\t}\n+\n+\ts_rule->pdata.lkup_tx_rx.recipe_id = CPU_TO_LE16(rid);\n+\ts_rule->pdata.lkup_tx_rx.act = CPU_TO_LE32(act);\n+\n+\tice_fill_adv_dummy_packet(lkups, lkups_cnt, rinfo->tun_type, s_rule,\n+\t\t\t\t  pkt, pkt_len);\n+\n+\tstatus = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,\n+\t\t\t\t rule_buf_sz, 1, ice_aqc_opc_add_sw_rules,\n+\t\t\t\t NULL);\n+\tif (status)\n+\t\tgoto err_ice_add_adv_rule;\n+\tadv_fltr = (struct ice_adv_fltr_mgmt_list_entry *)\n+\t\tice_malloc(hw, sizeof(struct ice_adv_fltr_mgmt_list_entry));\n+\tif (!adv_fltr) {\n+\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\tgoto err_ice_add_adv_rule;\n+\t}\n+\n+\tadv_fltr->lkups = (struct ice_adv_lkup_elem *)\n+\t\tice_memdup(hw, lkups, lkups_cnt * sizeof(*lkups),\n+\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\tif (!adv_fltr->lkups) {\n+\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\tgoto err_ice_add_adv_rule;\n+\t}\n+\n+\tadv_fltr->lkups_cnt = lkups_cnt;\n+\tadv_fltr->rule_info = *rinfo;\n+\tadv_fltr->rule_info.fltr_rule_id =\n+\t\tLE16_TO_CPU(s_rule->pdata.lkup_tx_rx.index);\n+\tsw = hw->switch_info;\n+\tsw->recp_list[rid].adv_rule = true;\n+\trule_head = &sw->recp_list[rid].filt_rules;\n+\n+\tif (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) {\n+\t\tstruct ice_fltr_info tmp_fltr;\n+\n+\t\ttmp_fltr.fltr_rule_id =\n+\t\t\tLE16_TO_CPU(s_rule->pdata.lkup_tx_rx.index);\n+\t\ttmp_fltr.fltr_act = ICE_FWD_TO_VSI;\n+\t\ttmp_fltr.fwd_id.hw_vsi_id =\n+\t\t\tice_get_hw_vsi_num(hw, vsi_handle);\n+\t\ttmp_fltr.vsi_handle = vsi_handle;\n+\t\t/* Update the previous switch rule of \"forward to VSI\" to\n+\t\t * \"fwd to VSI list\"\n+\t\t */\n+\t\tstatus = ice_update_pkt_fwd_rule(hw, &tmp_fltr);\n+\t\tif (status)\n+\t\t\tgoto err_ice_add_adv_rule;\n+\t\tadv_fltr->vsi_count = 1;\n+\t}\n+\n+\t/* Add rule entry to book keeping list */\n+\tLIST_ADD(&adv_fltr->list_entry, rule_head);\n+\tif (added_entry) {\n+\t\tadded_entry->rid = rid;\n+\t\tadded_entry->rule_id = adv_fltr->rule_info.fltr_rule_id;\n+\t\tadded_entry->vsi_handle = rinfo->sw_act.vsi_handle;\n+\t}\n+err_ice_add_adv_rule:\n+\tif (status && adv_fltr) {\n+\t\tice_free(hw, adv_fltr->lkups);\n+\t\tice_free(hw, adv_fltr);\n+\t}\n+\n+\tice_free(hw, s_rule);\n+\n+\treturn status;\n+}\n /**\n  * ice_replay_fltr - Replay all the filters stored by a specific list head\n  * @hw: pointer to the hardware structure\ndiff --git a/drivers/net/ice/base/ice_switch.h b/drivers/net/ice/base/ice_switch.h\nindex fd61c0eea..890df13dd 100644\n--- a/drivers/net/ice/base/ice_switch.h\n+++ b/drivers/net/ice/base/ice_switch.h\n@@ -172,11 +172,21 @@ struct ice_sw_act_ctrl {\n \tu8 qgrp_size;\n };\n \n+struct ice_rule_query_data {\n+\t/* Recipe ID for which the requested rule was added */\n+\tu16 rid;\n+\t/* Rule ID that was added or is supposed to be removed */\n+\tu16 rule_id;\n+\t/* vsi_handle for which Rule was added or is supposed to be removed */\n+\tu16 vsi_handle;\n+};\n+\n struct ice_adv_rule_info {\n \tenum ice_sw_tunnel_type tun_type;\n \tstruct ice_sw_act_ctrl sw_act;\n \tu32 priority;\n \tu8 rx; /* true means LOOKUP_RX otherwise LOOKUP_TX */\n+\tu16 fltr_rule_id;\n };\n \n /* A collection of one or more four word recipe */\n@@ -222,6 +232,7 @@ struct ice_sw_recipe {\n \t/* Profiles this recipe should be associated with */\n \tstruct LIST_HEAD_TYPE fv_list;\n \n+#define ICE_MAX_NUM_PROFILES 256\n \t/* Profiles this recipe is associated with */\n \tu8 num_profs, *prof_ids;\n \n@@ -281,6 +292,8 @@ struct ice_adv_fltr_mgmt_list_entry {\n \tstruct ice_adv_lkup_elem *lkups;\n \tstruct ice_adv_rule_info rule_info;\n \tu16 lkups_cnt;\n+\tstruct ice_vsi_list_map_info *vsi_list_info;\n+\tu16 vsi_count;\n };\n \n enum ice_promisc_flags {\n@@ -421,7 +434,15 @@ enum ice_status\n ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,\n \t\t\t     struct ice_sq_cd *cd);\n \n+enum ice_status\n+ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,\n+\t\t\t     struct ice_sq_cd *cd);\n+\n enum ice_status ice_alloc_recipe(struct ice_hw *hw, u16 *recipe_id);\n+enum ice_status\n+ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,\n+\t\t u16 lkups_cnt, struct ice_adv_rule_info *rinfo,\n+\t\t struct ice_rule_query_data *added_entry);\n enum ice_status ice_replay_all_fltr(struct ice_hw *hw);\n \n enum ice_status ice_init_def_sw_recp(struct ice_hw *hw);\n",
    "prefixes": [
        "v2",
        "07/66"
    ]
}