get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 48977,
    "url": "https://patches.dpdk.org/api/patches/48977/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1545032259-77179-9-git-send-email-wenzhuo.lu@intel.com/",
    "project": {
        "id": 1,
        "url": "https://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": "<1545032259-77179-9-git-send-email-wenzhuo.lu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1545032259-77179-9-git-send-email-wenzhuo.lu@intel.com",
    "date": "2018-12-17T07:37:16",
    "name": "[v5,08/31] net/ice/base: add virtual switch code",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "a1032ade10a98d150fb61bec32d008146f709a8a",
    "submitter": {
        "id": 258,
        "url": "https://patches.dpdk.org/api/people/258/?format=api",
        "name": "Wenzhuo Lu",
        "email": "wenzhuo.lu@intel.com"
    },
    "delegate": {
        "id": 1540,
        "url": "https://patches.dpdk.org/api/users/1540/?format=api",
        "username": "qzhan15",
        "first_name": "Qi",
        "last_name": "Zhang",
        "email": "qi.z.zhang@intel.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1545032259-77179-9-git-send-email-wenzhuo.lu@intel.com/mbox/",
    "series": [
        {
            "id": 2824,
            "url": "https://patches.dpdk.org/api/series/2824/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=2824",
            "date": "2018-12-17T07:37:08",
            "name": "A new net PMD - ICE",
            "version": 5,
            "mbox": "https://patches.dpdk.org/series/2824/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/48977/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/48977/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 C2A921B71D;\n\tMon, 17 Dec 2018 08:33:13 +0100 (CET)",
            "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n\tby dpdk.org (Postfix) with ESMTP id 83B0D1B5B8\n\tfor <dev@dpdk.org>; Mon, 17 Dec 2018 08:33:05 +0100 (CET)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t16 Dec 2018 23:33:03 -0800",
            "from dpdk26.sh.intel.com ([10.67.110.164])\n\tby orsmga002.jf.intel.com with ESMTP; 16 Dec 2018 23:33:03 -0800"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.56,364,1539673200\"; d=\"scan'208\";a=\"118899143\"",
        "From": "Wenzhuo Lu <wenzhuo.lu@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>",
        "Date": "Mon, 17 Dec 2018 15:37:16 +0800",
        "Message-Id": "<1545032259-77179-9-git-send-email-wenzhuo.lu@intel.com>",
        "X-Mailer": "git-send-email 1.9.3",
        "In-Reply-To": "<1545032259-77179-1-git-send-email-wenzhuo.lu@intel.com>",
        "References": "<1542956179-80951-1-git-send-email-wenzhuo.lu@intel.com>\n\t<1545032259-77179-1-git-send-email-wenzhuo.lu@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v5 08/31] net/ice/base: add virtual switch code",
        "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": "From: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>\n\nAdd code to handle the virtual switch within the NIC.\n\nSigned-off-by: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>\n---\n drivers/net/ice/base/ice_switch.c | 2812 +++++++++++++++++++++++++++++++++++++\n drivers/net/ice/base/ice_switch.h |  333 +++++\n 2 files changed, 3145 insertions(+)\n create mode 100644 drivers/net/ice/base/ice_switch.c\n create mode 100644 drivers/net/ice/base/ice_switch.h",
    "diff": "diff --git a/drivers/net/ice/base/ice_switch.c b/drivers/net/ice/base/ice_switch.c\nnew file mode 100644\nindex 0000000..0379cd0\n--- /dev/null\n+++ b/drivers/net/ice/base/ice_switch.c\n@@ -0,0 +1,2812 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2001-2018\n+ */\n+\n+#include \"ice_switch.h\"\n+\n+\n+#define ICE_ETH_DA_OFFSET\t\t0\n+#define ICE_ETH_ETHTYPE_OFFSET\t\t12\n+#define ICE_ETH_VLAN_TCI_OFFSET\t\t14\n+#define ICE_MAX_VLAN_ID\t\t\t0xFFF\n+\n+/* Dummy ethernet header needed in the ice_aqc_sw_rules_elem\n+ * struct to configure any switch filter rules.\n+ * {DA (6 bytes), SA(6 bytes),\n+ * Ether type (2 bytes for header without VLAN tag) OR\n+ * VLAN tag (4 bytes for header with VLAN tag) }\n+ *\n+ * Word on Hardcoded values\n+ * byte 0 = 0x2: to identify it as locally administered DA MAC\n+ * byte 6 = 0x2: to identify it as locally administered SA MAC\n+ * byte 12 = 0x81 & byte 13 = 0x00:\n+ *\tIn case of VLAN filter first two bytes defines ether type (0x8100)\n+ *\tand remaining two bytes are placeholder for programming a given VLAN id\n+ *\tIn case of Ether type filter it is treated as header without VLAN tag\n+ *\tand byte 12 and 13 is used to program a given Ether type instead\n+ */\n+#define DUMMY_ETH_HDR_LEN\t\t16\n+static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,\n+\t\t\t\t\t\t\t0x2, 0, 0, 0, 0, 0,\n+\t\t\t\t\t\t\t0x81, 0, 0, 0};\n+\n+#define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE \\\n+\t(sizeof(struct ice_aqc_sw_rules_elem) - \\\n+\t sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \\\n+\t sizeof(struct ice_sw_rule_lkup_rx_tx) + DUMMY_ETH_HDR_LEN - 1)\n+#define ICE_SW_RULE_RX_TX_NO_HDR_SIZE \\\n+\t(sizeof(struct ice_aqc_sw_rules_elem) - \\\n+\t sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \\\n+\t sizeof(struct ice_sw_rule_lkup_rx_tx) - 1)\n+#define ICE_SW_RULE_LG_ACT_SIZE(n) \\\n+\t(sizeof(struct ice_aqc_sw_rules_elem) - \\\n+\t sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \\\n+\t sizeof(struct ice_sw_rule_lg_act) - \\\n+\t sizeof(((struct ice_sw_rule_lg_act *)0)->act) + \\\n+\t ((n) * sizeof(((struct ice_sw_rule_lg_act *)0)->act)))\n+#define ICE_SW_RULE_VSI_LIST_SIZE(n) \\\n+\t(sizeof(struct ice_aqc_sw_rules_elem) - \\\n+\t sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \\\n+\t sizeof(struct ice_sw_rule_vsi_list) - \\\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+\n+/**\n+ * ice_init_def_sw_recp - initialize the recipe book keeping tables\n+ * @hw: pointer to the hw struct\n+ *\n+ * Allocate memory for the entire recipe table and initialize the structures/\n+ * entries corresponding to basic recipes.\n+ */\n+enum ice_status ice_init_def_sw_recp(struct ice_hw *hw)\n+{\n+\tstruct ice_sw_recipe *recps;\n+\tu8 i;\n+\n+\trecps = (struct ice_sw_recipe *)\n+\t\tice_calloc(hw, ICE_MAX_NUM_RECIPES, sizeof(*recps));\n+\tif (!recps)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tfor (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {\n+\t\trecps[i].root_rid = i;\n+\t\tINIT_LIST_HEAD(&recps[i].filt_rules);\n+\t\tINIT_LIST_HEAD(&recps[i].filt_replay_rules);\n+\t\tice_init_lock(&recps[i].filt_rule_lock);\n+\t}\n+\n+\thw->switch_info->recp_list = recps;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_aq_get_sw_cfg - get switch configuration\n+ * @hw: pointer to the hardware structure\n+ * @buf: pointer to the result buffer\n+ * @buf_size: length of the buffer available for response\n+ * @req_desc: pointer to requested descriptor\n+ * @num_elems: pointer to number of elements\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Get switch configuration (0x0200) to be placed in 'buff'.\n+ * This admin command returns information such as initial VSI/port number\n+ * and switch ID it belongs to.\n+ *\n+ * NOTE: *req_desc is both an input/output parameter.\n+ * The caller of this function first calls this function with *request_desc set\n+ * to 0. If the response from f/w has *req_desc set to 0, all the switch\n+ * configuration information has been returned; if non-zero (meaning not all\n+ * the information was returned), the caller should call this function again\n+ * with *req_desc set to the previous value returned by f/w to get the\n+ * next block of switch configuration information.\n+ *\n+ * *num_elems is output only parameter. This reflects the number of elements\n+ * in response buffer. The caller of this function to use *num_elems while\n+ * parsing the response buffer.\n+ */\n+static enum ice_status\n+ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp *buf,\n+\t\t  u16 buf_size, u16 *req_desc, u16 *num_elems,\n+\t\t  struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_get_sw_cfg *cmd;\n+\tenum ice_status status;\n+\tstruct ice_aq_desc desc;\n+\n+\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg);\n+\tcmd = &desc.params.get_sw_conf;\n+\tcmd->element = CPU_TO_LE16(*req_desc);\n+\n+\tstatus = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);\n+\tif (!status) {\n+\t\t*req_desc = LE16_TO_CPU(cmd->element);\n+\t\t*num_elems = LE16_TO_CPU(cmd->num_elems);\n+\t}\n+\n+\treturn status;\n+}\n+\n+\n+\n+/**\n+ * ice_aq_add_vsi\n+ * @hw: pointer to the hw struct\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Add a VSI context to the hardware (0x0210)\n+ */\n+static enum ice_status\n+ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n+\t       struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_add_update_free_vsi_resp *res;\n+\tstruct ice_aqc_add_get_update_free_vsi *cmd;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\n+\tcmd = &desc.params.vsi_cmd;\n+\tres = &desc.params.add_update_free_vsi_res;\n+\n+\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);\n+\n+\tif (!vsi_ctx->alloc_from_pool)\n+\t\tcmd->vsi_num = CPU_TO_LE16(vsi_ctx->vsi_num |\n+\t\t\t\t\t   ICE_AQ_VSI_IS_VALID);\n+\n+\tcmd->vsi_flags = CPU_TO_LE16(vsi_ctx->flags);\n+\n+\tdesc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);\n+\n+\tstatus = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,\n+\t\t\t\t sizeof(vsi_ctx->info), cd);\n+\n+\tif (!status) {\n+\t\tvsi_ctx->vsi_num = LE16_TO_CPU(res->vsi_num) & ICE_AQ_VSI_NUM_M;\n+\t\tvsi_ctx->vsis_allocd = LE16_TO_CPU(res->vsi_used);\n+\t\tvsi_ctx->vsis_unallocated = LE16_TO_CPU(res->vsi_free);\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_aq_free_vsi\n+ * @hw: pointer to the hw struct\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Free VSI context info from hardware (0x0213)\n+ */\n+static enum ice_status\n+ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n+\t\tbool keep_vsi_alloc, struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_add_update_free_vsi_resp *resp;\n+\tstruct ice_aqc_add_get_update_free_vsi *cmd;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\n+\tcmd = &desc.params.vsi_cmd;\n+\tresp = &desc.params.add_update_free_vsi_res;\n+\n+\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);\n+\n+\tcmd->vsi_num = CPU_TO_LE16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);\n+\tif (keep_vsi_alloc)\n+\t\tcmd->cmd_flags = CPU_TO_LE16(ICE_AQ_VSI_KEEP_ALLOC);\n+\n+\tstatus = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);\n+\tif (!status) {\n+\t\tvsi_ctx->vsis_allocd = LE16_TO_CPU(resp->vsi_used);\n+\t\tvsi_ctx->vsis_unallocated = LE16_TO_CPU(resp->vsi_free);\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_aq_update_vsi\n+ * @hw: pointer to the hw struct\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Update VSI context in the hardware (0x0211)\n+ */\n+static enum ice_status\n+ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n+\t\t  struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_add_update_free_vsi_resp *resp;\n+\tstruct ice_aqc_add_get_update_free_vsi *cmd;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\n+\tcmd = &desc.params.vsi_cmd;\n+\tresp = &desc.params.add_update_free_vsi_res;\n+\n+\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);\n+\n+\tcmd->vsi_num = CPU_TO_LE16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);\n+\n+\tdesc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);\n+\n+\tstatus = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,\n+\t\t\t\t sizeof(vsi_ctx->info), cd);\n+\n+\tif (!status) {\n+\t\tvsi_ctx->vsis_allocd = LE16_TO_CPU(resp->vsi_used);\n+\t\tvsi_ctx->vsis_unallocated = LE16_TO_CPU(resp->vsi_free);\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_is_vsi_valid - check whether the VSI is valid or not\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * check whether the VSI is valid or not\n+ */\n+bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\treturn vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];\n+}\n+\n+/**\n+ * ice_get_hw_vsi_num - return the hw VSI number\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * return the hw VSI number\n+ * Caution: call this function only if VSI is valid (ice_is_vsi_valid)\n+ */\n+u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\treturn hw->vsi_ctx[vsi_handle]->vsi_num;\n+}\n+\n+/**\n+ * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * return the VSI context entry for a given VSI handle\n+ */\n+struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\treturn (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];\n+}\n+\n+/**\n+ * ice_save_vsi_ctx - save the VSI context for a given VSI handle\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ * @vsi: VSI context pointer\n+ *\n+ * save the VSI context entry for a given VSI handle\n+ */\n+static void\n+ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi)\n+{\n+\thw->vsi_ctx[vsi_handle] = vsi;\n+}\n+\n+/**\n+ * ice_clear_vsi_ctx - clear the VSI context entry\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * clear the VSI context entry\n+ */\n+static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\tstruct ice_vsi_ctx *vsi;\n+\n+\tvsi = ice_get_vsi_ctx(hw, vsi_handle);\n+\tif (vsi) {\n+\t\tice_destroy_lock(&vsi->rss_locks);\n+\t\tice_free(hw, vsi);\n+\t\thw->vsi_ctx[vsi_handle] = NULL;\n+\t}\n+}\n+\n+/**\n+ * ice_clear_all_vsi_ctx - clear all the VSI context entries\n+ * @hw: pointer to the hw struct\n+ */\n+void ice_clear_all_vsi_ctx(struct ice_hw *hw)\n+{\n+\tu16 i;\n+\n+\tfor (i = 0; i < ICE_MAX_VSI; i++)\n+\t\tice_clear_vsi_ctx(hw, i);\n+}\n+\n+/**\n+ * ice_add_vsi - add VSI context to the hardware and VSI handle list\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: unique VSI handle provided by drivers\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Add a VSI context to the hardware also add it into the VSI handle list.\n+ * If this function gets called after reset for exisiting VSIs then update\n+ * with the new HW VSI number in the corresponding VSI handle list entry.\n+ */\n+enum ice_status\n+ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t    struct ice_sq_cd *cd)\n+{\n+\tstruct ice_vsi_ctx *tmp_vsi_ctx;\n+\tenum ice_status status;\n+\n+\tif (vsi_handle >= ICE_MAX_VSI)\n+\t\treturn ICE_ERR_PARAM;\n+\tstatus = ice_aq_add_vsi(hw, vsi_ctx, cd);\n+\tif (status)\n+\t\treturn status;\n+\ttmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);\n+\tif (!tmp_vsi_ctx) {\n+\t\t/* Create a new vsi context */\n+\t\ttmp_vsi_ctx = (struct ice_vsi_ctx *)\n+\t\t\tice_malloc(hw, sizeof(*tmp_vsi_ctx));\n+\t\tif (!tmp_vsi_ctx) {\n+\t\t\tice_aq_free_vsi(hw, vsi_ctx, false, cd);\n+\t\t\treturn ICE_ERR_NO_MEMORY;\n+\t\t}\n+\t\t*tmp_vsi_ctx = *vsi_ctx;\n+\t\tice_init_lock(&tmp_vsi_ctx->rss_locks);\n+\t\tINIT_LIST_HEAD(&tmp_vsi_ctx->rss_list_head);\n+\t\tice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);\n+\t} else {\n+\t\t/* update with new HW VSI num */\n+\t\tif (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num)\n+\t\t\ttmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_free_vsi- free VSI context from hardware and VSI handle list\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: unique VSI handle\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Free VSI context info from hardware as well as from VSI handle list\n+ */\n+enum ice_status\n+ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t     bool keep_vsi_alloc, struct ice_sq_cd *cd)\n+{\n+\tenum ice_status status;\n+\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\tvsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);\n+\tstatus = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);\n+\tif (!status)\n+\t\tice_clear_vsi_ctx(hw, vsi_handle);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_update_vsi\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: unique VSI handle\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Update VSI context in the hardware\n+ */\n+enum ice_status\n+ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t       struct ice_sq_cd *cd)\n+{\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\tvsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);\n+\treturn ice_aq_update_vsi(hw, vsi_ctx, cd);\n+}\n+\n+\n+\n+/**\n+ * ice_aq_alloc_free_vsi_list\n+ * @hw: pointer to the hw struct\n+ * @vsi_list_id: VSI list id returned or used for lookup\n+ * @lkup_type: switch rule filter lookup type\n+ * @opc: switch rules population command type - pass in the command opcode\n+ *\n+ * allocates or free a VSI list resource\n+ */\n+static enum ice_status\n+ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,\n+\t\t\t   enum ice_sw_lkup_type lkup_type,\n+\t\t\t   enum ice_adminq_opc opc)\n+{\n+\tstruct ice_aqc_alloc_free_res_elem *sw_buf;\n+\tstruct ice_aqc_res_elem *vsi_ele;\n+\tenum ice_status status;\n+\tu16 buf_len;\n+\n+\tbuf_len = sizeof(*sw_buf);\n+\tsw_buf = (struct ice_aqc_alloc_free_res_elem *)\n+\t\tice_malloc(hw, buf_len);\n+\tif (!sw_buf)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\tsw_buf->num_elems = CPU_TO_LE16(1);\n+\n+\tif (lkup_type == ICE_SW_LKUP_MAC ||\n+\t    lkup_type == ICE_SW_LKUP_MAC_VLAN ||\n+\t    lkup_type == ICE_SW_LKUP_ETHERTYPE ||\n+\t    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||\n+\t    lkup_type == ICE_SW_LKUP_PROMISC ||\n+\t    lkup_type == ICE_SW_LKUP_PROMISC_VLAN) {\n+\t\tsw_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_VSI_LIST_REP);\n+\t} else if (lkup_type == ICE_SW_LKUP_VLAN) {\n+\t\tsw_buf->res_type =\n+\t\t\tCPU_TO_LE16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);\n+\t} else {\n+\t\tstatus = ICE_ERR_PARAM;\n+\t\tgoto ice_aq_alloc_free_vsi_list_exit;\n+\t}\n+\n+\tif (opc == ice_aqc_opc_free_res)\n+\t\tsw_buf->elem[0].e.sw_resp = CPU_TO_LE16(*vsi_list_id);\n+\n+\tstatus = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL);\n+\tif (status)\n+\t\tgoto ice_aq_alloc_free_vsi_list_exit;\n+\n+\tif (opc == ice_aqc_opc_alloc_res) {\n+\t\tvsi_ele = &sw_buf->elem[0];\n+\t\t*vsi_list_id = LE16_TO_CPU(vsi_ele->e.sw_resp);\n+\t}\n+\n+ice_aq_alloc_free_vsi_list_exit:\n+\tice_free(hw, sw_buf);\n+\treturn status;\n+}\n+\n+\n+/**\n+ * ice_aq_sw_rules - add/update/remove switch rules\n+ * @hw: pointer to the hw struct\n+ * @rule_list: pointer to switch rule population list\n+ * @rule_list_sz: total size of the rule list in bytes\n+ * @num_rules: number of switch rules in the rule_list\n+ * @opc: switch rules population command type - pass in the command opcode\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware\n+ */\n+static enum ice_status\n+ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,\n+\t\tu8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aq_desc desc;\n+\n+\tice_debug(hw, ICE_DBG_TRACE, \"ice_aq_sw_rules\");\n+\n+\tif (opc != ice_aqc_opc_add_sw_rules &&\n+\t    opc != ice_aqc_opc_update_sw_rules &&\n+\t    opc != ice_aqc_opc_remove_sw_rules)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tice_fill_dflt_direct_cmd_desc(&desc, opc);\n+\n+\tdesc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);\n+\tdesc.params.sw_rules.num_rules_fltr_entry_index =\n+\t\tCPU_TO_LE16(num_rules);\n+\treturn ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd);\n+}\n+\n+\n+/* ice_init_port_info - Initialize port_info with switch configuration data\n+ * @pi: pointer to port_info\n+ * @vsi_port_num: VSI number or port number\n+ * @type: Type of switch element (port or VSI)\n+ * @swid: switch ID of the switch the element is attached to\n+ * @pf_vf_num: PF or VF number\n+ * @is_vf: true if the element is a VF, false otherwise\n+ */\n+static void\n+ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type,\n+\t\t   u16 swid, u16 pf_vf_num, bool is_vf)\n+{\n+\tswitch (type) {\n+\tcase ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:\n+\t\tpi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK);\n+\t\tpi->sw_id = swid;\n+\t\tpi->pf_vf_num = pf_vf_num;\n+\t\tpi->is_vf = is_vf;\n+\t\tpi->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;\n+\t\tpi->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;\n+\t\tbreak;\n+\tdefault:\n+\t\tice_debug(pi->hw, ICE_DBG_SW,\n+\t\t\t  \"incorrect VSI/port type received\\n\");\n+\t\tbreak;\n+\t}\n+}\n+\n+/* ice_get_initial_sw_cfg - Get initial port and default VSI data\n+ * @hw: pointer to the hardware structure\n+ */\n+enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw)\n+{\n+\tstruct ice_aqc_get_sw_cfg_resp *rbuf;\n+\tenum ice_status status;\n+\tu16 num_total_ports;\n+\tu16 req_desc = 0;\n+\tu16 num_elems;\n+\tu16 j = 0;\n+\tu16 i;\n+\n+\tnum_total_ports = 1;\n+\n+\trbuf = (struct ice_aqc_get_sw_cfg_resp *)\n+\t\tice_malloc(hw, ICE_SW_CFG_MAX_BUF_LEN);\n+\n+\tif (!rbuf)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t/* Multiple calls to ice_aq_get_sw_cfg may be required\n+\t * to get all the switch configuration information. The need\n+\t * for additional calls is indicated by ice_aq_get_sw_cfg\n+\t * writing a non-zero value in req_desc\n+\t */\n+\tdo {\n+\t\tstatus = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN,\n+\t\t\t\t\t   &req_desc, &num_elems, NULL);\n+\n+\t\tif (status)\n+\t\t\tbreak;\n+\n+\t\tfor (i = 0; i < num_elems; i++) {\n+\t\t\tstruct ice_aqc_get_sw_cfg_resp_elem *ele;\n+\t\t\tu16 pf_vf_num, swid, vsi_port_num;\n+\t\t\tbool is_vf = false;\n+\t\t\tu8 type;\n+\n+\t\t\tele = rbuf[i].elements;\n+\t\t\tvsi_port_num = LE16_TO_CPU(ele->vsi_port_num) &\n+\t\t\t\tICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M;\n+\n+\t\t\tpf_vf_num = LE16_TO_CPU(ele->pf_vf_num) &\n+\t\t\t\tICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M;\n+\n+\t\t\tswid = LE16_TO_CPU(ele->swid);\n+\n+\t\t\tif (LE16_TO_CPU(ele->pf_vf_num) &\n+\t\t\t    ICE_AQC_GET_SW_CONF_RESP_IS_VF)\n+\t\t\t\tis_vf = true;\n+\n+\t\t\ttype = LE16_TO_CPU(ele->vsi_port_num) >>\n+\t\t\t\tICE_AQC_GET_SW_CONF_RESP_TYPE_S;\n+\n+\t\t\tswitch (type) {\n+\t\t\tcase ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:\n+\t\t\tcase ICE_AQC_GET_SW_CONF_RESP_VIRT_PORT:\n+\t\t\t\tif (j == num_total_ports) {\n+\t\t\t\t\tice_debug(hw, ICE_DBG_SW,\n+\t\t\t\t\t\t  \"more ports than expected\\n\");\n+\t\t\t\t\tstatus = ICE_ERR_CFG;\n+\t\t\t\t\tgoto out;\n+\t\t\t\t}\n+\t\t\t\tice_init_port_info(hw->port_info,\n+\t\t\t\t\t\t   vsi_port_num, type, swid,\n+\t\t\t\t\t\t   pf_vf_num, is_vf);\n+\t\t\t\tj++;\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t} while (req_desc && !status);\n+\n+\n+out:\n+\tice_free(hw, (void *)rbuf);\n+\treturn status;\n+}\n+\n+\n+/**\n+ * ice_fill_sw_info - Helper function to populate lb_en and lan_en\n+ * @hw: pointer to the hardware structure\n+ * @fi: filter info structure to fill/update\n+ *\n+ * This helper function populates the lb_en and lan_en elements of the provided\n+ * ice_fltr_info struct using the switch's type and characteristics of the\n+ * switch rule being configured.\n+ */\n+static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)\n+{\n+\tfi->lb_en = false;\n+\tfi->lan_en = false;\n+\tif ((fi->flag & ICE_FLTR_TX) &&\n+\t    (fi->fltr_act == ICE_FWD_TO_VSI ||\n+\t     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||\n+\t     fi->fltr_act == ICE_FWD_TO_Q ||\n+\t     fi->fltr_act == ICE_FWD_TO_QGRP)) {\n+\t\t/* Setting LB for prune actions will result in replicated\n+\t\t * packets to the internal switch that will be dropped.\n+\t\t */\n+\t\tif (fi->lkup_type != ICE_SW_LKUP_VLAN)\n+\t\t\tfi->lb_en = true;\n+\n+\t\t/* Set lan_en to TRUE if\n+\t\t * 1. The switch is a VEB AND\n+\t\t * 2\n+\t\t * 2.1 The lookup is a directional lookup like ethertype,\n+\t\t * promiscuous, ethertype-mac, promiscuous-vlan\n+\t\t * and default-port OR\n+\t\t * 2.2 The lookup is VLAN, OR\n+\t\t * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR\n+\t\t * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC.\n+\t\t *\n+\t\t * OR\n+\t\t *\n+\t\t * The switch is a VEPA.\n+\t\t *\n+\t\t * In all other cases, the LAN enable has to be set to false.\n+\t\t */\n+\t\tif (hw->evb_veb) {\n+\t\t\tif (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE ||\n+\t\t\t    fi->lkup_type == ICE_SW_LKUP_PROMISC ||\n+\t\t\t    fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||\n+\t\t\t    fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||\n+\t\t\t    fi->lkup_type == ICE_SW_LKUP_DFLT ||\n+\t\t\t    fi->lkup_type == ICE_SW_LKUP_VLAN ||\n+\t\t\t    (fi->lkup_type == ICE_SW_LKUP_MAC &&\n+\t\t\t     !IS_UNICAST_ETHER_ADDR(fi->l_data.mac.mac_addr)) ||\n+\t\t\t    (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN &&\n+\t\t\t     !IS_UNICAST_ETHER_ADDR(fi->l_data.mac.mac_addr)))\n+\t\t\t\tfi->lan_en = true;\n+\t\t} else {\n+\t\t\tfi->lan_en = true;\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * ice_ilog2 - Caculates integer log base 2 of a number\n+ * @n: number on which to perform operation\n+ */\n+static int ice_ilog2(u64 n)\n+{\n+\tint i;\n+\n+\tfor (i = 63; i >= 0; i--)\n+\t\tif (((u64)1 << i) & n)\n+\t\t\treturn i;\n+\n+\treturn -1;\n+}\n+\n+\n+/**\n+ * ice_fill_sw_rule - Helper function to fill switch rule structure\n+ * @hw: pointer to the hardware structure\n+ * @f_info: entry containing packet forwarding information\n+ * @s_rule: switch rule structure to be filled in based on mac_entry\n+ * @opc: switch rules population command type - pass in the command opcode\n+ */\n+static void\n+ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,\n+\t\t struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc)\n+{\n+\tu16 vlan_id = ICE_MAX_VLAN_ID + 1;\n+\tvoid *daddr = NULL;\n+\tu16 eth_hdr_sz;\n+\tu8 *eth_hdr;\n+\tu32 act = 0;\n+\t__be16 *off;\n+\tu8 q_rgn;\n+\n+\n+\tif (opc == ice_aqc_opc_remove_sw_rules) {\n+\t\ts_rule->pdata.lkup_tx_rx.act = 0;\n+\t\ts_rule->pdata.lkup_tx_rx.index =\n+\t\t\tCPU_TO_LE16(f_info->fltr_rule_id);\n+\t\ts_rule->pdata.lkup_tx_rx.hdr_len = 0;\n+\t\treturn;\n+\t}\n+\n+\teth_hdr_sz = sizeof(dummy_eth_header);\n+\teth_hdr = s_rule->pdata.lkup_tx_rx.hdr;\n+\n+\t/* initialize the ether header with a dummy header */\n+\tice_memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz, ICE_NONDMA_TO_NONDMA);\n+\tice_fill_sw_info(hw, f_info);\n+\n+\tswitch (f_info->fltr_act) {\n+\tcase ICE_FWD_TO_VSI:\n+\t\tact |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &\n+\t\t\tICE_SINGLE_ACT_VSI_ID_M;\n+\t\tif (f_info->lkup_type != ICE_SW_LKUP_VLAN)\n+\t\t\tact |= ICE_SINGLE_ACT_VSI_FORWARDING |\n+\t\t\t\tICE_SINGLE_ACT_VALID_BIT;\n+\t\tbreak;\n+\tcase ICE_FWD_TO_VSI_LIST:\n+\t\tact |= ICE_SINGLE_ACT_VSI_LIST;\n+\t\tact |= (f_info->fwd_id.vsi_list_id <<\n+\t\t\tICE_SINGLE_ACT_VSI_LIST_ID_S) &\n+\t\t\tICE_SINGLE_ACT_VSI_LIST_ID_M;\n+\t\tif (f_info->lkup_type != ICE_SW_LKUP_VLAN)\n+\t\t\tact |= ICE_SINGLE_ACT_VSI_FORWARDING |\n+\t\t\t\tICE_SINGLE_ACT_VALID_BIT;\n+\t\tbreak;\n+\tcase ICE_FWD_TO_Q:\n+\t\tact |= ICE_SINGLE_ACT_TO_Q;\n+\t\tact |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &\n+\t\t\tICE_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\tICE_SINGLE_ACT_VALID_BIT;\n+\t\tbreak;\n+\tcase ICE_FWD_TO_QGRP:\n+\t\tq_rgn = f_info->qgrp_size > 0 ?\n+\t\t\t(u8)ice_ilog2(f_info->qgrp_size) : 0;\n+\t\tact |= ICE_SINGLE_ACT_TO_Q;\n+\t\tact |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &\n+\t\t\tICE_SINGLE_ACT_Q_INDEX_M;\n+\t\tact |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &\n+\t\t\tICE_SINGLE_ACT_Q_REGION_M;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn;\n+\t}\n+\n+\tif (f_info->lb_en)\n+\t\tact |= ICE_SINGLE_ACT_LB_ENABLE;\n+\tif (f_info->lan_en)\n+\t\tact |= ICE_SINGLE_ACT_LAN_ENABLE;\n+\n+\tswitch (f_info->lkup_type) {\n+\tcase ICE_SW_LKUP_MAC:\n+\t\tdaddr = f_info->l_data.mac.mac_addr;\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_VLAN:\n+\t\tvlan_id = f_info->l_data.vlan.vlan_id;\n+\t\tif (f_info->fltr_act == ICE_FWD_TO_VSI ||\n+\t\t    f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {\n+\t\t\tact |= ICE_SINGLE_ACT_PRUNE;\n+\t\t\tact |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS;\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_ETHERTYPE_MAC:\n+\t\tdaddr = f_info->l_data.ethertype_mac.mac_addr;\n+\t\t/* fall-through */\n+\tcase ICE_SW_LKUP_ETHERTYPE:\n+\t\toff = (__be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);\n+\t\t*off = CPU_TO_BE16(f_info->l_data.ethertype_mac.ethertype);\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_MAC_VLAN:\n+\t\tdaddr = f_info->l_data.mac_vlan.mac_addr;\n+\t\tvlan_id = f_info->l_data.mac_vlan.vlan_id;\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_PROMISC_VLAN:\n+\t\tvlan_id = f_info->l_data.mac_vlan.vlan_id;\n+\t\t/* fall-through */\n+\tcase ICE_SW_LKUP_PROMISC:\n+\t\tdaddr = f_info->l_data.mac_vlan.mac_addr;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\ts_rule->type = (f_info->flag & ICE_FLTR_RX) ?\n+\t\tCPU_TO_LE16(ICE_AQC_SW_RULES_T_LKUP_RX) :\n+\t\tCPU_TO_LE16(ICE_AQC_SW_RULES_T_LKUP_TX);\n+\n+\t/* Recipe set depending on lookup type */\n+\ts_rule->pdata.lkup_tx_rx.recipe_id = CPU_TO_LE16(f_info->lkup_type);\n+\ts_rule->pdata.lkup_tx_rx.src = CPU_TO_LE16(f_info->src);\n+\ts_rule->pdata.lkup_tx_rx.act = CPU_TO_LE32(act);\n+\n+\tif (daddr)\n+\t\tice_memcpy(eth_hdr + ICE_ETH_DA_OFFSET, daddr, ETH_ALEN,\n+\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\n+\tif (!(vlan_id > ICE_MAX_VLAN_ID)) {\n+\t\toff = (__be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);\n+\t\t*off = CPU_TO_BE16(vlan_id);\n+\t}\n+\n+\t/* Create the switch rule with the final dummy Ethernet header */\n+\tif (opc != ice_aqc_opc_update_sw_rules)\n+\t\ts_rule->pdata.lkup_tx_rx.hdr_len = CPU_TO_LE16(eth_hdr_sz);\n+}\n+\n+/**\n+ * ice_add_marker_act\n+ * @hw: pointer to the hardware structure\n+ * @m_ent: the management entry for which sw marker needs to be added\n+ * @sw_marker: sw marker to tag the Rx descriptor with\n+ * @l_id: large action resource id\n+ *\n+ * Create a large action to hold software marker and update the switch rule\n+ * entry pointed by m_ent with newly created large action\n+ */\n+static enum ice_status\n+ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,\n+\t\t   u16 sw_marker, u16 l_id)\n+{\n+\tstruct ice_aqc_sw_rules_elem *lg_act, *rx_tx;\n+\t/* For software marker we need 3 large actions\n+\t * 1. FWD action: FWD TO VSI or VSI LIST\n+\t * 2. GENERIC VALUE action to hold the profile id\n+\t * 3. GENERIC VALUE action to hold the software marker id\n+\t */\n+\tconst u16 num_lg_acts = 3;\n+\tenum ice_status status;\n+\tu16 lg_act_size;\n+\tu16 rules_size;\n+\tu32 act;\n+\tu16 id;\n+\n+\tif (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\t/* Create two back-to-back switch rules and submit them to the HW using\n+\t * one memory buffer:\n+\t *    1. Large Action\n+\t *    2. Look up Tx Rx\n+\t */\n+\tlg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(num_lg_acts);\n+\trules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;\n+\tlg_act = (struct ice_aqc_sw_rules_elem *)ice_malloc(hw, rules_size);\n+\tif (!lg_act)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\trx_tx = (struct ice_aqc_sw_rules_elem *)((u8 *)lg_act + lg_act_size);\n+\n+\t/* Fill in the first switch rule i.e. large action */\n+\tlg_act->type = CPU_TO_LE16(ICE_AQC_SW_RULES_T_LG_ACT);\n+\tlg_act->pdata.lg_act.index = CPU_TO_LE16(l_id);\n+\tlg_act->pdata.lg_act.size = CPU_TO_LE16(num_lg_acts);\n+\n+\t/* First action VSI forwarding or VSI list forwarding depending on how\n+\t * many VSIs\n+\t */\n+\tid = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id :\n+\t\tm_ent->fltr_info.fwd_id.hw_vsi_id;\n+\n+\tact = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;\n+\tact |= (id << ICE_LG_ACT_VSI_LIST_ID_S) &\n+\t\tICE_LG_ACT_VSI_LIST_ID_M;\n+\tif (m_ent->vsi_count > 1)\n+\t\tact |= ICE_LG_ACT_VSI_LIST;\n+\tlg_act->pdata.lg_act.act[0] = CPU_TO_LE32(act);\n+\n+\t/* Second action descriptor type */\n+\tact = ICE_LG_ACT_GENERIC;\n+\n+\tact |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;\n+\tlg_act->pdata.lg_act.act[1] = CPU_TO_LE32(act);\n+\n+\tact = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<\n+\t       ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;\n+\n+\t/* Third action Marker value */\n+\tact |= ICE_LG_ACT_GENERIC;\n+\tact |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &\n+\t\tICE_LG_ACT_GENERIC_VALUE_M;\n+\n+\tlg_act->pdata.lg_act.act[2] = CPU_TO_LE32(act);\n+\n+\t/* call the fill switch rule to fill the lookup Tx Rx structure */\n+\tice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx,\n+\t\t\t ice_aqc_opc_update_sw_rules);\n+\n+\t/* Update the action to point to the large action id */\n+\trx_tx->pdata.lkup_tx_rx.act =\n+\t\tCPU_TO_LE32(ICE_SINGLE_ACT_PTR |\n+\t\t\t    ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &\n+\t\t\t     ICE_SINGLE_ACT_PTR_VAL_M));\n+\n+\t/* Use the filter rule id of the previously created rule with single\n+\t * act. Once the update happens, hardware will treat this as large\n+\t * action\n+\t */\n+\trx_tx->pdata.lkup_tx_rx.index =\n+\t\tCPU_TO_LE16(m_ent->fltr_info.fltr_rule_id);\n+\n+\tstatus = ice_aq_sw_rules(hw, lg_act, rules_size, 2,\n+\t\t\t\t ice_aqc_opc_update_sw_rules, NULL);\n+\tif (!status) {\n+\t\tm_ent->lg_act_idx = l_id;\n+\t\tm_ent->sw_marker_id = sw_marker;\n+\t}\n+\n+\tice_free(hw, lg_act);\n+\treturn status;\n+}\n+\n+\n+/**\n+ * ice_create_vsi_list_map\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle_arr: array of VSI handles to set in the VSI mapping\n+ * @num_vsi: number of VSI handles in the array\n+ * @vsi_list_id: VSI list id generated as part of allocate resource\n+ *\n+ * Helper function to create a new entry of VSI list id to VSI mapping\n+ * using the given VSI list id\n+ */\n+static struct ice_vsi_list_map_info *\n+ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,\n+\t\t\tu16 vsi_list_id)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_vsi_list_map_info *v_map;\n+\tint i;\n+\n+\tv_map = (struct ice_vsi_list_map_info *)ice_calloc(hw, 1,\n+\t\tsizeof(*v_map));\n+\tif (!v_map)\n+\t\treturn NULL;\n+\n+\tv_map->vsi_list_id = vsi_list_id;\n+\tv_map->ref_cnt = 1;\n+\tfor (i = 0; i < num_vsi; i++)\n+\t\tice_set_bit(vsi_handle_arr[i], v_map->vsi_map);\n+\n+\tLIST_ADD(&v_map->list_entry, &sw->vsi_list_map_head);\n+\treturn v_map;\n+}\n+\n+/**\n+ * ice_update_vsi_list_rule\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle_arr: array of VSI handles to form a VSI list\n+ * @num_vsi: number of VSI handles in the array\n+ * @vsi_list_id: VSI list id generated as part of allocate resource\n+ * @remove: Boolean value to indicate if this is a remove action\n+ * @opc: switch rules population command type - pass in the command opcode\n+ * @lkup_type: lookup type of the filter\n+ *\n+ * Call AQ command to add a new switch rule or update existing switch rule\n+ * using the given VSI list id\n+ */\n+static enum ice_status\n+ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,\n+\t\t\t u16 vsi_list_id, bool remove, enum ice_adminq_opc opc,\n+\t\t\t enum ice_sw_lkup_type lkup_type)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\tenum ice_status status;\n+\tu16 s_rule_size;\n+\tu16 type;\n+\tint i;\n+\n+\tif (!num_vsi)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tif (lkup_type == ICE_SW_LKUP_MAC ||\n+\t    lkup_type == ICE_SW_LKUP_MAC_VLAN ||\n+\t    lkup_type == ICE_SW_LKUP_ETHERTYPE ||\n+\t    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||\n+\t    lkup_type == ICE_SW_LKUP_PROMISC ||\n+\t    lkup_type == ICE_SW_LKUP_PROMISC_VLAN)\n+\t\ttype = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR :\n+\t\t\t\tICE_AQC_SW_RULES_T_VSI_LIST_SET;\n+\telse if (lkup_type == ICE_SW_LKUP_VLAN)\n+\t\ttype = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR :\n+\t\t\t\tICE_AQC_SW_RULES_T_PRUNE_LIST_SET;\n+\telse\n+\t\treturn ICE_ERR_PARAM;\n+\n+\ts_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(num_vsi);\n+\ts_rule = (struct ice_aqc_sw_rules_elem *)ice_malloc(hw, s_rule_size);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\tfor (i = 0; i < num_vsi; i++) {\n+\t\tif (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) {\n+\t\t\tstatus = ICE_ERR_PARAM;\n+\t\t\tgoto exit;\n+\t\t}\n+\t\t/* AQ call requires hw_vsi_id(s) */\n+\t\ts_rule->pdata.vsi_list.vsi[i] =\n+\t\t\tCPU_TO_LE16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i]));\n+\t}\n+\n+\ts_rule->type = CPU_TO_LE16(type);\n+\ts_rule->pdata.vsi_list.number_vsi = CPU_TO_LE16(num_vsi);\n+\ts_rule->pdata.vsi_list.index = CPU_TO_LE16(vsi_list_id);\n+\n+\tstatus = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL);\n+\n+exit:\n+\tice_free(hw, s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_create_vsi_list_rule - Creates and populates a VSI list rule\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle_arr: array of VSI handles to form a VSI list\n+ * @num_vsi: number of VSI handles in the array\n+ * @vsi_list_id: stores the ID of the VSI list to be created\n+ * @lkup_type: switch rule filter's lookup type\n+ */\n+static enum ice_status\n+ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,\n+\t\t\t u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type)\n+{\n+\tenum ice_status status;\n+\n+\tstatus = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type,\n+\t\t\t\t\t    ice_aqc_opc_alloc_res);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* Update the newly created VSI list to include the specified VSIs */\n+\treturn ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi,\n+\t\t\t\t\t*vsi_list_id, false,\n+\t\t\t\t\tice_aqc_opc_add_sw_rules, lkup_type);\n+}\n+\n+/**\n+ * ice_create_pkt_fwd_rule\n+ * @hw: pointer to the hardware structure\n+ * @f_entry: entry containing packet forwarding information\n+ *\n+ * Create switch rule with given filter information and add an entry\n+ * to the corresponding filter management list to track this switch rule\n+ * and VSI mapping\n+ */\n+static enum ice_status\n+ice_create_pkt_fwd_rule(struct ice_hw *hw,\n+\t\t\tstruct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *fm_entry;\n+\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\tenum ice_sw_lkup_type l_type;\n+\tstruct ice_sw_recipe *recp;\n+\tenum ice_status status;\n+\n+\ts_rule = (struct ice_aqc_sw_rules_elem *)\n+\t\tice_malloc(hw, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\tfm_entry = (struct ice_fltr_mgmt_list_entry *)\n+\t\t   ice_malloc(hw, sizeof(*fm_entry));\n+\tif (!fm_entry) {\n+\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\tgoto ice_create_pkt_fwd_rule_exit;\n+\t}\n+\n+\tfm_entry->fltr_info = f_entry->fltr_info;\n+\n+\t/* Initialize all the fields for the management entry */\n+\tfm_entry->vsi_count = 1;\n+\tfm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX;\n+\tfm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID;\n+\tfm_entry->counter_index = ICE_INVAL_COUNTER_ID;\n+\n+\tice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule,\n+\t\t\t ice_aqc_opc_add_sw_rules);\n+\n+\tstatus = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,\n+\t\t\t\t ice_aqc_opc_add_sw_rules, NULL);\n+\tif (status) {\n+\t\tice_free(hw, fm_entry);\n+\t\tgoto ice_create_pkt_fwd_rule_exit;\n+\t}\n+\n+\tf_entry->fltr_info.fltr_rule_id =\n+\t\tLE16_TO_CPU(s_rule->pdata.lkup_tx_rx.index);\n+\tfm_entry->fltr_info.fltr_rule_id =\n+\t\tLE16_TO_CPU(s_rule->pdata.lkup_tx_rx.index);\n+\n+\t/* The book keeping entries will get removed when base driver\n+\t * calls remove filter AQ command\n+\t */\n+\tl_type = fm_entry->fltr_info.lkup_type;\n+\trecp = &hw->switch_info->recp_list[l_type];\n+\tLIST_ADD(&fm_entry->list_entry, &recp->filt_rules);\n+\n+ice_create_pkt_fwd_rule_exit:\n+\tice_free(hw, s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_update_pkt_fwd_rule\n+ * @hw: pointer to the hardware structure\n+ * @f_info: filter information for switch rule\n+ *\n+ * Call AQ command to update a previously created switch rule with a\n+ * VSI list id\n+ */\n+static enum ice_status\n+ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\tenum ice_status status;\n+\n+\ts_rule = (struct ice_aqc_sw_rules_elem *)\n+\t\tice_malloc(hw, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules);\n+\n+\ts_rule->pdata.lkup_tx_rx.index = CPU_TO_LE16(f_info->fltr_rule_id);\n+\n+\t/* Update switch rule with new rule set to forward VSI list */\n+\tstatus = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,\n+\t\t\t\t ice_aqc_opc_update_sw_rules, NULL);\n+\n+\tice_free(hw, s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_update_sw_rule_bridge_mode\n+ * @hw: pointer to the hw struct\n+ *\n+ * Updates unicast switch filter rules based on VEB/VEPA mode\n+ */\n+enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_mgmt_list_entry *fm_entry;\n+\tenum ice_status status = ICE_SUCCESS;\n+\tstruct LIST_HEAD_TYPE *rule_head;\n+\tstruct ice_lock *rule_lock; /* Lock to protect filter rule list */\n+\n+\trule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;\n+\trule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;\n+\n+\tice_acquire_lock(rule_lock);\n+\tLIST_FOR_EACH_ENTRY(fm_entry, rule_head, ice_fltr_mgmt_list_entry,\n+\t\t\t    list_entry) {\n+\t\tstruct ice_fltr_info *fi = &fm_entry->fltr_info;\n+\t\tu8 *addr = fi->l_data.mac.mac_addr;\n+\n+\t\t/* Update unicast Tx rules to reflect the selected\n+\t\t * VEB/VEPA mode\n+\t\t */\n+\t\tif ((fi->flag & ICE_FLTR_TX) && IS_UNICAST_ETHER_ADDR(addr) &&\n+\t\t    (fi->fltr_act == ICE_FWD_TO_VSI ||\n+\t\t     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||\n+\t\t     fi->fltr_act == ICE_FWD_TO_Q ||\n+\t\t     fi->fltr_act == ICE_FWD_TO_QGRP)) {\n+\t\t\tstatus = ice_update_pkt_fwd_rule(hw, fi);\n+\t\t\tif (status)\n+\t\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tice_release_lock(rule_lock);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_add_update_vsi_list\n+ * @hw: pointer to the hardware structure\n+ * @m_entry: pointer to current 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 book keeping is described below :\n+ * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.)\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_add_update_vsi_list(struct ice_hw *hw,\n+\t\t\tstruct ice_fltr_mgmt_list_entry *m_entry,\n+\t\t\tstruct ice_fltr_info *cur_fltr,\n+\t\t\tstruct ice_fltr_info *new_fltr)\n+{\n+\tenum ice_status status = ICE_SUCCESS;\n+\tu16 vsi_list_id = 0;\n+\n+\tif ((cur_fltr->fltr_act == ICE_FWD_TO_Q ||\n+\t     cur_fltr->fltr_act == ICE_FWD_TO_QGRP))\n+\t\treturn ICE_ERR_NOT_IMPL;\n+\n+\tif ((new_fltr->fltr_act == ICE_FWD_TO_Q ||\n+\t     new_fltr->fltr_act == ICE_FWD_TO_QGRP) &&\n+\t    (cur_fltr->fltr_act == ICE_FWD_TO_VSI ||\n+\t     cur_fltr->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->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id)\n+\t\t\treturn ICE_ERR_ALREADY_EXISTS;\n+\n+\t\tvsi_handle_arr[0] = cur_fltr->vsi_handle;\n+\t\tvsi_handle_arr[1] = new_fltr->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  new_fltr->lkup_type);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\ttmp_fltr = *new_fltr;\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 \"MAC forward to VSI\" to\n+\t\t * \"MAC 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->fwd_id.vsi_list_id = vsi_list_id;\n+\t\tcur_fltr->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+\n+\t\t/* If this entry was large action then the large action needs\n+\t\t * to be updated to point to FWD to VSI list\n+\t\t */\n+\t\tif (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID)\n+\t\t\tstatus =\n+\t\t\t    ice_add_marker_act(hw, m_entry,\n+\t\t\t\t\t       m_entry->sw_marker_id,\n+\t\t\t\t\t       m_entry->lg_act_idx);\n+\t} else {\n+\t\tu16 vsi_handle = new_fltr->vsi_handle;\n+\t\tenum ice_adminq_opc opcode;\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->fwd_id.vsi_list_id;\n+\t\topcode = ice_aqc_opc_update_sw_rules;\n+\n+\t\tstatus = ice_update_vsi_list_rule(hw, &vsi_handle, 1,\n+\t\t\t\t\t\t  vsi_list_id, false, opcode,\n+\t\t\t\t\t\t  new_fltr->lkup_type);\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_find_rule_entry - Search a rule entry\n+ * @hw: pointer to the hardware structure\n+ * @recp_id: lookup type for which the specified rule needs to be searched\n+ * @f_info: rule information\n+ *\n+ * Helper function to search for a given rule entry\n+ * Returns pointer to entry storing the rule if found\n+ */\n+static struct ice_fltr_mgmt_list_entry *\n+ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL;\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct LIST_HEAD_TYPE *list_head;\n+\n+\tlist_head = &sw->recp_list[recp_id].filt_rules;\n+\tLIST_FOR_EACH_ENTRY(list_itr, list_head, ice_fltr_mgmt_list_entry,\n+\t\t\t    list_entry) {\n+\t\tif (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,\n+\t\t\t    sizeof(f_info->l_data)) &&\n+\t\t    f_info->flag == list_itr->fltr_info.flag) {\n+\t\t\tret = list_itr;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_find_vsi_list_entry - Search VSI list map with VSI count 1\n+ * @hw: pointer to the hardware structure\n+ * @recp_id: lookup type for which VSI lists needs to be searched\n+ * @vsi_handle: VSI handle to be found in VSI list\n+ * @vsi_list_id: VSI list id found contaning vsi_handle\n+ *\n+ * Helper function to search a VSI list with single entry containing given VSI\n+ * handle element. This can be extended further to search VSI list with more\n+ * than 1 vsi_count. Returns pointer to VSI list entry if found.\n+ */\n+static struct ice_vsi_list_map_info *\n+ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,\n+\t\t\tu16 *vsi_list_id)\n+{\n+\tstruct ice_vsi_list_map_info *map_info = NULL;\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_mgmt_list_entry *list_itr;\n+\tstruct LIST_HEAD_TYPE *list_head;\n+\n+\tlist_head = &sw->recp_list[recp_id].filt_rules;\n+\tLIST_FOR_EACH_ENTRY(list_itr, list_head, ice_fltr_mgmt_list_entry,\n+\t\t\t    list_entry) {\n+\t\tif (list_itr->vsi_count == 1 && list_itr->vsi_list_info) {\n+\t\t\tmap_info = list_itr->vsi_list_info;\n+\t\t\tif (ice_is_bit_set(map_info->vsi_map, vsi_handle)) {\n+\t\t\t\t*vsi_list_id = map_info->vsi_list_id;\n+\t\t\t\treturn map_info;\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn NULL;\n+}\n+\n+/**\n+ * ice_add_rule_internal - add rule for a given lookup type\n+ * @hw: pointer to the hardware structure\n+ * @recp_id: lookup type (recipe id) for which rule has to be added\n+ * @f_entry: structure containing MAC forwarding information\n+ *\n+ * Adds or updates the rule lists for a given recipe\n+ */\n+static enum ice_status\n+ice_add_rule_internal(struct ice_hw *hw, u8 recp_id,\n+\t\t      struct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_info *new_fltr, *cur_fltr;\n+\tstruct ice_fltr_mgmt_list_entry *m_entry;\n+\tstruct ice_lock *rule_lock; /* Lock to protect filter rule list */\n+\tenum ice_status status = ICE_SUCCESS;\n+\n+\tif (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\t/* Load the hw_vsi_id only if the fwd action is fwd to VSI */\n+\tif (f_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI)\n+\t\tf_entry->fltr_info.fwd_id.hw_vsi_id =\n+\t\t\tice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);\n+\n+\trule_lock = &sw->recp_list[recp_id].filt_rule_lock;\n+\n+\tice_acquire_lock(rule_lock);\n+\tnew_fltr = &f_entry->fltr_info;\n+\tif (new_fltr->flag & ICE_FLTR_RX)\n+\t\tnew_fltr->src = hw->port_info->lport;\n+\telse if (new_fltr->flag & ICE_FLTR_TX)\n+\t\tnew_fltr->src =\n+\t\t\tice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);\n+\n+\tm_entry = ice_find_rule_entry(hw, recp_id, new_fltr);\n+\tif (!m_entry) {\n+\t\tice_release_lock(rule_lock);\n+\t\treturn ice_create_pkt_fwd_rule(hw, f_entry);\n+\t}\n+\n+\tcur_fltr = &m_entry->fltr_info;\n+\tstatus = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr);\n+\tice_release_lock(rule_lock);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_remove_vsi_list_rule\n+ * @hw: pointer to the hardware structure\n+ * @vsi_list_id: VSI list id generated as part of allocate resource\n+ * @lkup_type: switch rule filter lookup type\n+ *\n+ * The VSI list should be emptied before this function is called to remove the\n+ * VSI list.\n+ */\n+static enum ice_status\n+ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,\n+\t\t\t enum ice_sw_lkup_type lkup_type)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\tenum ice_status status;\n+\tu16 s_rule_size;\n+\n+\ts_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0);\n+\ts_rule = (struct ice_aqc_sw_rules_elem *)ice_malloc(hw, s_rule_size);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\ts_rule->type = CPU_TO_LE16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR);\n+\ts_rule->pdata.vsi_list.index = CPU_TO_LE16(vsi_list_id);\n+\n+\t/* Free the vsi_list resource that we allocated. It is assumed that the\n+\t * list is empty at this point.\n+\t */\n+\tstatus = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,\n+\t\t\t\t\t    ice_aqc_opc_free_res);\n+\n+\tice_free(hw, s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_rem_update_vsi_list\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle of the VSI to remove\n+ * @fm_list: filter management entry for which the VSI list management needs to\n+ *\t     be done\n+ */\n+static enum ice_status\n+ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,\n+\t\t\tstruct ice_fltr_mgmt_list_entry *fm_list)\n+{\n+\tenum ice_sw_lkup_type lkup_type;\n+\tenum ice_status status = ICE_SUCCESS;\n+\tu16 vsi_list_id;\n+\n+\tif (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST ||\n+\t    fm_list->vsi_count == 0)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\t/* A rule with the VSI being removed does not exist */\n+\tif (!ice_is_bit_set(fm_list->vsi_list_info->vsi_map, vsi_handle))\n+\t\treturn ICE_ERR_DOES_NOT_EXIST;\n+\n+\tlkup_type = fm_list->fltr_info.lkup_type;\n+\tvsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id;\n+\tstatus = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,\n+\t\t\t\t\t  ice_aqc_opc_update_sw_rules,\n+\t\t\t\t\t  lkup_type);\n+\tif (status)\n+\t\treturn status;\n+\n+\tfm_list->vsi_count--;\n+\tice_clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);\n+\n+\tif (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) {\n+\t\tstruct ice_fltr_info tmp_fltr_info = fm_list->fltr_info;\n+\t\tstruct ice_vsi_list_map_info *vsi_list_info =\n+\t\t\tfm_list->vsi_list_info;\n+\t\tu16 rem_vsi_handle;\n+\n+\t\trem_vsi_handle = ice_find_first_bit(vsi_list_info->vsi_map,\n+\t\t\t\t\t\t    ICE_MAX_VSI);\n+\t\tif (!ice_is_vsi_valid(hw, rem_vsi_handle))\n+\t\t\treturn ICE_ERR_OUT_OF_RANGE;\n+\n+\t\t/* Make sure VSI list is empty before removing it below */\n+\t\tstatus = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,\n+\t\t\t\t\t\t  vsi_list_id, true,\n+\t\t\t\t\t\t  ice_aqc_opc_update_sw_rules,\n+\t\t\t\t\t\t  lkup_type);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\ttmp_fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\t\ttmp_fltr_info.fwd_id.hw_vsi_id =\n+\t\t\tice_get_hw_vsi_num(hw, rem_vsi_handle);\n+\t\ttmp_fltr_info.vsi_handle = rem_vsi_handle;\n+\t\tstatus = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info);\n+\t\tif (status) {\n+\t\t\tice_debug(hw, ICE_DBG_SW,\n+\t\t\t\t  \"Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\\n\",\n+\t\t\t\t  tmp_fltr_info.fwd_id.hw_vsi_id, status);\n+\t\t\treturn status;\n+\t\t}\n+\n+\t\tfm_list->fltr_info = tmp_fltr_info;\n+\t}\n+\n+\tif ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) ||\n+\t    (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) {\n+\t\tstruct ice_vsi_list_map_info *vsi_list_info =\n+\t\t\tfm_list->vsi_list_info;\n+\n+\t\t/* Remove the VSI list since it is no longer used */\n+\t\tstatus = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);\n+\t\tif (status) {\n+\t\t\tice_debug(hw, ICE_DBG_SW,\n+\t\t\t\t  \"Failed to remove VSI list %d, error %d\\n\",\n+\t\t\t\t  vsi_list_id, status);\n+\t\t\treturn status;\n+\t\t}\n+\n+\t\tLIST_DEL(&vsi_list_info->list_entry);\n+\t\tice_free(hw, vsi_list_info);\n+\t\tfm_list->vsi_list_info = NULL;\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_remove_rule_internal - Remove a filter rule of a given type\n+ *\n+ * @hw: pointer to the hardware structure\n+ * @recp_id: recipe id for which the rule needs to removed\n+ * @f_entry: rule entry containing filter information\n+ */\n+static enum ice_status\n+ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id,\n+\t\t\t struct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_mgmt_list_entry *list_elem;\n+\tstruct ice_lock *rule_lock; /* Lock to protect filter rule list */\n+\tenum ice_status status = ICE_SUCCESS;\n+\tbool remove_rule = false;\n+\tu16 vsi_handle;\n+\n+\tif (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\tf_entry->fltr_info.fwd_id.hw_vsi_id =\n+\t\tice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);\n+\n+\trule_lock = &sw->recp_list[recp_id].filt_rule_lock;\n+\tice_acquire_lock(rule_lock);\n+\tlist_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info);\n+\tif (!list_elem) {\n+\t\tstatus = ICE_ERR_DOES_NOT_EXIST;\n+\t\tgoto exit;\n+\t}\n+\n+\tif (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {\n+\t\tremove_rule = true;\n+\t} else if (!list_elem->vsi_list_info) {\n+\t\tstatus = ICE_ERR_DOES_NOT_EXIST;\n+\t\tgoto exit;\n+\t} else if (list_elem->vsi_list_info->ref_cnt > 1) {\n+\t\t/* a ref_cnt > 1 indicates that the vsi_list is being\n+\t\t * shared by multiple rules. Decrement the ref_cnt and\n+\t\t * remove this rule, but do not modify the list, as it\n+\t\t * is in-use by other rules.\n+\t\t */\n+\t\tlist_elem->vsi_list_info->ref_cnt--;\n+\t\tremove_rule = true;\n+\t} else {\n+\t\t/* a ref_cnt of 1 indicates the vsi_list is only used\n+\t\t * by one rule. However, the original removal request is only\n+\t\t * for a single VSI. Update the vsi_list first, and only\n+\t\t * remove the rule if there are no further VSIs in this list.\n+\t\t */\n+\t\tvsi_handle = f_entry->fltr_info.vsi_handle;\n+\t\tstatus = ice_rem_update_vsi_list(hw, vsi_handle, list_elem);\n+\t\tif (status)\n+\t\t\tgoto exit;\n+\t\t/* if vsi count goes to zero after updating the vsi list */\n+\t\tif (list_elem->vsi_count == 0)\n+\t\t\tremove_rule = true;\n+\t}\n+\n+\tif (remove_rule) {\n+\t\t/* Remove the lookup rule */\n+\t\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\n+\t\ts_rule = (struct ice_aqc_sw_rules_elem *)\n+\t\t\tice_malloc(hw, ICE_SW_RULE_RX_TX_NO_HDR_SIZE);\n+\t\tif (!s_rule) {\n+\t\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\tice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule,\n+\t\t\t\t ice_aqc_opc_remove_sw_rules);\n+\n+\t\tstatus = ice_aq_sw_rules(hw, s_rule,\n+\t\t\t\t\t ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1,\n+\t\t\t\t\t ice_aqc_opc_remove_sw_rules, NULL);\n+\t\tif (status)\n+\t\t\tgoto exit;\n+\n+\t\t/* Remove a book keeping from the list */\n+\t\tice_free(hw, s_rule);\n+\n+\t\tLIST_DEL(&list_elem->list_entry);\n+\t\tice_free(hw, list_elem);\n+\t}\n+exit:\n+\tice_release_lock(rule_lock);\n+\treturn status;\n+}\n+\n+\n+/**\n+ * ice_add_mac - Add a MAC address based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @m_list: list of MAC addresses and forwarding information\n+ *\n+ * IMPORTANT: When the ucast_shared flag is set to false and m_list has\n+ * multiple unicast addresses, the function assumes that all the\n+ * addresses are unique in a given add_mac call. It doesn't\n+ * check for duplicates in this case, removing duplicates from a given\n+ * list should be taken care of in the caller of this function.\n+ */\n+enum ice_status\n+ice_add_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule, *r_iter;\n+\tstruct ice_fltr_list_entry *m_list_itr;\n+\tstruct LIST_HEAD_TYPE *rule_head;\n+\tu16 elem_sent, total_elem_left;\n+\tstruct ice_switch_info *sw;\n+\tstruct ice_lock *rule_lock; /* Lock to protect filter rule list */\n+\tenum ice_status status = ICE_SUCCESS;\n+\tu16 num_unicast = 0;\n+\tu16 s_rule_size;\n+\n+\tif (!m_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\ts_rule = NULL;\n+\tsw = hw->switch_info;\n+\trule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;\n+\tLIST_FOR_EACH_ENTRY(m_list_itr, m_list, ice_fltr_list_entry,\n+\t\t\t    list_entry) {\n+\t\tu8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];\n+\t\tu16 vsi_handle;\n+\t\tu16 hw_vsi_id;\n+\n+\t\tm_list_itr->fltr_info.flag = ICE_FLTR_TX;\n+\t\tvsi_handle = m_list_itr->fltr_info.vsi_handle;\n+\t\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\thw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);\n+\t\tm_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id;\n+\t\t/* update the src in case it is vsi num */\n+\t\tif (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI)\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tm_list_itr->fltr_info.src = hw_vsi_id;\n+\t\tif (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||\n+\t\t    IS_ZERO_ETHER_ADDR(add))\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tif (IS_UNICAST_ETHER_ADDR(add) && !hw->ucast_shared) {\n+\t\t\t/* Don't overwrite the unicast address */\n+\t\t\tice_acquire_lock(rule_lock);\n+\t\t\tif (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC,\n+\t\t\t\t\t\t&m_list_itr->fltr_info)) {\n+\t\t\t\tice_release_lock(rule_lock);\n+\t\t\t\treturn ICE_ERR_ALREADY_EXISTS;\n+\t\t\t}\n+\t\t\tice_release_lock(rule_lock);\n+\t\t\tnum_unicast++;\n+\t\t} else if (IS_MULTICAST_ETHER_ADDR(add) ||\n+\t\t\t   (IS_UNICAST_ETHER_ADDR(add) && hw->ucast_shared)) {\n+\t\t\tm_list_itr->status =\n+\t\t\t\tice_add_rule_internal(hw, ICE_SW_LKUP_MAC,\n+\t\t\t\t\t\t      m_list_itr);\n+\t\t\tif (m_list_itr->status)\n+\t\t\t\treturn m_list_itr->status;\n+\t\t}\n+\t}\n+\n+\tice_acquire_lock(rule_lock);\n+\t/* Exit if no suitable entries were found for adding bulk switch rule */\n+\tif (!num_unicast) {\n+\t\tstatus = ICE_SUCCESS;\n+\t\tgoto ice_add_mac_exit;\n+\t}\n+\n+\trule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;\n+\n+\t/* Allocate switch rule buffer for the bulk update for unicast */\n+\ts_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;\n+\ts_rule = (struct ice_aqc_sw_rules_elem *)\n+\t\tice_calloc(hw, num_unicast, s_rule_size);\n+\tif (!s_rule) {\n+\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\tgoto ice_add_mac_exit;\n+\t}\n+\n+\tr_iter = s_rule;\n+\tLIST_FOR_EACH_ENTRY(m_list_itr, m_list, ice_fltr_list_entry,\n+\t\t\t    list_entry) {\n+\t\tstruct ice_fltr_info *f_info = &m_list_itr->fltr_info;\n+\t\tu8 *mac_addr = &f_info->l_data.mac.mac_addr[0];\n+\n+\t\tif (IS_UNICAST_ETHER_ADDR(mac_addr)) {\n+\t\t\tice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter,\n+\t\t\t\t\t ice_aqc_opc_add_sw_rules);\n+\t\t\tr_iter = (struct ice_aqc_sw_rules_elem *)\n+\t\t\t\t((u8 *)r_iter + s_rule_size);\n+\t\t}\n+\t}\n+\n+\t/* Call AQ bulk switch rule update for all unicast addresses */\n+\tr_iter = s_rule;\n+\t/* Call AQ switch rule in AQ_MAX chunk */\n+\tfor (total_elem_left = num_unicast; total_elem_left > 0;\n+\t     total_elem_left -= elem_sent) {\n+\t\tstruct ice_aqc_sw_rules_elem *entry = r_iter;\n+\n+\t\telem_sent = min(total_elem_left,\n+\t\t\t\t(u16)(ICE_AQ_MAX_BUF_LEN / s_rule_size));\n+\t\tstatus = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size,\n+\t\t\t\t\t elem_sent, ice_aqc_opc_add_sw_rules,\n+\t\t\t\t\t NULL);\n+\t\tif (status)\n+\t\t\tgoto ice_add_mac_exit;\n+\t\tr_iter = (struct ice_aqc_sw_rules_elem *)\n+\t\t\t((u8 *)r_iter + (elem_sent * s_rule_size));\n+\t}\n+\n+\t/* Fill up rule id based on the value returned from FW */\n+\tr_iter = s_rule;\n+\tLIST_FOR_EACH_ENTRY(m_list_itr, m_list, ice_fltr_list_entry,\n+\t\t\t    list_entry) {\n+\t\tstruct ice_fltr_info *f_info = &m_list_itr->fltr_info;\n+\t\tu8 *mac_addr = &f_info->l_data.mac.mac_addr[0];\n+\t\tstruct ice_fltr_mgmt_list_entry *fm_entry;\n+\n+\t\tif (IS_UNICAST_ETHER_ADDR(mac_addr)) {\n+\t\t\tf_info->fltr_rule_id =\n+\t\t\t\tLE16_TO_CPU(r_iter->pdata.lkup_tx_rx.index);\n+\t\t\tf_info->fltr_act = ICE_FWD_TO_VSI;\n+\t\t\t/* Create an entry to track this MAC address */\n+\t\t\tfm_entry = (struct ice_fltr_mgmt_list_entry *)\n+\t\t\t\tice_malloc(hw, sizeof(*fm_entry));\n+\t\t\tif (!fm_entry) {\n+\t\t\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\t\t\tgoto ice_add_mac_exit;\n+\t\t\t}\n+\t\t\tfm_entry->fltr_info = *f_info;\n+\t\t\tfm_entry->vsi_count = 1;\n+\t\t\t/* The book keeping entries will get removed when\n+\t\t\t * base driver calls remove filter AQ command\n+\t\t\t */\n+\n+\t\t\tLIST_ADD(&fm_entry->list_entry, rule_head);\n+\t\t\tr_iter = (struct ice_aqc_sw_rules_elem *)\n+\t\t\t\t((u8 *)r_iter + s_rule_size);\n+\t\t}\n+\t}\n+\n+ice_add_mac_exit:\n+\tice_release_lock(rule_lock);\n+\tif (s_rule)\n+\t\tice_free(hw, s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_add_vlan_internal - Add one VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @f_entry: filter entry containing one VLAN information\n+ */\n+static enum ice_status\n+ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_mgmt_list_entry *v_list_itr;\n+\tstruct ice_fltr_info *new_fltr, *cur_fltr;\n+\tenum ice_sw_lkup_type lkup_type;\n+\tu16 vsi_list_id = 0, vsi_handle;\n+\tstruct ice_lock *rule_lock; /* Lock to protect filter rule list */\n+\tenum ice_status status = ICE_SUCCESS;\n+\n+\tif (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tf_entry->fltr_info.fwd_id.hw_vsi_id =\n+\t\tice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);\n+\tnew_fltr = &f_entry->fltr_info;\n+\n+\t/* VLAN id should only be 12 bits */\n+\tif (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tif (new_fltr->src_id != ICE_SRC_ID_VSI)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tnew_fltr->src = new_fltr->fwd_id.hw_vsi_id;\n+\tlkup_type = new_fltr->lkup_type;\n+\tvsi_handle = new_fltr->vsi_handle;\n+\trule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;\n+\tice_acquire_lock(rule_lock);\n+\tv_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr);\n+\tif (!v_list_itr) {\n+\t\tstruct ice_vsi_list_map_info *map_info = NULL;\n+\n+\t\tif (new_fltr->fltr_act == ICE_FWD_TO_VSI) {\n+\t\t\t/* All VLAN pruning rules use a VSI list. Check if\n+\t\t\t * there is already a VSI list containing VSI that we\n+\t\t\t * want to add. If found, use the same vsi_list_id for\n+\t\t\t * this new VLAN rule or else create a new list.\n+\t\t\t */\n+\t\t\tmap_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN,\n+\t\t\t\t\t\t\t   vsi_handle,\n+\t\t\t\t\t\t\t   &vsi_list_id);\n+\t\t\tif (!map_info) {\n+\t\t\t\tstatus = ice_create_vsi_list_rule(hw,\n+\t\t\t\t\t\t\t\t  &vsi_handle,\n+\t\t\t\t\t\t\t\t  1,\n+\t\t\t\t\t\t\t\t  &vsi_list_id,\n+\t\t\t\t\t\t\t\t  lkup_type);\n+\t\t\t\tif (status)\n+\t\t\t\t\tgoto exit;\n+\t\t\t}\n+\t\t\t/* Convert the action to forwarding to a VSI list. */\n+\t\t\tnew_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;\n+\t\t\tnew_fltr->fwd_id.vsi_list_id = vsi_list_id;\n+\t\t}\n+\n+\t\tstatus = ice_create_pkt_fwd_rule(hw, f_entry);\n+\t\tif (!status) {\n+\t\t\tv_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN,\n+\t\t\t\t\t\t\t new_fltr);\n+\t\t\tif (!v_list_itr) {\n+\t\t\t\tstatus = ICE_ERR_DOES_NOT_EXIST;\n+\t\t\t\tgoto exit;\n+\t\t\t}\n+\t\t\t/* reuse VSI list for new rule and increment ref_cnt */\n+\t\t\tif (map_info) {\n+\t\t\t\tv_list_itr->vsi_list_info = map_info;\n+\t\t\t\tmap_info->ref_cnt++;\n+\t\t\t} else {\n+\t\t\t\tv_list_itr->vsi_list_info =\n+\t\t\t\t\tice_create_vsi_list_map(hw, &vsi_handle,\n+\t\t\t\t\t\t\t\t1, vsi_list_id);\n+\t\t\t}\n+\t\t}\n+\t} else if (v_list_itr->vsi_list_info->ref_cnt == 1) {\n+\t\t/* Update existing VSI list to add new VSI id only if it used\n+\t\t * by one VLAN rule.\n+\t\t */\n+\t\tcur_fltr = &v_list_itr->fltr_info;\n+\t\tstatus = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr,\n+\t\t\t\t\t\t new_fltr);\n+\t} else {\n+\t\t/* If VLAN rule exists and VSI list being used by this rule is\n+\t\t * referenced by more than 1 VLAN rule. Then create a new VSI\n+\t\t * list appending previous VSI with new VSI and update existing\n+\t\t * VLAN rule to point to new VSI list id\n+\t\t */\n+\t\tstruct ice_fltr_info tmp_fltr;\n+\t\tu16 vsi_handle_arr[2];\n+\t\tu16 cur_handle;\n+\n+\t\t/* Current implementation only supports reusing VSI list with\n+\t\t * one VSI count. We should never hit below condition\n+\t\t */\n+\t\tif (v_list_itr->vsi_count > 1 &&\n+\t\t    v_list_itr->vsi_list_info->ref_cnt > 1) {\n+\t\t\tice_debug(hw, ICE_DBG_SW,\n+\t\t\t\t  \"Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\\n\");\n+\t\t\tstatus = ICE_ERR_CFG;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\tcur_handle =\n+\t\t\tice_find_first_bit(v_list_itr->vsi_list_info->vsi_map,\n+\t\t\t\t\t   ICE_MAX_VSI);\n+\n+\t\t/* A rule already exists with the new VSI being added */\n+\t\tif (cur_handle == vsi_handle) {\n+\t\t\tstatus = ICE_ERR_ALREADY_EXISTS;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\tvsi_handle_arr[0] = cur_handle;\n+\t\tvsi_handle_arr[1] = 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, lkup_type);\n+\t\tif (status)\n+\t\t\tgoto exit;\n+\n+\t\ttmp_fltr = v_list_itr->fltr_info;\n+\t\ttmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id;\n+\t\ttmp_fltr.fwd_id.vsi_list_id = vsi_list_id;\n+\t\ttmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;\n+\t\t/* Update the previous switch rule to a new VSI list which\n+\t\t * includes current VSI that is requested\n+\t\t */\n+\t\tstatus = ice_update_pkt_fwd_rule(hw, &tmp_fltr);\n+\t\tif (status)\n+\t\t\tgoto exit;\n+\n+\t\t/* before overriding VSI list map info. decrement ref_cnt of\n+\t\t * previous VSI list\n+\t\t */\n+\t\tv_list_itr->vsi_list_info->ref_cnt--;\n+\n+\t\t/* now update to newly created list */\n+\t\tv_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id;\n+\t\tv_list_itr->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\tv_list_itr->vsi_count++;\n+\t}\n+\n+exit:\n+\tice_release_lock(rule_lock);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_add_vlan - Add VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @v_list: list of VLAN entries and forwarding information\n+ */\n+enum ice_status\n+ice_add_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list)\n+{\n+\tstruct ice_fltr_list_entry *v_list_itr;\n+\n+\tif (!v_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tLIST_FOR_EACH_ENTRY(v_list_itr, v_list, ice_fltr_list_entry,\n+\t\t\t    list_entry) {\n+\t\tif (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tv_list_itr->fltr_info.flag = ICE_FLTR_TX;\n+\t\tv_list_itr->status = ice_add_vlan_internal(hw, v_list_itr);\n+\t\tif (v_list_itr->status)\n+\t\t\treturn v_list_itr->status;\n+\t}\n+\treturn ICE_SUCCESS;\n+}\n+\n+#ifndef NO_MACVLAN_SUPPORT\n+/**\n+ * ice_add_mac_vlan - Add MAC and VLAN pair based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @mv_list: list of MAC and VLAN filters\n+ *\n+ * If the VSI on which the mac-vlan pair has to be added has RX and Tx VLAN\n+ * pruning bits enabled, then it is the responsibility of the caller to make\n+ * sure to add a vlan only filter on the same VSI. Packets belonging to that\n+ * VLAN won't be received on that VSI otherwise.\n+ */\n+enum ice_status\n+ice_add_mac_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *mv_list)\n+{\n+\tstruct ice_fltr_list_entry *mv_list_itr;\n+\n+\tif (!mv_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tLIST_FOR_EACH_ENTRY(mv_list_itr, mv_list, ice_fltr_list_entry,\n+\t\t\t    list_entry) {\n+\t\tenum ice_sw_lkup_type l_type =\n+\t\t\tmv_list_itr->fltr_info.lkup_type;\n+\n+\t\tif (l_type != ICE_SW_LKUP_MAC_VLAN)\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tmv_list_itr->fltr_info.flag = ICE_FLTR_TX;\n+\t\tmv_list_itr->status =\n+\t\t\tice_add_rule_internal(hw, ICE_SW_LKUP_MAC_VLAN,\n+\t\t\t\t\t      mv_list_itr);\n+\t\tif (mv_list_itr->status)\n+\t\t\treturn mv_list_itr->status;\n+\t}\n+\treturn ICE_SUCCESS;\n+}\n+#endif\n+\n+\n+\n+/**\n+ * ice_rem_sw_rule_info\n+ * @hw: pointer to the hardware structure\n+ * @rule_head: pointer to the switch list structure that we want to delete\n+ */\n+static void\n+ice_rem_sw_rule_info(struct ice_hw *hw, struct LIST_HEAD_TYPE *rule_head)\n+{\n+\tif (!LIST_EMPTY(rule_head)) {\n+\t\tstruct ice_fltr_mgmt_list_entry *entry;\n+\t\tstruct ice_fltr_mgmt_list_entry *tmp;\n+\n+\t\tLIST_FOR_EACH_ENTRY_SAFE(entry, tmp, rule_head,\n+\t\t\t\t\t ice_fltr_mgmt_list_entry, list_entry) {\n+\t\t\tLIST_DEL(&entry->list_entry);\n+\t\t\tice_free(hw, entry);\n+\t\t}\n+\t}\n+}\n+\n+\n+\n+/**\n+ * ice_cfg_dflt_vsi - change state of VSI to set/clear default\n+ * @pi: pointer to the port_info structure\n+ * @vsi_handle: VSI handle to set as default\n+ * @set: true to add the above mentioned switch rule, false to remove it\n+ * @direction: ICE_FLTR_RX or ICE_FLTR_TX\n+ *\n+ * add filter rule to set/unset given VSI as default VSI for the switch\n+ * (represented by swid)\n+ */\n+enum ice_status\n+ice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set,\n+\t\t u8 direction)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\tstruct ice_fltr_info f_info;\n+\tstruct ice_hw *hw = pi->hw;\n+\tenum ice_adminq_opc opcode;\n+\tenum ice_status status;\n+\tu16 s_rule_size;\n+\tu16 hw_vsi_id;\n+\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\thw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);\n+\n+\ts_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE :\n+\t\t\t    ICE_SW_RULE_RX_TX_NO_HDR_SIZE;\n+\ts_rule = (struct ice_aqc_sw_rules_elem *)ice_malloc(hw, s_rule_size);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tice_memset(&f_info, 0, sizeof(f_info), ICE_NONDMA_MEM);\n+\n+\tf_info.lkup_type = ICE_SW_LKUP_DFLT;\n+\tf_info.flag = direction;\n+\tf_info.fltr_act = ICE_FWD_TO_VSI;\n+\tf_info.fwd_id.hw_vsi_id = hw_vsi_id;\n+\n+\tif (f_info.flag & ICE_FLTR_RX) {\n+\t\tf_info.src = pi->lport;\n+\t\tf_info.src_id = ICE_SRC_ID_LPORT;\n+\t\tif (!set)\n+\t\t\tf_info.fltr_rule_id =\n+\t\t\t\tpi->dflt_rx_vsi_rule_id;\n+\t} else if (f_info.flag & ICE_FLTR_TX) {\n+\t\tf_info.src_id = ICE_SRC_ID_VSI;\n+\t\tf_info.src = hw_vsi_id;\n+\t\tif (!set)\n+\t\t\tf_info.fltr_rule_id =\n+\t\t\t\tpi->dflt_tx_vsi_rule_id;\n+\t}\n+\n+\tif (set)\n+\t\topcode = ice_aqc_opc_add_sw_rules;\n+\telse\n+\t\topcode = ice_aqc_opc_remove_sw_rules;\n+\n+\tice_fill_sw_rule(hw, &f_info, s_rule, opcode);\n+\n+\tstatus = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opcode, NULL);\n+\tif (status || !(f_info.flag & ICE_FLTR_TX_RX))\n+\t\tgoto out;\n+\tif (set) {\n+\t\tu16 index = LE16_TO_CPU(s_rule->pdata.lkup_tx_rx.index);\n+\n+\t\tif (f_info.flag & ICE_FLTR_TX) {\n+\t\t\tpi->dflt_tx_vsi_num = hw_vsi_id;\n+\t\t\tpi->dflt_tx_vsi_rule_id = index;\n+\t\t} else if (f_info.flag & ICE_FLTR_RX) {\n+\t\t\tpi->dflt_rx_vsi_num = hw_vsi_id;\n+\t\t\tpi->dflt_rx_vsi_rule_id = index;\n+\t\t}\n+\t} else {\n+\t\tif (f_info.flag & ICE_FLTR_TX) {\n+\t\t\tpi->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;\n+\t\t\tpi->dflt_tx_vsi_rule_id = ICE_INVAL_ACT;\n+\t\t} else if (f_info.flag & ICE_FLTR_RX) {\n+\t\t\tpi->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;\n+\t\t\tpi->dflt_rx_vsi_rule_id = ICE_INVAL_ACT;\n+\t\t}\n+\t}\n+\n+out:\n+\tice_free(hw, s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_remove_mac - remove a MAC address based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @m_list: list of MAC addresses and forwarding information\n+ *\n+ * This function removes either a MAC filter rule or a specific VSI from a\n+ * VSI list for a multicast MAC address.\n+ *\n+ * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by\n+ * ice_add_mac. Caller should be aware that this call will only work if all\n+ * the entries passed into m_list were added previously. It will not attempt to\n+ * do a partial remove of entries that were found.\n+ */\n+enum ice_status\n+ice_remove_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list)\n+{\n+\tstruct ice_fltr_list_entry *list_itr, *tmp;\n+\n+\tif (!m_list)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tLIST_FOR_EACH_ENTRY_SAFE(list_itr, tmp, m_list, ice_fltr_list_entry,\n+\t\t\t\t list_entry) {\n+\t\tenum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;\n+\n+\t\tif (l_type != ICE_SW_LKUP_MAC)\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tlist_itr->status = ice_remove_rule_internal(hw,\n+\t\t\t\t\t\t\t    ICE_SW_LKUP_MAC,\n+\t\t\t\t\t\t\t    list_itr);\n+\t\tif (list_itr->status)\n+\t\t\treturn list_itr->status;\n+\t}\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_remove_vlan - Remove VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @v_list: list of VLAN entries and forwarding information\n+ */\n+enum ice_status\n+ice_remove_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list)\n+{\n+\tstruct ice_fltr_list_entry *v_list_itr, *tmp;\n+\n+\tif (!v_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tLIST_FOR_EACH_ENTRY_SAFE(v_list_itr, tmp, v_list, ice_fltr_list_entry,\n+\t\t\t\t list_entry) {\n+\t\tenum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;\n+\n+\t\tif (l_type != ICE_SW_LKUP_VLAN)\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tv_list_itr->status = ice_remove_rule_internal(hw,\n+\t\t\t\t\t\t\t      ICE_SW_LKUP_VLAN,\n+\t\t\t\t\t\t\t      v_list_itr);\n+\t\tif (v_list_itr->status)\n+\t\t\treturn v_list_itr->status;\n+\t}\n+\treturn ICE_SUCCESS;\n+}\n+\n+#ifndef NO_MACVLAN_SUPPORT\n+/**\n+ * ice_remove_mac_vlan - Remove MAC VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @v_list: list of MAC VLAN entries and forwarding information\n+ */\n+enum ice_status\n+ice_remove_mac_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list)\n+{\n+\tstruct ice_fltr_list_entry *v_list_itr, *tmp;\n+\n+\tif (!v_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tLIST_FOR_EACH_ENTRY_SAFE(v_list_itr, tmp, v_list, ice_fltr_list_entry,\n+\t\t\t\t list_entry) {\n+\t\tenum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;\n+\n+\t\tif (l_type != ICE_SW_LKUP_MAC_VLAN)\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tv_list_itr->status =\n+\t\t\tice_remove_rule_internal(hw, ICE_SW_LKUP_MAC_VLAN,\n+\t\t\t\t\t\t v_list_itr);\n+\t\tif (v_list_itr->status)\n+\t\t\treturn v_list_itr->status;\n+\t}\n+\treturn ICE_SUCCESS;\n+}\n+#endif /* !NO_MACVLAN_SUPPORT */\n+\n+/**\n+ * ice_vsi_uses_fltr - Determine if given VSI uses specified filter\n+ * @fm_entry: filter entry to inspect\n+ * @vsi_handle: VSI handle to compare with filter info\n+ */\n+static bool\n+ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle)\n+{\n+\treturn ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&\n+\t\t fm_entry->fltr_info.vsi_handle == vsi_handle) ||\n+\t\t(fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&\n+\t\t (ice_is_bit_set(fm_entry->vsi_list_info->vsi_map,\n+\t\t\t\t vsi_handle))));\n+}\n+\n+/**\n+ * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle to remove filters from\n+ * @vsi_list_head: pointer to the list to add entry to\n+ * @fi: pointer to fltr_info of filter entry to copy & add\n+ *\n+ * Helper function, used when creating a list of filters to remove from\n+ * a specific VSI. The entry added to vsi_list_head is a COPY of the\n+ * original filter entry, with the exception of fltr_info.fltr_act and\n+ * fltr_info.fwd_id fields. These are set such that later logic can\n+ * extract which VSI to remove the fltr from, and pass on that information.\n+ */\n+static enum ice_status\n+ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,\n+\t\t\t       struct LIST_HEAD_TYPE *vsi_list_head,\n+\t\t\t       struct ice_fltr_info *fi)\n+{\n+\tstruct ice_fltr_list_entry *tmp;\n+\n+\t/* this memory is freed up in the caller function\n+\t * once filters for this VSI are removed\n+\t */\n+\ttmp = (struct ice_fltr_list_entry *)ice_malloc(hw, sizeof(*tmp));\n+\tif (!tmp)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\ttmp->fltr_info = *fi;\n+\n+\t/* Overwrite these fields to indicate which VSI to remove filter from,\n+\t * so find and remove logic can extract the information from the\n+\t * list entries. Note that original entries will still have proper\n+\t * values.\n+\t */\n+\ttmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\ttmp->fltr_info.vsi_handle = vsi_handle;\n+\ttmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);\n+\n+\tLIST_ADD(&tmp->list_entry, vsi_list_head);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_add_to_vsi_fltr_list - Add VSI filters to the list\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle to remove filters from\n+ * @lkup_list_head: pointer to the list that has certain lookup type filters\n+ * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle\n+ *\n+ * Locates all filters in lkup_list_head that are used by the given VSI,\n+ * and adds COPIES of those entries to vsi_list_head (intended to be used\n+ * to remove the listed filters).\n+ * Note that this means all entries in vsi_list_head must be explicitly\n+ * deallocated by the caller when done with list.\n+ */\n+static enum ice_status\n+ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,\n+\t\t\t struct LIST_HEAD_TYPE *lkup_list_head,\n+\t\t\t struct LIST_HEAD_TYPE *vsi_list_head)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *fm_entry;\n+\tenum ice_status status = ICE_SUCCESS;\n+\n+\t/* check to make sure VSI id is valid and within boundary */\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tLIST_FOR_EACH_ENTRY(fm_entry, lkup_list_head,\n+\t\t\t    ice_fltr_mgmt_list_entry, list_entry) {\n+\t\tstruct ice_fltr_info *fi;\n+\n+\t\tfi = &fm_entry->fltr_info;\n+\t\tif (!fi || !ice_vsi_uses_fltr(fm_entry, vsi_handle))\n+\t\t\tcontinue;\n+\n+\t\tstatus = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,\n+\t\t\t\t\t\t\tvsi_list_head, fi);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\treturn status;\n+}\n+\n+\n+/**\n+ * ice_determine_promisc_mask\n+ * @fi: filter info to parse\n+ *\n+ * Helper function to determine which ICE_PROMISC_ mask corresponds\n+ * to given filter into.\n+ */\n+static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi)\n+{\n+\tu16 vid = fi->l_data.mac_vlan.vlan_id;\n+\tu8 *macaddr = fi->l_data.mac.mac_addr;\n+\tbool is_tx_fltr = false;\n+\tu8 promisc_mask = 0;\n+\n+\tif (fi->flag == ICE_FLTR_TX)\n+\t\tis_tx_fltr = true;\n+\n+\tif (IS_BROADCAST_ETHER_ADDR(macaddr))\n+\t\tpromisc_mask |= is_tx_fltr ?\n+\t\t\tICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX;\n+\telse if (IS_MULTICAST_ETHER_ADDR(macaddr))\n+\t\tpromisc_mask |= is_tx_fltr ?\n+\t\t\tICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX;\n+\telse if (IS_UNICAST_ETHER_ADDR(macaddr))\n+\t\tpromisc_mask |= is_tx_fltr ?\n+\t\t\tICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX;\n+\tif (vid)\n+\t\tpromisc_mask |= is_tx_fltr ?\n+\t\t\tICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX;\n+\n+\treturn promisc_mask;\n+}\n+\n+\n+/**\n+ * ice_remove_promisc - Remove promisc based filter rules\n+ * @hw: pointer to the hardware structure\n+ * @recp_id: recipe id for which the rule needs to removed\n+ * @v_list: list of promisc entries\n+ */\n+static enum ice_status\n+ice_remove_promisc(struct ice_hw *hw, u8 recp_id,\n+\t\t   struct LIST_HEAD_TYPE *v_list)\n+{\n+\tstruct ice_fltr_list_entry *v_list_itr, *tmp;\n+\n+\tLIST_FOR_EACH_ENTRY_SAFE(v_list_itr, tmp, v_list, ice_fltr_list_entry,\n+\t\t\t\t list_entry) {\n+\t\tv_list_itr->status =\n+\t\t\tice_remove_rule_internal(hw, recp_id, v_list_itr);\n+\t\tif (v_list_itr->status)\n+\t\t\treturn v_list_itr->status;\n+\t}\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle to clear mode\n+ * @promisc_mask: mask of promiscuous config bits to clear\n+ * @vid: VLAN ID to clear VLAN promiscuous\n+ */\n+enum ice_status\n+ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,\n+\t\t      u16 vid)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_list_entry *fm_entry, *tmp;\n+\tstruct LIST_HEAD_TYPE remove_list_head;\n+\tstruct ice_fltr_mgmt_list_entry *itr;\n+\tstruct LIST_HEAD_TYPE *rule_head;\n+\tstruct ice_lock *rule_lock;\t/* Lock to protect filter rule list */\n+\tenum ice_status status = ICE_SUCCESS;\n+\tu8 recipe_id;\n+\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tif (vid)\n+\t\trecipe_id = ICE_SW_LKUP_PROMISC_VLAN;\n+\telse\n+\t\trecipe_id = ICE_SW_LKUP_PROMISC;\n+\n+\trule_head = &sw->recp_list[recipe_id].filt_rules;\n+\trule_lock = &sw->recp_list[recipe_id].filt_rule_lock;\n+\n+\tINIT_LIST_HEAD(&remove_list_head);\n+\n+\tice_acquire_lock(rule_lock);\n+\tLIST_FOR_EACH_ENTRY(itr, rule_head,\n+\t\t\t    ice_fltr_mgmt_list_entry, list_entry) {\n+\t\tu8 fltr_promisc_mask = 0;\n+\n+\t\tif (!ice_vsi_uses_fltr(itr, vsi_handle))\n+\t\t\tcontinue;\n+\n+\t\tfltr_promisc_mask |=\n+\t\t\tice_determine_promisc_mask(&itr->fltr_info);\n+\n+\t\t/* Skip if filter is not completely specified by given mask */\n+\t\tif (fltr_promisc_mask & ~promisc_mask)\n+\t\t\tcontinue;\n+\n+\t\tstatus = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,\n+\t\t\t\t\t\t\t&remove_list_head,\n+\t\t\t\t\t\t\t&itr->fltr_info);\n+\t\tif (status) {\n+\t\t\tice_release_lock(rule_lock);\n+\t\t\tgoto free_fltr_list;\n+\t\t}\n+\t}\n+\tice_release_lock(rule_lock);\n+\n+\tstatus = ice_remove_promisc(hw, recipe_id, &remove_list_head);\n+\n+free_fltr_list:\n+\tLIST_FOR_EACH_ENTRY_SAFE(fm_entry, tmp, &remove_list_head,\n+\t\t\t\t ice_fltr_list_entry, list_entry) {\n+\t\tLIST_DEL(&fm_entry->list_entry);\n+\t\tice_free(hw, fm_entry);\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle to configure\n+ * @promisc_mask: mask of promiscuous config bits\n+ * @vid: VLAN ID to set VLAN promiscuous\n+ */\n+enum ice_status\n+ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid)\n+{\n+\tenum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR };\n+\tstruct ice_fltr_list_entry f_list_entry;\n+\tstruct ice_fltr_info new_fltr;\n+\tenum ice_status status = ICE_SUCCESS;\n+\tbool is_tx_fltr;\n+\tu16 hw_vsi_id;\n+\tint pkt_type;\n+\tu8 recipe_id;\n+\n+\tice_debug(hw, ICE_DBG_TRACE, \"ice_set_vsi_promisc\\n\");\n+\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\thw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);\n+\n+\tice_memset(&new_fltr, 0, sizeof(new_fltr), ICE_NONDMA_MEM);\n+\n+\tif (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) {\n+\t\tnew_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN;\n+\t\tnew_fltr.l_data.mac_vlan.vlan_id = vid;\n+\t\trecipe_id = ICE_SW_LKUP_PROMISC_VLAN;\n+\t} else {\n+\t\tnew_fltr.lkup_type = ICE_SW_LKUP_PROMISC;\n+\t\trecipe_id = ICE_SW_LKUP_PROMISC;\n+\t}\n+\n+\t/* Separate filters must be set for each direction/packet type\n+\t * combination, so we will loop over the mask value, store the\n+\t * individual type, and clear it out in the input mask as it\n+\t * is found.\n+\t */\n+\twhile (promisc_mask) {\n+\t\tu8 *mac_addr;\n+\n+\t\tpkt_type = 0;\n+\t\tis_tx_fltr = false;\n+\n+\t\tif (promisc_mask & ICE_PROMISC_UCAST_RX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_UCAST_RX;\n+\t\t\tpkt_type = UCAST_FLTR;\n+\t\t} else if (promisc_mask & ICE_PROMISC_UCAST_TX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_UCAST_TX;\n+\t\t\tpkt_type = UCAST_FLTR;\n+\t\t\tis_tx_fltr = true;\n+\t\t} else if (promisc_mask & ICE_PROMISC_MCAST_RX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_MCAST_RX;\n+\t\t\tpkt_type = MCAST_FLTR;\n+\t\t} else if (promisc_mask & ICE_PROMISC_MCAST_TX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_MCAST_TX;\n+\t\t\tpkt_type = MCAST_FLTR;\n+\t\t\tis_tx_fltr = true;\n+\t\t} else if (promisc_mask & ICE_PROMISC_BCAST_RX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_BCAST_RX;\n+\t\t\tpkt_type = BCAST_FLTR;\n+\t\t} else if (promisc_mask & ICE_PROMISC_BCAST_TX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_BCAST_TX;\n+\t\t\tpkt_type = BCAST_FLTR;\n+\t\t\tis_tx_fltr = true;\n+\t\t}\n+\n+\t\t/* Check for VLAN promiscuous flag */\n+\t\tif (promisc_mask & ICE_PROMISC_VLAN_RX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_VLAN_RX;\n+\t\t} else if (promisc_mask & ICE_PROMISC_VLAN_TX) {\n+\t\t\tpromisc_mask &= ~ICE_PROMISC_VLAN_TX;\n+\t\t\tis_tx_fltr = true;\n+\t\t}\n+\n+\t\t/* Set filter DA based on packet type */\n+\t\tmac_addr = new_fltr.l_data.mac.mac_addr;\n+\t\tif (pkt_type == BCAST_FLTR) {\n+\t\t\tice_memset(mac_addr, 0xff, ETH_ALEN, ICE_NONDMA_MEM);\n+\t\t} else if (pkt_type == MCAST_FLTR ||\n+\t\t\t   pkt_type == UCAST_FLTR) {\n+\t\t\t/* Use the dummy ether header DA */\n+\t\t\tice_memcpy(mac_addr, dummy_eth_header, ETH_ALEN,\n+\t\t\t\t   ICE_NONDMA_TO_NONDMA);\n+\t\t\tif (pkt_type == MCAST_FLTR)\n+\t\t\t\tmac_addr[0] |= 0x1;\t/* Set multicast bit */\n+\t\t}\n+\n+\t\t/* Need to reset this to zero for all iterations */\n+\t\tnew_fltr.flag = 0;\n+\t\tif (is_tx_fltr) {\n+\t\t\tnew_fltr.flag |= ICE_FLTR_TX;\n+\t\t\tnew_fltr.src = hw_vsi_id;\n+\t\t} else {\n+\t\t\tnew_fltr.flag |= ICE_FLTR_RX;\n+\t\t\tnew_fltr.src = hw->port_info->lport;\n+\t\t}\n+\n+\t\tnew_fltr.fltr_act = ICE_FWD_TO_VSI;\n+\t\tnew_fltr.vsi_handle = vsi_handle;\n+\t\tnew_fltr.fwd_id.hw_vsi_id = hw_vsi_id;\n+\t\tf_list_entry.fltr_info = new_fltr;\n+\n+\t\tstatus = ice_add_rule_internal(hw, recipe_id, &f_list_entry);\n+\t\tif (status != ICE_SUCCESS)\n+\t\t\tgoto set_promisc_exit;\n+\t}\n+\n+set_promisc_exit:\n+\treturn status;\n+}\n+\n+/**\n+ * ice_set_vlan_vsi_promisc\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle to configure\n+ * @promisc_mask: mask of promiscuous config bits\n+ * @rm_vlan_promisc: Clear VLANs VSI promisc mode\n+ *\n+ * Configure VSI with all associated VLANs to given promiscuous mode(s)\n+ */\n+enum ice_status\n+ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,\n+\t\t\t bool rm_vlan_promisc)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_list_entry *list_itr, *tmp;\n+\tstruct LIST_HEAD_TYPE vsi_list_head;\n+\tstruct LIST_HEAD_TYPE *vlan_head;\n+\tstruct ice_lock *vlan_lock; /* Lock to protect filter rule list */\n+\tenum ice_status status;\n+\tu16 vlan_id;\n+\n+\tINIT_LIST_HEAD(&vsi_list_head);\n+\tvlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;\n+\tvlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;\n+\tice_acquire_lock(vlan_lock);\n+\tstatus = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head,\n+\t\t\t\t\t  &vsi_list_head);\n+\tice_release_lock(vlan_lock);\n+\tif (status)\n+\t\tgoto free_fltr_list;\n+\n+\tLIST_FOR_EACH_ENTRY(list_itr, &vsi_list_head, ice_fltr_list_entry,\n+\t\t\t    list_entry) {\n+\t\tvlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;\n+\t\tif (rm_vlan_promisc)\n+\t\t\tstatus = ice_clear_vsi_promisc(hw, vsi_handle,\n+\t\t\t\t\t\t       promisc_mask, vlan_id);\n+\t\telse\n+\t\t\tstatus = ice_set_vsi_promisc(hw, vsi_handle,\n+\t\t\t\t\t\t     promisc_mask, vlan_id);\n+\t\tif (status)\n+\t\t\tbreak;\n+\t}\n+\n+free_fltr_list:\n+\tLIST_FOR_EACH_ENTRY_SAFE(list_itr, tmp, &vsi_list_head,\n+\t\t\t\t ice_fltr_list_entry, list_entry) {\n+\t\tLIST_DEL(&list_itr->list_entry);\n+\t\tice_free(hw, list_itr);\n+\t}\n+\treturn status;\n+}\n+\n+/**\n+ * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle to remove filters from\n+ * @lkup: switch rule filter lookup type\n+ */\n+static void\n+ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,\n+\t\t\t enum ice_sw_lkup_type lkup)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_list_entry *fm_entry;\n+\tstruct LIST_HEAD_TYPE remove_list_head;\n+\tstruct LIST_HEAD_TYPE *rule_head;\n+\tstruct ice_fltr_list_entry *tmp;\n+\tstruct ice_lock *rule_lock;\t/* Lock to protect filter rule list */\n+\tenum ice_status status;\n+\n+\tINIT_LIST_HEAD(&remove_list_head);\n+\trule_lock = &sw->recp_list[lkup].filt_rule_lock;\n+\trule_head = &sw->recp_list[lkup].filt_rules;\n+\tice_acquire_lock(rule_lock);\n+\tstatus = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head,\n+\t\t\t\t\t  &remove_list_head);\n+\tice_release_lock(rule_lock);\n+\tif (status)\n+\t\treturn;\n+\n+\tswitch (lkup) {\n+\tcase ICE_SW_LKUP_MAC:\n+\t\tice_remove_mac(hw, &remove_list_head);\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_VLAN:\n+\t\tice_remove_vlan(hw, &remove_list_head);\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_PROMISC:\n+\tcase ICE_SW_LKUP_PROMISC_VLAN:\n+\t\tice_remove_promisc(hw, lkup, &remove_list_head);\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_MAC_VLAN:\n+#ifndef NO_MACVLAN_SUPPORT\n+\t\tice_remove_mac_vlan(hw, &remove_list_head);\n+#else\n+\t\tice_debug(hw, ICE_DBG_SW, \"MAC VLAN look up is not supported yet\\n\");\n+#endif /* !NO_MACVLAN_SUPPORT */\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_ETHERTYPE:\n+\tcase ICE_SW_LKUP_ETHERTYPE_MAC:\n+\tcase ICE_SW_LKUP_DFLT:\n+\t\tice_debug(hw, ICE_DBG_SW,\n+\t\t\t  \"Remove filters for this lookup type hasn't been implemented yet\\n\");\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_LAST:\n+\t\tice_debug(hw, ICE_DBG_SW, \"Unsupported lookup type\\n\");\n+\t\tbreak;\n+\t}\n+\n+\tLIST_FOR_EACH_ENTRY_SAFE(fm_entry, tmp, &remove_list_head,\n+\t\t\t\t ice_fltr_list_entry, list_entry) {\n+\t\tLIST_DEL(&fm_entry->list_entry);\n+\t\tice_free(hw, fm_entry);\n+\t}\n+}\n+\n+/**\n+ * ice_remove_vsi_fltr - Remove all filters for a VSI\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: VSI handle to remove filters from\n+ */\n+void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\tice_debug(hw, ICE_DBG_TRACE, \"ice_remove_vsi_fltr\\n\");\n+\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN);\n+}\n+\n+\n+\n+\n+\n+/**\n+ * ice_replay_vsi_fltr - Replay filters for requested VSI\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: driver vsi handle\n+ * @recp_id: Recipe id for which rules need to be replayed\n+ * @list_head: list for which filters need to be replayed\n+ *\n+ * Replays the filter of recipe recp_id for a VSI represented via vsi_handle.\n+ * It is required to pass valid VSI handle.\n+ */\n+static enum ice_status\n+ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id,\n+\t\t    struct LIST_HEAD_TYPE *list_head)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *itr;\n+\tenum ice_status status = ICE_SUCCESS;\n+\tu16 hw_vsi_id;\n+\n+\tif (LIST_EMPTY(list_head))\n+\t\treturn status;\n+\thw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);\n+\n+\tLIST_FOR_EACH_ENTRY(itr, list_head, ice_fltr_mgmt_list_entry,\n+\t\t\t    list_entry) {\n+\t\tstruct ice_fltr_list_entry f_entry;\n+\n+\t\tf_entry.fltr_info = itr->fltr_info;\n+\t\tif (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN &&\n+\t\t    itr->fltr_info.vsi_handle == vsi_handle) {\n+\t\t\t/* update the src in case it is vsi num */\n+\t\t\tif (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)\n+\t\t\t\tf_entry.fltr_info.src = hw_vsi_id;\n+\t\t\tstatus = ice_add_rule_internal(hw, recp_id, &f_entry);\n+\t\t\tif (status != ICE_SUCCESS)\n+\t\t\t\tgoto end;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!itr->vsi_list_info ||\n+\t\t    !ice_is_bit_set(itr->vsi_list_info->vsi_map, vsi_handle))\n+\t\t\tcontinue;\n+\t\t/* Clearing it so that the logic can add it back */\n+\t\tice_clear_bit(vsi_handle, itr->vsi_list_info->vsi_map);\n+\t\tf_entry.fltr_info.vsi_handle = vsi_handle;\n+\t\tf_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\t\t/* update the src in case it is vsi num */\n+\t\tif (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)\n+\t\t\tf_entry.fltr_info.src = hw_vsi_id;\n+\t\tif (recp_id == ICE_SW_LKUP_VLAN)\n+\t\t\tstatus = ice_add_vlan_internal(hw, &f_entry);\n+\t\telse\n+\t\t\tstatus = ice_add_rule_internal(hw, recp_id, &f_entry);\n+\t\tif (status != ICE_SUCCESS)\n+\t\t\tgoto end;\n+\t}\n+end:\n+\treturn status;\n+}\n+\n+\n+/**\n+ * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists\n+ * @hw: pointer to the hardware structure\n+ * @vsi_handle: driver vsi handle\n+ *\n+ * Replays filters for requested VSI via vsi_handle.\n+ */\n+enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tenum ice_status status = ICE_SUCCESS;\n+\tu8 i;\n+\n+\tfor (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {\n+\t\t/* Update the default recipe lines and ones that were created */\n+\t\tif (i < ICE_MAX_NUM_RECIPES || sw->recp_list[i].recp_created) {\n+\t\t\tstruct LIST_HEAD_TYPE *head;\n+\n+\t\t\thead = &sw->recp_list[i].filt_replay_rules;\n+\t\t\tif (!sw->recp_list[i].adv_rule)\n+\t\t\t\tstatus = ice_replay_vsi_fltr(hw, vsi_handle, i,\n+\t\t\t\t\t\t\t     head);\n+\t\t\tif (status != ICE_SUCCESS)\n+\t\t\t\treturn status;\n+\t\t}\n+\t}\n+\treturn status;\n+}\n+\n+/**\n+ * ice_rm_all_sw_replay_rule_info - deletes filter replay rules\n+ * @hw: pointer to the hw struct\n+ *\n+ * Deletes the filter replay rules.\n+ */\n+void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tu8 i;\n+\n+\tif (!sw)\n+\t\treturn;\n+\n+\tfor (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {\n+\t\tif (!LIST_EMPTY(&sw->recp_list[i].filt_replay_rules)) {\n+\t\t\tstruct LIST_HEAD_TYPE *l_head;\n+\n+\t\t\tl_head = &sw->recp_list[i].filt_replay_rules;\n+\t\t\tif (!sw->recp_list[i].adv_rule)\n+\t\t\t\tice_rem_sw_rule_info(hw, l_head);\n+\t\t}\n+\t}\n+}\ndiff --git a/drivers/net/ice/base/ice_switch.h b/drivers/net/ice/base/ice_switch.h\nnew file mode 100644\nindex 0000000..66a172f\n--- /dev/null\n+++ b/drivers/net/ice/base/ice_switch.h\n@@ -0,0 +1,333 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2001-2018\n+ */\n+\n+#ifndef _ICE_SWITCH_H_\n+#define _ICE_SWITCH_H_\n+\n+#include \"ice_common.h\"\n+#include \"ice_protocol_type.h\"\n+\n+#define ICE_SW_CFG_MAX_BUF_LEN 2048\n+#define ICE_MAX_SW 256\n+#define ICE_DFLT_VSI_INVAL 0xff\n+\n+\n+\n+#define ICE_VSI_INVAL_ID 0xFFFF\n+\n+/* VSI context structure for add/get/update/free operations */\n+struct ice_vsi_ctx {\n+\tu16 vsi_num;\n+\tu16 vsis_allocd;\n+\tu16 vsis_unallocated;\n+\tu16 flags;\n+\tstruct ice_aqc_vsi_props info;\n+\tstruct ice_sched_vsi_info sched;\n+\tu8 alloc_from_pool;\n+\tstruct ice_lock rss_locks;\t/* protect rss config in VSI ctx */\n+\tstruct LIST_HEAD_TYPE rss_list_head;\n+};\n+\n+\n+/* Switch recipe ID enum values are specific to hardware */\n+enum ice_sw_lkup_type {\n+\tICE_SW_LKUP_ETHERTYPE = 0,\n+\tICE_SW_LKUP_MAC = 1,\n+\tICE_SW_LKUP_MAC_VLAN = 2,\n+\tICE_SW_LKUP_PROMISC = 3,\n+\tICE_SW_LKUP_VLAN = 4,\n+\tICE_SW_LKUP_DFLT = 5,\n+\tICE_SW_LKUP_ETHERTYPE_MAC = 8,\n+\tICE_SW_LKUP_PROMISC_VLAN = 9,\n+\tICE_SW_LKUP_LAST,\n+};\n+\n+/* type of filter src id */\n+enum ice_src_id {\n+\tICE_SRC_ID_UNKNOWN = 0,\n+\tICE_SRC_ID_VSI,\n+\tICE_SRC_ID_QUEUE,\n+\tICE_SRC_ID_LPORT,\n+};\n+\n+struct ice_fltr_info {\n+\t/* Look up information: how to look up packet */\n+\tenum ice_sw_lkup_type lkup_type;\n+\t/* Forward action: filter action to do after lookup */\n+\tenum ice_sw_fwd_act_type fltr_act;\n+\t/* rule ID returned by firmware once filter rule is created */\n+\tu16 fltr_rule_id;\n+\tu16 flag;\n+#define ICE_FLTR_RX\t\tBIT(0)\n+#define ICE_FLTR_TX\t\tBIT(1)\n+#define ICE_FLTR_TX_RX\t\t(ICE_FLTR_RX | ICE_FLTR_TX)\n+\n+\t/* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */\n+\tu16 src;\n+\tenum ice_src_id src_id;\n+\n+\tunion {\n+\t\tstruct {\n+\t\t\tu8 mac_addr[ETH_ALEN];\n+\t\t} mac;\n+\t\tstruct {\n+\t\t\tu8 mac_addr[ETH_ALEN];\n+\t\t\tu16 vlan_id;\n+\t\t} mac_vlan;\n+\t\tstruct {\n+\t\t\tu16 vlan_id;\n+\t\t} vlan;\n+\t\t/* Set lkup_type as ICE_SW_LKUP_ETHERTYPE\n+\t\t * if just using ethertype as filter. Set lkup_type as\n+\t\t * ICE_SW_LKUP_ETHERTYPE_MAC if MAC also needs to be\n+\t\t * passed in as filter.\n+\t\t */\n+\t\tstruct {\n+\t\t\tu16 ethertype;\n+\t\t\tu8 mac_addr[ETH_ALEN]; /* optional */\n+\t\t} ethertype_mac;\n+\t} l_data; /* Make sure to zero out the memory of l_data before using\n+\t\t   * it or only set the data associated with lookup match\n+\t\t   * rest everything should be zero\n+\t\t   */\n+\n+\t/* Depending on filter action */\n+\tunion {\n+\t\t/* queue id in case of ICE_FWD_TO_Q and starting\n+\t\t * queue id in case of ICE_FWD_TO_QGRP.\n+\t\t */\n+\t\tu16 q_id:11;\n+\t\tu16 hw_vsi_id:10;\n+\t\tu16 vsi_id:10;\n+\t\tu16 vsi_list_id:10;\n+\t} fwd_id;\n+\n+\t/* Sw VSI handle */\n+\tu16 vsi_handle;\n+\n+\t/* Set to num_queues if action is ICE_FWD_TO_QGRP. This field\n+\t * determines the range of queues the packet needs to be forwarded to.\n+\t * Note that qgrp_size must be set to a power of 2.\n+\t */\n+\tu8 qgrp_size;\n+\n+\t/* Rule creations populate these indicators basing on the switch type */\n+\tu8 lb_en;\t/* Indicate if packet can be looped back */\n+\tu8 lan_en;\t/* Indicate if packet can be forwarded to the uplink */\n+};\n+\n+struct ice_adv_lkup_elem {\n+\tenum ice_protocol_type type;\n+\tunion ice_prot_hdr h_u;\t/* Header values */\n+\tunion ice_prot_hdr m_u;\t/* Mask of header values to match */\n+};\n+\n+struct ice_sw_act_ctrl {\n+\t/* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */\n+\tu16 src;\n+\tu16 flag;\n+#define ICE_FLTR_RX             BIT(0)\n+#define ICE_FLTR_TX             BIT(1)\n+#define ICE_FLTR_TX_RX (ICE_FLTR_RX | ICE_FLTR_TX)\n+\n+\tenum ice_sw_fwd_act_type fltr_act;\n+\t/* Depending on filter action */\n+\tunion {\n+\t\t/* This is a queue id in case of ICE_FWD_TO_Q and starting\n+\t\t * queue id in case of ICE_FWD_TO_QGRP.\n+\t\t */\n+\t\tu16 q_id:11;\n+\t\tu16 vsi_id:10;\n+\t\tu16 hw_vsi_id:10;\n+\t\tu16 vsi_list_id:10;\n+\t} fwd_id;\n+\t/* software VSI handle */\n+\tu16 vsi_handle;\n+\tu8 qgrp_size;\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+};\n+\n+/* A collection of one or more four word recipe */\n+struct ice_sw_recipe {\n+\t/* For a chained recipe the root recipe is what should be used for\n+\t * programming rules\n+\t */\n+\tu8 root_rid;\n+\tu8 recp_created;\n+\n+\t/* Number of extraction words */\n+\tu8 n_ext_words;\n+\t/* Protocol ID and Offset pair (extraction word) to describe the\n+\t * recipe\n+\t */\n+\tstruct ice_fv_word ext_words[ICE_MAX_CHAIN_WORDS];\n+\n+\t/* if this recipe is a collection of other recipe */\n+\tu8 big_recp;\n+\n+\t/* if this recipe is part of another bigger recipe then chain index\n+\t * corresponding to this recipe\n+\t */\n+\tu8 chain_idx;\n+\n+\t/* if this recipe is a collection of other recipe then count of other\n+\t * recipes and recipe ids of those recipes\n+\t */\n+\tu8 n_grp_count;\n+\n+\t/* Bit map specifying the IDs associated with this group of recipe */\n+\tice_declare_bitmap(r_bitmap, ICE_MAX_NUM_RECIPES);\n+\n+\tenum ice_sw_tunnel_type tun_type;\n+\n+\t/* List of type ice_fltr_mgmt_list_entry or adv_rule */\n+\tu8 adv_rule;\n+\tstruct LIST_HEAD_TYPE filt_rules;\n+\tstruct LIST_HEAD_TYPE filt_replay_rules;\n+\n+\tstruct ice_lock filt_rule_lock;\t/* protect filter rule structure */\n+\n+\t/* Profiles this recipe should be associated with */\n+\tstruct LIST_HEAD_TYPE fv_list;\n+\n+\t/* Profiles this recipe is associated with */\n+\tu8 num_profs, *prof_ids;\n+\n+\t/* This allows user to specify the recipe priority.\n+\t * For now, this becomes 'fwd_priority' when recipe\n+\t * is created, usually recipes can have 'fwd' and 'join'\n+\t * priority.\n+\t */\n+\tu8 priority;\n+\n+\tstruct LIST_HEAD_TYPE rg_list;\n+\n+\t/* AQ buffer associated with this recipe */\n+\tstruct ice_aqc_recipe_data_elem *root_buf;\n+};\n+\n+/* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list id */\n+struct ice_vsi_list_map_info {\n+\tstruct LIST_ENTRY_TYPE list_entry;\n+\tice_declare_bitmap(vsi_map, ICE_MAX_VSI);\n+\tu16 vsi_list_id;\n+\t/* counter to track how many rules are reusing this VSI list */\n+\tu16 ref_cnt;\n+};\n+\n+struct ice_fltr_list_entry {\n+\tstruct LIST_ENTRY_TYPE list_entry;\n+\tenum ice_status status;\n+\tstruct ice_fltr_info fltr_info;\n+};\n+\n+/* This defines an entry in the list that maintains MAC or VLAN membership\n+ * to HW list mapping, since multiple VSIs can subscribe to the same MAC or\n+ * VLAN. As an optimization the VSI list should be created only when a\n+ * second VSI becomes a subscriber to the same MAC address. VSI lists are always\n+ * used for VLAN membership.\n+ */\n+struct ice_fltr_mgmt_list_entry {\n+\t/* back pointer to VSI list id to VSI list mapping */\n+\tstruct ice_vsi_list_map_info *vsi_list_info;\n+\tu16 vsi_count;\n+#define ICE_INVAL_LG_ACT_INDEX 0xffff\n+\tu16 lg_act_idx;\n+#define ICE_INVAL_SW_MARKER_ID 0xffff\n+\tu16 sw_marker_id;\n+\tstruct LIST_ENTRY_TYPE list_entry;\n+\tstruct ice_fltr_info fltr_info;\n+#define ICE_INVAL_COUNTER_ID 0xff\n+\tu8 counter_index;\n+};\n+\n+struct ice_adv_fltr_mgmt_list_entry {\n+\tstruct LIST_ENTRY_TYPE list_entry;\n+\n+\tstruct ice_adv_lkup_elem *lkups;\n+\tstruct ice_adv_rule_info rule_info;\n+\tu16 lkups_cnt;\n+};\n+\n+enum ice_promisc_flags {\n+\tICE_PROMISC_UCAST_RX = 0x1,\n+\tICE_PROMISC_UCAST_TX = 0x2,\n+\tICE_PROMISC_MCAST_RX = 0x4,\n+\tICE_PROMISC_MCAST_TX = 0x8,\n+\tICE_PROMISC_BCAST_RX = 0x10,\n+\tICE_PROMISC_BCAST_TX = 0x20,\n+\tICE_PROMISC_VLAN_RX = 0x40,\n+\tICE_PROMISC_VLAN_TX = 0x80,\n+};\n+\n+/* VSI related commands */\n+enum ice_status\n+ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t    struct ice_sq_cd *cd);\n+enum ice_status\n+ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t     bool keep_vsi_alloc, struct ice_sq_cd *cd);\n+enum ice_status\n+ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t       struct ice_sq_cd *cd);\n+struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle);\n+void ice_clear_all_vsi_ctx(struct ice_hw *hw);\n+/* Switch config */\n+enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);\n+\n+enum ice_status\n+ice_alloc_vlan_res_counter(struct ice_hw *hw, u16 *counter_id);\n+enum ice_status\n+ice_free_vlan_res_counter(struct ice_hw *hw, u16 counter_id);\n+\n+/* Switch/bridge related commands */\n+enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw);\n+enum ice_status\n+ice_add_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list);\n+enum ice_status ice_add_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_lst);\n+enum ice_status ice_remove_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_lst);\n+enum ice_status\n+ice_remove_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list);\n+#ifndef NO_MACVLAN_SUPPORT\n+enum ice_status\n+ice_add_mac_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list);\n+enum ice_status\n+ice_remove_mac_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list);\n+#endif /* !NO_MACVLAN_SUPPORT */\n+\n+void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle);\n+\n+\n+/* Promisc/defport setup for VSIs */\n+enum ice_status\n+ice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set,\n+\t\t u8 direction);\n+enum ice_status\n+ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,\n+\t\t    u16 vid);\n+enum ice_status\n+ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,\n+\t\t      u16 vid);\n+enum ice_status\n+ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,\n+\t\t\t bool rm_vlan_promisc);\n+\n+\n+\n+\n+\n+enum ice_status ice_init_def_sw_recp(struct ice_hw *hw);\n+u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle);\n+bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle);\n+\n+enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle);\n+void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw);\n+\n+#endif /* _ICE_SWITCH_H_ */\n",
    "prefixes": [
        "v5",
        "08/31"
    ]
}