get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 887914,
    "url": "http://patchwork.ozlabs.org/api/patches/887914/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180319215644.31978-8-jeffrey.t.kirsher@intel.com/",
    "project": {
        "id": 46,
        "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api",
        "name": "Intel Wired Ethernet development",
        "link_name": "intel-wired-lan",
        "list_id": "intel-wired-lan.osuosl.org",
        "list_email": "intel-wired-lan@osuosl.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20180319215644.31978-8-jeffrey.t.kirsher@intel.com>",
    "list_archive_url": null,
    "date": "2018-03-19T21:56:37",
    "name": "[v3,08/15] ice: Add support for switch filter programming",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "51aef2f62fa770faf1827f7d823088acd54ce49e",
    "submitter": {
        "id": 473,
        "url": "http://patchwork.ozlabs.org/api/people/473/?format=api",
        "name": "Kirsher, Jeffrey T",
        "email": "jeffrey.t.kirsher@intel.com"
    },
    "delegate": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/users/68/?format=api",
        "username": "jtkirshe",
        "first_name": "Jeff",
        "last_name": "Kirsher",
        "email": "jeffrey.t.kirsher@intel.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180319215644.31978-8-jeffrey.t.kirsher@intel.com/mbox/",
    "series": [
        {
            "id": 34702,
            "url": "http://patchwork.ozlabs.org/api/series/34702/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=34702",
            "date": "2018-03-19T21:56:30",
            "name": "[v3,01/15] ice: Add basic driver framework for Intel(R) E800 Series",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/34702/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/887914/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/887914/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<intel-wired-lan-bounces@osuosl.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.137; helo=fraxinus.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org;\n\tdmarc=none (p=none dis=none) header.from=intel.com"
        ],
        "Received": [
            "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 404qdv5QZLz9sVl\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 20 Mar 2018 08:56:35 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 4A40586787;\n\tMon, 19 Mar 2018 21:56:34 +0000 (UTC)",
            "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id ba1nJCIraSfH; Mon, 19 Mar 2018 21:56:24 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 445418670F;\n\tMon, 19 Mar 2018 21:56:24 +0000 (UTC)",
            "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id BCE251C2272\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:20 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id AFE0888ED1\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:20 +0000 (UTC)",
            "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id fjT50mX9ls0Y for <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:12 +0000 (UTC)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id 113D688F80\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:09 +0000 (UTC)",
            "from orsmga008.jf.intel.com ([10.7.209.65])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t19 Mar 2018 14:56:07 -0700",
            "from jtkirshe-nuc.jf.intel.com ([134.134.177.59])\n\tby orsmga008.jf.intel.com with ESMTP; 19 Mar 2018 14:56:07 -0700"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6",
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.48,332,1517904000\"; d=\"scan'208\";a=\"26667085\"",
        "From": "Jeff Kirsher <jeffrey.t.kirsher@intel.com>",
        "To": "intel-wired-lan@lists.osuosl.org",
        "Date": "Mon, 19 Mar 2018 14:56:37 -0700",
        "Message-Id": "<20180319215644.31978-8-jeffrey.t.kirsher@intel.com>",
        "X-Mailer": "git-send-email 2.14.3",
        "In-Reply-To": "<20180319215644.31978-1-jeffrey.t.kirsher@intel.com>",
        "References": "<20180319215644.31978-1-jeffrey.t.kirsher@intel.com>",
        "Subject": "[Intel-wired-lan] [PATCH v3 08/15] ice: Add support for switch\n\tfilter programming",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.24",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>",
        "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>",
        "List-Post": "<mailto:intel-wired-lan@osuosl.org>",
        "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>",
        "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "intel-wired-lan-bounces@osuosl.org",
        "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"
    },
    "content": "From: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>\n\nA VSI needs traffic directed towards it. This is done by programming\nfilter rules on the switch (embedded vSwitch) element in the hardware,\nwhich connects the VSI to the ingress/egress port.\n\nThis patch introduces data structures and functions necessary to add\nremove or update switch rules on the switch element. This is a pretty low\nlevel function that is generic enough to add a whole range of filters.\n\nThis patch also introduces two top level functions ice_add_mac and\nice_remove mac which through a series of intermediate helper functions\neventually call ice_aq_sw_rules to add/delete simple MAC based filters.\nIt's worth noting that one invocation of ice_add_mac/ice_remove_mac\nis capable of adding/deleting multiple MAC filters.\n\nAlso worth noting is the fact that the driver maintains a list of currently\nactive filters, so every filter addition/removal causes an update to this\nlist. This is done for a couple of reasons:\n\n1) If two VSIs try to add the same filters, we need to detect it and do\n   things a little differently (i.e. use VSI lists, described below) as\n   the same filter can't be added more than once.\n\n2) In the event of a hardware reset we can simply walk through this list\n   and restore the filters.\n\nVSI Lists:\nIn a multi-VSI situation, it's possible that multiple VSIs want to add the\nsame filter rule. For example, two VSIs that want to receive broadcast\ntraffic would both add a filter for destination MAC ff:ff:ff:ff:ff:ff.\nThis can become cumbersome to maintain and so this is handled using a\nVSI list.\n\nA VSI list is resource that can be allocated in the hardware using the\nice_aq_alloc_free_res admin queue command. Simply put, a VSI list can\nbe thought of as a subscription list containing a set of VSIs to which\nthe packet should be forwarded, should the filter match.\n\nFor example, if VSI-0 has already added a broadcast filter, and VSI-1\nwants to do the same thing, the filter creation flow will detect this,\nallocate a VSI list and update the switch rule so that broadcast traffic\nwill now be forwarded to the VSI list which contains VSI-0 and VSI-1.\n\nSigned-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>\n---\n drivers/net/ethernet/intel/ice/ice_adminq_cmd.h |  249 ++++\n drivers/net/ethernet/intel/ice/ice_common.c     |   74 +-\n drivers/net/ethernet/intel/ice/ice_main.c       |   92 ++\n drivers/net/ethernet/intel/ice/ice_status.h     |    3 +\n drivers/net/ethernet/intel/ice/ice_switch.c     | 1378 +++++++++++++++++++++++\n drivers/net/ethernet/intel/ice/ice_switch.h     |  120 ++\n drivers/net/ethernet/intel/ice/ice_type.h       |   21 +\n 7 files changed, 1935 insertions(+), 2 deletions(-)",
    "diff": "diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 570169c99786..c834ed38602b 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -22,6 +22,7 @@\n  * descriptor format.  It is shared between Firmware and Software.\n  */\n \n+#define ICE_MAX_VSI\t\t\t768\n #define ICE_AQC_TOPO_MAX_LEVEL_NUM\t0x9\n #define ICE_AQ_SET_MAC_FRAME_SIZE_MAX\t9728\n \n@@ -205,6 +206,46 @@ struct ice_aqc_get_sw_cfg_resp {\n \tstruct ice_aqc_get_sw_cfg_resp_elem elements[1];\n };\n \n+/* These resource type defines are used for all switch resource\n+ * commands where a resource type is required, such as:\n+ * Get Resource Allocation command (indirect 0x0204)\n+ * Allocate Resources command (indirect 0x0208)\n+ * Free Resources command (indirect 0x0209)\n+ * Get Allocated Resource Descriptors Command (indirect 0x020A)\n+ */\n+#define ICE_AQC_RES_TYPE_VSI_LIST_REP\t\t\t0x03\n+#define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE\t\t\t0x04\n+\n+/* Allocate Resources command (indirect 0x0208)\n+ * Free Resources command (indirect 0x0209)\n+ */\n+struct ice_aqc_alloc_free_res_cmd {\n+\t__le16 num_entries; /* Number of Resource entries */\n+\tu8 reserved[6];\n+\t__le32 addr_high;\n+\t__le32 addr_low;\n+};\n+\n+/* Resource descriptor */\n+struct ice_aqc_res_elem {\n+\tunion {\n+\t\t__le16 sw_resp;\n+\t\t__le16 flu_resp;\n+\t} e;\n+};\n+\n+/* Buffer for Allocate/Free Resources commands */\n+struct ice_aqc_alloc_free_res_elem {\n+\t__le16 res_type; /* Types defined above cmd 0x0204 */\n+#define ICE_AQC_RES_TYPE_SHARED_S\t7\n+#define ICE_AQC_RES_TYPE_SHARED_M\t(0x1 << ICE_AQC_RES_TYPE_SHARED_S)\n+#define ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_S\t8\n+#define ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_M\t\\\n+\t\t\t\t(0xF << ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_S)\n+\t__le16 num_elems;\n+\tstruct ice_aqc_res_elem elem[1];\n+};\n+\n /* Add VSI (indirect 0x0210)\n  * Update VSI (indirect 0x0211)\n  * Get VSI (indirect 0x0212)\n@@ -398,6 +439,202 @@ struct ice_aqc_vsi_props {\n \tu8 reserved[24];\n };\n \n+/* Add/Update/Remove/Get switch rules (indirect 0x02A0, 0x02A1, 0x02A2, 0x02A3)\n+ */\n+struct ice_aqc_sw_rules {\n+\t/* ops: add switch rules, referring the number of rules.\n+\t * ops: update switch rules, referring the number of filters\n+\t * ops: remove switch rules, referring the entry index.\n+\t * ops: get switch rules, referring to the number of filters.\n+\t */\n+\t__le16 num_rules_fltr_entry_index;\n+\tu8 reserved[6];\n+\t__le32 addr_high;\n+\t__le32 addr_low;\n+};\n+\n+/* Add/Update/Get/Remove lookup Rx/Tx command/response entry\n+ * This structures describes the lookup rules and associated actions.  \"index\"\n+ * is returned as part of a response to a successful Add command, and can be\n+ * used to identify the rule for Update/Get/Remove commands.\n+ */\n+struct ice_sw_rule_lkup_rx_tx {\n+\t__le16 recipe_id;\n+#define ICE_SW_RECIPE_LOGICAL_PORT_FWD\t\t10\n+\t/* Source port for LOOKUP_RX and source VSI in case of LOOKUP_TX */\n+\t__le16 src;\n+\t__le32 act;\n+\n+\t/* Bit 0:1 - Action type */\n+#define ICE_SINGLE_ACT_TYPE_S\t0x00\n+#define ICE_SINGLE_ACT_TYPE_M\t(0x3 << ICE_SINGLE_ACT_TYPE_S)\n+\n+\t/* Bit 2 - Loop back enable\n+\t * Bit 3 - LAN enable\n+\t */\n+#define ICE_SINGLE_ACT_LB_ENABLE\tBIT(2)\n+#define ICE_SINGLE_ACT_LAN_ENABLE\tBIT(3)\n+\n+\t/* Action type = 0 - Forward to VSI or VSI list */\n+#define ICE_SINGLE_ACT_VSI_FORWARDING\t0x0\n+\n+#define ICE_SINGLE_ACT_VSI_ID_S\t\t4\n+#define ICE_SINGLE_ACT_VSI_ID_M\t\t(0x3FF << ICE_SINGLE_ACT_VSI_ID_S)\n+#define ICE_SINGLE_ACT_VSI_LIST_ID_S\t4\n+#define ICE_SINGLE_ACT_VSI_LIST_ID_M\t(0x3FF << ICE_SINGLE_ACT_VSI_LIST_ID_S)\n+\t/* This bit needs to be set if action is forward to VSI list */\n+#define ICE_SINGLE_ACT_VSI_LIST\t\tBIT(14)\n+#define ICE_SINGLE_ACT_VALID_BIT\tBIT(17)\n+#define ICE_SINGLE_ACT_DROP\t\tBIT(18)\n+\n+\t/* Action type = 1 - Forward to Queue of Queue group */\n+#define ICE_SINGLE_ACT_TO_Q\t\t0x1\n+#define ICE_SINGLE_ACT_Q_INDEX_S\t4\n+#define ICE_SINGLE_ACT_Q_INDEX_M\t(0x7FF << ICE_SINGLE_ACT_Q_INDEX_S)\n+#define ICE_SINGLE_ACT_Q_REGION_S\t15\n+#define ICE_SINGLE_ACT_Q_REGION_M\t(0x7 << ICE_SINGLE_ACT_Q_REGION_S)\n+#define ICE_SINGLE_ACT_Q_PRIORITY\tBIT(18)\n+\n+\t/* Action type = 2 - Prune */\n+#define ICE_SINGLE_ACT_PRUNE\t\t0x2\n+#define ICE_SINGLE_ACT_EGRESS\t\tBIT(15)\n+#define ICE_SINGLE_ACT_INGRESS\t\tBIT(16)\n+#define ICE_SINGLE_ACT_PRUNET\t\tBIT(17)\n+\t/* Bit 18 should be set to 0 for this action */\n+\n+\t/* Action type = 2 - Pointer */\n+#define ICE_SINGLE_ACT_PTR\t\t0x2\n+#define ICE_SINGLE_ACT_PTR_VAL_S\t4\n+#define ICE_SINGLE_ACT_PTR_VAL_M\t(0x1FFF << ICE_SINGLE_ACT_PTR_VAL_S)\n+\t/* Bit 18 should be set to 1 */\n+#define ICE_SINGLE_ACT_PTR_BIT\t\tBIT(18)\n+\n+\t/* Action type = 3 - Other actions. Last two bits\n+\t * are other action identifier\n+\t */\n+#define ICE_SINGLE_ACT_OTHER_ACTS\t\t0x3\n+#define ICE_SINGLE_OTHER_ACT_IDENTIFIER_S\t17\n+#define ICE_SINGLE_OTHER_ACT_IDENTIFIER_M\t\\\n+\t\t\t\t(0x3 << \\ ICE_SINGLE_OTHER_ACT_IDENTIFIER_S)\n+\n+\t/* Bit 17:18 - Defines other actions */\n+\t/* Other action = 0 - Mirror VSI */\n+#define ICE_SINGLE_OTHER_ACT_MIRROR\t\t0\n+#define ICE_SINGLE_ACT_MIRROR_VSI_ID_S\t4\n+#define ICE_SINGLE_ACT_MIRROR_VSI_ID_M\t\\\n+\t\t\t\t(0x3FF << ICE_SINGLE_ACT_MIRROR_VSI_ID_S)\n+\n+\t/* Other action = 3 - Set Stat count */\n+#define ICE_SINGLE_OTHER_ACT_STAT_COUNT\t\t3\n+#define ICE_SINGLE_ACT_STAT_COUNT_INDEX_S\t4\n+#define ICE_SINGLE_ACT_STAT_COUNT_INDEX_M\t\\\n+\t\t\t\t(0x7F << ICE_SINGLE_ACT_STAT_COUNT_INDEX_S)\n+\n+\t__le16 index; /* The index of the rule in the lookup table */\n+\t/* Length and values of the header to be matched per recipe or\n+\t * lookup-type\n+\t */\n+\t__le16 hdr_len;\n+\tu8 hdr[1];\n+} __packed;\n+\n+/* Add/Update/Remove large action command/response entry\n+ * \"index\" is returned as part of a response to a successful Add command, and\n+ * can be used to identify the action for Update/Get/Remove commands.\n+ */\n+struct ice_sw_rule_lg_act {\n+\t__le16 index; /* Index in large action table */\n+\t__le16 size;\n+\t__le32 act[1]; /* array of size for actions */\n+\t/* Max number of large actions */\n+#define ICE_MAX_LG_ACT\t4\n+\t/* Bit 0:1 - Action type */\n+#define ICE_LG_ACT_TYPE_S\t0\n+#define ICE_LG_ACT_TYPE_M\t(0x7 << ICE_LG_ACT_TYPE_S)\n+\n+\t/* Action type = 0 - Forward to VSI or VSI list */\n+#define ICE_LG_ACT_VSI_FORWARDING\t0\n+#define ICE_LG_ACT_VSI_ID_S\t\t3\n+#define ICE_LG_ACT_VSI_ID_M\t\t(0x3FF << ICE_LG_ACT_VSI_ID_S)\n+#define ICE_LG_ACT_VSI_LIST_ID_S\t3\n+#define ICE_LG_ACT_VSI_LIST_ID_M\t(0x3FF << ICE_LG_ACT_VSI_LIST_ID_S)\n+\t/* This bit needs to be set if action is forward to VSI list */\n+#define ICE_LG_ACT_VSI_LIST\t\tBIT(13)\n+\n+#define ICE_LG_ACT_VALID_BIT\t\tBIT(16)\n+\n+\t/* Action type = 1 - Forward to Queue of Queue group */\n+#define ICE_LG_ACT_TO_Q\t\t\t0x1\n+#define ICE_LG_ACT_Q_INDEX_S\t\t3\n+#define ICE_LG_ACT_Q_INDEX_M\t\t(0x7FF << ICE_LG_ACT_Q_INDEX_S)\n+#define ICE_LG_ACT_Q_REGION_S\t\t14\n+#define ICE_LG_ACT_Q_REGION_M\t\t(0x7 << ICE_LG_ACT_Q_REGION_S)\n+#define ICE_LG_ACT_Q_PRIORITY_SET\tBIT(17)\n+\n+\t/* Action type = 2 - Prune */\n+#define ICE_LG_ACT_PRUNE\t\t0x2\n+#define ICE_LG_ACT_EGRESS\t\tBIT(14)\n+#define ICE_LG_ACT_INGRESS\t\tBIT(15)\n+#define ICE_LG_ACT_PRUNET\t\tBIT(16)\n+\n+\t/* Action type = 3 - Mirror VSI */\n+#define ICE_LG_OTHER_ACT_MIRROR\t\t0x3\n+#define ICE_LG_ACT_MIRROR_VSI_ID_S\t3\n+#define ICE_LG_ACT_MIRROR_VSI_ID_M\t(0x3FF << ICE_LG_ACT_MIRROR_VSI_ID_S)\n+\n+\t/* Action type = 5 - Large Action */\n+#define ICE_LG_ACT_GENERIC\t\t0x5\n+#define ICE_LG_ACT_GENERIC_VALUE_S\t3\n+#define ICE_LG_ACT_GENERIC_VALUE_M\t(0xFFFF << ICE_LG_ACT_GENERIC_VALUE_S)\n+#define ICE_LG_ACT_GENERIC_OFFSET_S\t19\n+#define ICE_LG_ACT_GENERIC_OFFSET_M\t(0x7 << ICE_LG_ACT_GENERIC_OFFSET_S)\n+#define ICE_LG_ACT_GENERIC_PRIORITY_S\t22\n+#define ICE_LG_ACT_GENERIC_PRIORITY_M\t(0x7 << ICE_LG_ACT_GENERIC_PRIORITY_S)\n+\n+\t/* Action = 7 - Set Stat count */\n+#define ICE_LG_ACT_STAT_COUNT\t\t0x7\n+#define ICE_LG_ACT_STAT_COUNT_S\t\t3\n+#define ICE_LG_ACT_STAT_COUNT_M\t\t(0x7F << ICE_LG_ACT_STAT_COUNT_S)\n+};\n+\n+/* Add/Update/Remove VSI list command/response entry\n+ * \"index\" is returned as part of a response to a successful Add command, and\n+ * can be used to identify the VSI list for Update/Get/Remove commands.\n+ */\n+struct ice_sw_rule_vsi_list {\n+\t__le16 index; /* Index of VSI/Prune list */\n+\t__le16 number_vsi;\n+\t__le16 vsi[1]; /* Array of number_vsi VSI numbers */\n+};\n+\n+/* Query VSI list command/response entry */\n+struct ice_sw_rule_vsi_list_query {\n+\t__le16 index;\n+\tDECLARE_BITMAP(vsi_list, ICE_MAX_VSI);\n+} __packed;\n+\n+/* Add switch rule response:\n+ * Content of return buffer is same as the input buffer. The status field and\n+ * LUT index are updated as part of the response\n+ */\n+struct ice_aqc_sw_rules_elem {\n+\t__le16 type; /* Switch rule type, one of T_... */\n+#define ICE_AQC_SW_RULES_T_LKUP_RX\t\t0x0\n+#define ICE_AQC_SW_RULES_T_LKUP_TX\t\t0x1\n+#define ICE_AQC_SW_RULES_T_LG_ACT\t\t0x2\n+#define ICE_AQC_SW_RULES_T_VSI_LIST_SET\t\t0x3\n+#define ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR\t0x4\n+#define ICE_AQC_SW_RULES_T_PRUNE_LIST_SET\t0x5\n+#define ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR\t0x6\n+\t__le16 status;\n+\tunion {\n+\t\tstruct ice_sw_rule_lkup_rx_tx lkup_tx_rx;\n+\t\tstruct ice_sw_rule_lg_act lg_act;\n+\t\tstruct ice_sw_rule_vsi_list vsi_list;\n+\t\tstruct ice_sw_rule_vsi_list_query vsi_list_query;\n+\t} __packed pdata;\n+};\n+\n /* Get Default Topology (indirect 0x0400) */\n struct ice_aqc_get_topo {\n \tu8 port_num;\n@@ -780,11 +1017,13 @@ struct ice_aq_desc {\n \t\tstruct ice_aqc_list_caps get_cap;\n \t\tstruct ice_aqc_get_phy_caps get_phy;\n \t\tstruct ice_aqc_get_sw_cfg get_sw_conf;\n+\t\tstruct ice_aqc_sw_rules sw_rules;\n \t\tstruct ice_aqc_get_topo get_topo;\n \t\tstruct ice_aqc_query_txsched_res query_sched_res;\n \t\tstruct ice_aqc_add_move_delete_elem add_move_delete_elem;\n \t\tstruct ice_aqc_nvm nvm;\n \t\tstruct ice_aqc_add_get_update_free_vsi vsi_cmd;\n+\t\tstruct ice_aqc_alloc_free_res_cmd sw_res_ctrl;\n \t\tstruct ice_aqc_get_link_status get_link_status;\n \t} params;\n };\n@@ -835,10 +1074,20 @@ enum ice_adminq_opc {\n \t/* internal switch commands */\n \tice_aqc_opc_get_sw_cfg\t\t\t\t= 0x0200,\n \n+\t/* Alloc/Free/Get Resources */\n+\tice_aqc_opc_alloc_res\t\t\t\t= 0x0208,\n+\tice_aqc_opc_free_res\t\t\t\t= 0x0209,\n+\n \t/* VSI commands */\n \tice_aqc_opc_add_vsi\t\t\t\t= 0x0210,\n \tice_aqc_opc_update_vsi\t\t\t\t= 0x0211,\n \tice_aqc_opc_free_vsi\t\t\t\t= 0x0213,\n+\n+\t/* switch rules population commands */\n+\tice_aqc_opc_add_sw_rules\t\t\t= 0x02A0,\n+\tice_aqc_opc_update_sw_rules\t\t\t= 0x02A1,\n+\tice_aqc_opc_remove_sw_rules\t\t\t= 0x02A2,\n+\n \tice_aqc_opc_clear_pf_cfg\t\t\t= 0x02A4,\n \n \t/* transmit scheduler commands */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex e66e9e36a580..cb48146b46f3 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -272,6 +272,66 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,\n \treturn status;\n }\n \n+/**\n+ * ice_init_fltr_mgmt_struct - initializes filter management list and locks\n+ * @hw: pointer to the hw struct\n+ */\n+static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw)\n+{\n+\tstruct ice_switch_info *sw;\n+\n+\thw->switch_info = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t\t       sizeof(*hw->switch_info), GFP_KERNEL);\n+\tsw = hw->switch_info;\n+\n+\tif (!sw)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tINIT_LIST_HEAD(&sw->vsi_list_map_head);\n+\n+\tmutex_init(&sw->mac_list_lock);\n+\tINIT_LIST_HEAD(&sw->mac_list_head);\n+\n+\tmutex_init(&sw->vlan_list_lock);\n+\tINIT_LIST_HEAD(&sw->vlan_list_head);\n+\n+\tmutex_init(&sw->eth_m_list_lock);\n+\tINIT_LIST_HEAD(&sw->eth_m_list_head);\n+\n+\tmutex_init(&sw->promisc_list_lock);\n+\tINIT_LIST_HEAD(&sw->promisc_list_head);\n+\n+\tmutex_init(&sw->mac_vlan_list_lock);\n+\tINIT_LIST_HEAD(&sw->mac_vlan_list_head);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_cleanup_fltr_mgmt_struct - cleanup filter management list and locks\n+ * @hw: pointer to the hw struct\n+ */\n+static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_vsi_list_map_info *v_pos_map;\n+\tstruct ice_vsi_list_map_info *v_tmp_map;\n+\n+\tlist_for_each_entry_safe(v_pos_map, v_tmp_map, &sw->vsi_list_map_head,\n+\t\t\t\t list_entry) {\n+\t\tlist_del(&v_pos_map->list_entry);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), v_pos_map);\n+\t}\n+\n+\tmutex_destroy(&sw->mac_list_lock);\n+\tmutex_destroy(&sw->vlan_list_lock);\n+\tmutex_destroy(&sw->eth_m_list_lock);\n+\tmutex_destroy(&sw->promisc_list_lock);\n+\tmutex_destroy(&sw->mac_vlan_list_lock);\n+\n+\tdevm_kfree(ice_hw_to_dev(hw), sw);\n+}\n+\n /**\n  * ice_init_hw - main hardware initialization routine\n  * @hw: pointer to the hardware structure\n@@ -335,6 +395,8 @@ enum ice_status ice_init_hw(struct ice_hw *hw)\n \tif (status)\n \t\tgoto err_unroll_alloc;\n \n+\thw->evb_veb = true;\n+\n \t/* Query the allocated resources for tx scheduler */\n \tstatus = ice_sched_query_res_alloc(hw);\n \tif (status) {\n@@ -366,21 +428,27 @@ enum ice_status ice_init_hw(struct ice_hw *hw)\n \tif (status)\n \t\tgoto err_unroll_sched;\n \n+\tstatus = ice_init_fltr_mgmt_struct(hw);\n+\tif (status)\n+\t\tgoto err_unroll_sched;\n+\n \t/* Get port MAC information */\n \tmac_buf_len = sizeof(struct ice_aqc_manage_mac_read_resp);\n \tmac_buf = devm_kzalloc(ice_hw_to_dev(hw), mac_buf_len, GFP_KERNEL);\n \n \tif (!mac_buf)\n-\t\tgoto err_unroll_sched;\n+\t\tgoto err_unroll_fltr_mgmt_struct;\n \n \tstatus = ice_aq_manage_mac_read(hw, mac_buf, mac_buf_len, NULL);\n \tdevm_kfree(ice_hw_to_dev(hw), mac_buf);\n \n \tif (status)\n-\t\tgoto err_unroll_sched;\n+\t\tgoto err_unroll_fltr_mgmt_struct;\n \n \treturn 0;\n \n+err_unroll_fltr_mgmt_struct:\n+\tice_cleanup_fltr_mgmt_struct(hw);\n err_unroll_sched:\n \tice_sched_cleanup_all(hw);\n err_unroll_alloc:\n@@ -403,6 +471,8 @@ void ice_deinit_hw(struct ice_hw *hw)\n \t\tdevm_kfree(ice_hw_to_dev(hw), hw->port_info);\n \t\thw->port_info = NULL;\n \t}\n+\n+\tice_cleanup_fltr_mgmt_struct(hw);\n }\n \n /**\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex eebc25cab244..ae13fe979397 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -176,6 +176,57 @@ static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id)\n \treturn count;\n }\n \n+/**\n+ * ice_add_mac_to_list - Add a mac address filter entry to the list\n+ * @vsi: the VSI to be forwarded to\n+ * @add_list: pointer to the list which contains MAC filter entries\n+ * @macaddr: the MAC address to be added.\n+ *\n+ * Adds mac address filter entry to the temp list\n+ *\n+ * Returns 0 on success or ENOMEM on failure.\n+ */\n+static int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list,\n+\t\t\t       const u8 *macaddr)\n+{\n+\tstruct ice_fltr_list_entry *tmp;\n+\tstruct ice_pf *pf = vsi->back;\n+\n+\ttmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC);\n+\tif (!tmp)\n+\t\treturn -ENOMEM;\n+\n+\ttmp->fltr_info.flag = ICE_FLTR_TX;\n+\ttmp->fltr_info.src = vsi->vsi_num;\n+\ttmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC;\n+\ttmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\ttmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num;\n+\tether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr);\n+\n+\tINIT_LIST_HEAD(&tmp->list_entry);\n+\tlist_add(&tmp->list_entry, add_list);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_free_fltr_list - free filter lists helper\n+ * @dev: pointer to the device struct\n+ * @h: pointer to the list head to be freed\n+ *\n+ * Helper function to free filter lists previously created using\n+ * ice_add_mac_to_list\n+ */\n+static void ice_free_fltr_list(struct device *dev, struct list_head *h)\n+{\n+\tstruct ice_fltr_list_entry *e, *tmp;\n+\n+\tlist_for_each_entry_safe(e, tmp, h, list_entry) {\n+\t\tlist_del(&e->list_entry);\n+\t\tdevm_kfree(dev, e);\n+\t}\n+}\n+\n /**\n  * __ice_clean_ctrlq - helper function to clean controlq rings\n  * @pf: ptr to struct ice_pf\n@@ -1533,6 +1584,8 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n  */\n static int ice_setup_pf_sw(struct ice_pf *pf)\n {\n+\tLIST_HEAD(tmp_add_list);\n+\tu8 broadcast[ETH_ALEN];\n \tstruct ice_vsi *vsi;\n \tint status = 0;\n \n@@ -1542,7 +1595,37 @@ static int ice_setup_pf_sw(struct ice_pf *pf)\n \t\tgoto error_exit;\n \t}\n \n+\t/* tmp_add_list contains a list of MAC addresses for which MAC\n+\t * filters need to be programmed. Add the VSI's unicast MAC to\n+\t * this list\n+\t */\n+\tstatus = ice_add_mac_to_list(vsi, &tmp_add_list,\n+\t\t\t\t     vsi->port_info->mac.perm_addr);\n+\tif (status)\n+\t\tgoto error_exit;\n+\n+\t/* VSI needs to receive broadcast traffic, so add the broadcast\n+\t * MAC address to the list.\n+\t */\n+\teth_broadcast_addr(broadcast);\n+\tstatus = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);\n+\tif (status)\n+\t\tgoto error_exit;\n+\n+\t/* program MAC filters for entries in tmp_add_list */\n+\tstatus = ice_add_mac(&pf->hw, &tmp_add_list);\n+\tif (status) {\n+\t\tdev_err(&pf->pdev->dev, \"Could not add MAC filters\\n\");\n+\t\tstatus = -ENOMEM;\n+\t\tgoto error_exit;\n+\t}\n+\n+\tice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);\n+\treturn status;\n+\n error_exit:\n+\tice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);\n+\n \tif (vsi) {\n \t\tice_vsi_free_q_vectors(vsi);\n \t\tif (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED)\n@@ -1551,6 +1634,7 @@ static int ice_setup_pf_sw(struct ice_pf *pf)\n \t\t\tfree_netdev(vsi->netdev);\n \t\t\tvsi->netdev = NULL;\n \t\t}\n+\n \t\tice_vsi_delete(vsi);\n \t\tice_vsi_put_qs(vsi);\n \t\tpf->q_left_tx += vsi->alloc_txq;\n@@ -1883,6 +1967,13 @@ static int ice_probe(struct pci_dev *pdev,\n \t\t\t\"probe failed due to setup pf switch:%d\\n\", err);\n \t\tgoto err_alloc_sw_unroll;\n \t}\n+\n+\t/* Driver is mostly up */\n+\tclear_bit(__ICE_DOWN, pf->state);\n+\n+\t/* since everything is good, start the service timer */\n+\tmod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));\n+\n \treturn 0;\n \n err_alloc_sw_unroll:\n@@ -2026,6 +2117,7 @@ static int ice_vsi_release(struct ice_vsi *vsi)\n \tice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx);\n \tpf->num_avail_msix += vsi->num_q_vectors;\n \n+\tice_remove_vsi_fltr(&pf->hw, vsi->vsi_num);\n \tice_vsi_delete(vsi);\n \tice_vsi_free_q_vectors(vsi);\n \tice_vsi_clear_rings(vsi);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h\nindex 47ab8c4d1c96..7367392258a5 100644\n--- a/drivers/net/ethernet/intel/ice/ice_status.h\n+++ b/drivers/net/ethernet/intel/ice/ice_status.h\n@@ -21,6 +21,7 @@\n /* Error Codes */\n enum ice_status {\n \tICE_ERR_PARAM\t\t\t\t= -1,\n+\tICE_ERR_NOT_IMPL\t\t\t= -2,\n \tICE_ERR_NOT_READY\t\t\t= -3,\n \tICE_ERR_INVAL_SIZE\t\t\t= -6,\n \tICE_ERR_DEVICE_NOT_SUPPORTED\t\t= -8,\n@@ -29,6 +30,8 @@ enum ice_status {\n \tICE_ERR_NO_MEMORY\t\t\t= -11,\n \tICE_ERR_CFG\t\t\t\t= -12,\n \tICE_ERR_OUT_OF_RANGE\t\t\t= -13,\n+\tICE_ERR_ALREADY_EXISTS\t\t\t= -14,\n+\tICE_ERR_DOES_NOT_EXIST\t\t\t= -15,\n \tICE_ERR_BUF_TOO_SHORT\t\t\t= -52,\n \tICE_ERR_NVM_BLANK_MODE\t\t\t= -53,\n \tICE_ERR_AQ_ERROR\t\t\t= -100,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c\nindex e94bc30c20af..dd396db664f0 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.c\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.c\n@@ -17,6 +17,88 @@\n \n #include \"ice_switch.h\"\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+ * ice_aq_alloc_free_res - command to allocate/free resources\n+ * @hw: pointer to the hw struct\n+ * @num_entries: number of resource entries in buffer\n+ * @buf: Indirect buffer to hold data parameters and response\n+ * @buf_size: size of buffer for indirect commands\n+ * @opc: pass in the command opcode\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Helper function to allocate/free resources using the admin queue commands\n+ */\n+static enum ice_status\n+ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,\n+\t\t      struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,\n+\t\t      enum ice_adminq_opc opc, struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_alloc_free_res_cmd *cmd;\n+\tstruct ice_aq_desc desc;\n+\n+\tcmd = &desc.params.sw_res_ctrl;\n+\n+\tif (!buf)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tif (buf_size < (num_entries * sizeof(buf->elem[0])))\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+\n+\tcmd->num_entries = cpu_to_le16(num_entries);\n+\n+\treturn ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);\n+}\n+\n /**\n  * ice_aq_get_sw_cfg - get switch configuration\n  * @hw: pointer to the hardware structure\n@@ -179,6 +261,93 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n \treturn status;\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 = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL);\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+\tdevm_kfree(ice_hw_to_dev(hw), sw_buf);\n+\treturn status;\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+\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 /* 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@@ -271,3 +440,1212 @@ enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw)\n \tdevm_kfree(ice_hw_to_dev(hw), (void *)rbuf);\n \treturn status;\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+ * @f_info: 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 *f_info)\n+{\n+\tf_info->lb_en = false;\n+\tf_info->lan_en = false;\n+\tif ((f_info->flag & ICE_FLTR_TX) &&\n+\t    (f_info->fltr_act == ICE_FWD_TO_VSI ||\n+\t     f_info->fltr_act == ICE_FWD_TO_VSI_LIST ||\n+\t     f_info->fltr_act == ICE_FWD_TO_Q ||\n+\t     f_info->fltr_act == ICE_FWD_TO_QGRP)) {\n+\t\tf_info->lb_en = true;\n+\t\tif (!(hw->evb_veb && f_info->lkup_type == ICE_SW_LKUP_MAC &&\n+\t\t      is_unicast_ether_addr(f_info->l_data.mac.mac_addr)))\n+\t\t\tf_info->lan_en = true;\n+\t}\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+\tu8 eth_hdr[DUMMY_ETH_HDR_LEN];\n+\tvoid *daddr = NULL;\n+\tu32 act = 0;\n+\t__be16 *off;\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+\t/* initialize the ether header with a dummy header */\n+\tmemcpy(eth_hdr, dummy_eth_header, sizeof(dummy_eth_header));\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.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_FWD_TO_QGRP:\n+\t\tact |= ICE_SINGLE_ACT_TO_Q;\n+\t\tact |= (f_info->qgrp_size << ICE_SINGLE_ACT_Q_REGION_S) &\n+\t\t\tICE_SINGLE_ACT_Q_REGION_M;\n+\t\tbreak;\n+\tcase ICE_DROP_PACKET:\n+\t\tact |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP;\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\tether_addr_copy(&eth_hdr[ICE_ETH_DA_OFFSET], daddr);\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(sizeof(eth_hdr));\n+\n+\tmemcpy(s_rule->pdata.lkup_tx_rx.hdr, eth_hdr, sizeof(eth_hdr));\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+\tu16 vsi_info;\n+\tu32 act;\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 = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL);\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+\tvsi_info = (m_ent->vsi_count > 1) ?\n+\t\tm_ent->fltr_info.fwd_id.vsi_list_id :\n+\t\tm_ent->fltr_info.fwd_id.vsi_id;\n+\n+\tact = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;\n+\tact |= (vsi_info << 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 = (7 << ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_VALUE_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+\tact |= (0 << ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_VALUE_M;\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+\tdevm_kfree(ice_hw_to_dev(hw), lg_act);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_create_vsi_list_map\n+ * @hw: pointer to the hardware structure\n+ * @vsi_array: array of VSIs to form a VSI list\n+ * @num_vsi: num VSI 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_array, 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 = devm_kcalloc(ice_hw_to_dev(hw), 1, sizeof(*v_map), GFP_KERNEL);\n+\tif (!v_map)\n+\t\treturn NULL;\n+\n+\tv_map->vsi_list_id = vsi_list_id;\n+\n+\tfor (i = 0; i < num_vsi; i++)\n+\t\tset_bit(vsi_array[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_array: array of VSIs to form a VSI list\n+ * @num_vsi: num VSI 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_array, 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 = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tfor (i = 0; i < num_vsi; i++)\n+\t\ts_rule->pdata.vsi_list.vsi[i] = cpu_to_le16(vsi_array[i]);\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+\tdevm_kfree(ice_hw_to_dev(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_array: array of VSIs to form a VSI list\n+ * @num_vsi: number of VSIs 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_array, 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+\tint i;\n+\n+\tfor (i = 0; i < num_vsi; i++)\n+\t\tif (vsi_array[i] >= ICE_MAX_VSI)\n+\t\t\treturn ICE_ERR_OUT_OF_RANGE;\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_array, num_vsi, *vsi_list_id,\n+\t\t\t\t\tfalse, ice_aqc_opc_add_sw_rules,\n+\t\t\t\t\tlkup_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_switch_info *sw = hw->switch_info;\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+\tenum ice_status status;\n+\n+\ts_rule = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\tfm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry),\n+\t\t\t\tGFP_KERNEL);\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\tdevm_kfree(ice_hw_to_dev(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+\tif (l_type == ICE_SW_LKUP_MAC) {\n+\t\tmutex_lock(&sw->mac_list_lock);\n+\t\tlist_add(&fm_entry->list_entry, &sw->mac_list_head);\n+\t\tmutex_unlock(&sw->mac_list_lock);\n+\t} else if (l_type == ICE_SW_LKUP_VLAN) {\n+\t\tmutex_lock(&sw->vlan_list_lock);\n+\t\tlist_add(&fm_entry->list_entry, &sw->vlan_list_head);\n+\t\tmutex_unlock(&sw->vlan_list_lock);\n+\t} else if (l_type == ICE_SW_LKUP_ETHERTYPE ||\n+\t\t   l_type == ICE_SW_LKUP_ETHERTYPE_MAC) {\n+\t\tmutex_lock(&sw->eth_m_list_lock);\n+\t\tlist_add(&fm_entry->list_entry, &sw->eth_m_list_head);\n+\t\tmutex_unlock(&sw->eth_m_list_lock);\n+\t} else if (l_type == ICE_SW_LKUP_PROMISC ||\n+\t\t   l_type == ICE_SW_LKUP_PROMISC_VLAN) {\n+\t\tmutex_lock(&sw->promisc_list_lock);\n+\t\tlist_add(&fm_entry->list_entry, &sw->promisc_list_head);\n+\t\tmutex_unlock(&sw->promisc_list_lock);\n+\t} else if (fm_entry->fltr_info.lkup_type == ICE_SW_LKUP_MAC_VLAN) {\n+\t\tmutex_lock(&sw->mac_vlan_list_lock);\n+\t\tlist_add(&fm_entry->list_entry, &sw->mac_vlan_list_head);\n+\t\tmutex_unlock(&sw->mac_vlan_list_lock);\n+\t} else {\n+\t\tstatus = ICE_ERR_NOT_IMPL;\n+\t}\n+ice_create_pkt_fwd_rule_exit:\n+\tdevm_kfree(ice_hw_to_dev(hw), s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_update_pkt_fwd_rule\n+ * @hw: pointer to the hardware structure\n+ * @rule_id: rule of previously created switch rule to update\n+ * @vsi_list_id: VSI list id to be updated with\n+ * @f_info: ice_fltr_info to pull other 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, u16 rule_id, u16 vsi_list_id,\n+\t\t\tstruct ice_fltr_info f_info)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\tstruct ice_fltr_info tmp_fltr;\n+\tenum ice_status status;\n+\n+\ts_rule = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\ttmp_fltr = f_info;\n+\ttmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;\n+\ttmp_fltr.fwd_id.vsi_list_id = vsi_list_id;\n+\n+\tice_fill_sw_rule(hw, &tmp_fltr, s_rule,\n+\t\t\t ice_aqc_opc_update_sw_rules);\n+\n+\ts_rule->pdata.lkup_tx_rx.index = cpu_to_le16(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+\tdevm_kfree(ice_hw_to_dev(hw), s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_handle_vsi_list_mgmt\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 booking 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_handle_vsi_list_mgmt(struct ice_hw *hw,\n+\t\t\t struct ice_fltr_mgmt_list_entry *m_entry,\n+\t\t\t struct ice_fltr_info *cur_fltr,\n+\t\t\t struct ice_fltr_info *new_fltr)\n+{\n+\tenum ice_status status = 0;\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\tu16 vsi_id_arr[2];\n+\t\tu16 fltr_rule;\n+\n+\t\t/* A rule already exists with the new VSI being added */\n+\t\tif (cur_fltr->fwd_id.vsi_id == new_fltr->fwd_id.vsi_id)\n+\t\t\treturn ICE_ERR_ALREADY_EXISTS;\n+\n+\t\tvsi_id_arr[0] = cur_fltr->fwd_id.vsi_id;\n+\t\tvsi_id_arr[1] = new_fltr->fwd_id.vsi_id;\n+\t\tstatus = ice_create_vsi_list_rule(hw, &vsi_id_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\tfltr_rule = cur_fltr->fltr_rule_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, fltr_rule, vsi_list_id,\n+\t\t\t\t\t\t *new_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_id_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_id = new_fltr->fwd_id.vsi_id;\n+\t\tenum ice_adminq_opc opcode;\n+\n+\t\t/* A rule already exists with the new VSI being added */\n+\t\tif (test_bit(vsi_id, m_entry->vsi_list_info->vsi_map))\n+\t\t\treturn 0;\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_id, 1, vsi_list_id,\n+\t\t\t\t\t\t  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\tset_bit(vsi_id, 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_mac_entry\n+ * @hw: pointer to the hardware structure\n+ * @mac_addr: MAC address to search for\n+ *\n+ * Helper function to search for a MAC entry using a given MAC address\n+ * Returns pointer to the entry if found.\n+ */\n+static struct ice_fltr_mgmt_list_entry *\n+ice_find_mac_entry(struct ice_hw *hw, u8 *mac_addr)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *m_list_itr, *mac_ret = NULL;\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\n+\tmutex_lock(&sw->mac_list_lock);\n+\tlist_for_each_entry(m_list_itr, &sw->mac_list_head, list_entry) {\n+\t\tu8 *buf = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];\n+\n+\t\tif (ether_addr_equal(buf, mac_addr)) {\n+\t\t\tmac_ret = m_list_itr;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tmutex_unlock(&sw->mac_list_lock);\n+\treturn mac_ret;\n+}\n+\n+/**\n+ * ice_add_shared_mac - Add one MAC shared filter rule\n+ * @hw: pointer to the hardware structure\n+ * @f_entry: structure containing MAC forwarding information\n+ *\n+ * Adds or updates the book keeping list for the MAC addresses\n+ */\n+static enum ice_status\n+ice_add_shared_mac(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_fltr_info *new_fltr, *cur_fltr;\n+\tstruct ice_fltr_mgmt_list_entry *m_entry;\n+\n+\tnew_fltr = &f_entry->fltr_info;\n+\n+\tm_entry = ice_find_mac_entry(hw, &new_fltr->l_data.mac.mac_addr[0]);\n+\tif (!m_entry)\n+\t\treturn ice_create_pkt_fwd_rule(hw, f_entry);\n+\n+\tcur_fltr = &m_entry->fltr_info;\n+\n+\treturn ice_handle_vsi_list_mgmt(hw, m_entry, cur_fltr, new_fltr);\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 *m_list)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule, *r_iter;\n+\tstruct ice_fltr_list_entry *m_list_itr;\n+\tu16 elem_sent, total_elem_left;\n+\tenum ice_status status = 0;\n+\tu16 num_unicast = 0;\n+\tu16 s_rule_size;\n+\n+\tif (!m_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tlist_for_each_entry(m_list_itr, m_list, list_entry) {\n+\t\tu8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];\n+\n+\t\tif (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC)\n+\t\t\treturn ICE_ERR_PARAM;\n+\t\tif (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\tif (ice_find_mac_entry(hw, add))\n+\t\t\t\treturn ICE_ERR_ALREADY_EXISTS;\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\tstatus = ice_add_shared_mac(hw, m_list_itr);\n+\t\t\tif (status) {\n+\t\t\t\tm_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;\n+\t\t\t\treturn status;\n+\t\t\t}\n+\t\t\tm_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;\n+\t\t}\n+\t}\n+\n+\t/* Exit if no suitable entries were found for adding bulk switch rule */\n+\tif (!num_unicast)\n+\t\treturn 0;\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 = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,\n+\t\t\t      GFP_KERNEL);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tr_iter = s_rule;\n+\tlist_for_each_entry(m_list_itr, m_list, list_entry) {\n+\t\tstruct ice_fltr_info *f_info = &m_list_itr->fltr_info;\n+\t\tu8 *addr = &f_info->l_data.mac.mac_addr[0];\n+\n+\t\tif (is_unicast_ether_addr(addr)) {\n+\t\t\tice_fill_sw_rule(hw, &m_list_itr->fltr_info,\n+\t\t\t\t\t r_iter, 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, list_entry) {\n+\t\tstruct ice_fltr_info *f_info = &m_list_itr->fltr_info;\n+\t\tu8 *addr = &f_info->l_data.mac.mac_addr[0];\n+\t\tstruct ice_switch_info *sw = hw->switch_info;\n+\t\tstruct ice_fltr_mgmt_list_entry *fm_entry;\n+\n+\t\tif (is_unicast_ether_addr(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 = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t\t\t\tsizeof(*fm_entry), GFP_KERNEL);\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+\t\t\tmutex_lock(&sw->mac_list_lock);\n+\t\t\tlist_add(&fm_entry->list_entry, &sw->mac_list_head);\n+\t\t\tmutex_unlock(&sw->mac_list_lock);\n+\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+\tdevm_kfree(ice_hw_to_dev(hw), s_rule);\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+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 = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);\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+\t/* FW expects number of VSIs in vsi_list resource to be 0 for clear\n+\t * command. Since memory is zero'ed out during initialization, it's not\n+\t * necessary to explicitly initialize the variable to 0.\n+\t */\n+\n+\tstatus = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1,\n+\t\t\t\t ice_aqc_opc_remove_sw_rules, NULL);\n+\tif (!status)\n+\t\t/* Free the vsi_list resource that we allocated */\n+\t\tstatus = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,\n+\t\t\t\t\t\t    ice_aqc_opc_free_res);\n+\n+\tdevm_kfree(ice_hw_to_dev(hw), s_rule);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_handle_rem_vsi_list_mgmt\n+ * @hw: pointer to the hardware structure\n+ * @vsi_id: ID of the VSI to remove\n+ * @fm_list_itr: filter management entry for which the VSI list management\n+ * needs to be done\n+ */\n+static enum ice_status\n+ice_handle_rem_vsi_list_mgmt(struct ice_hw *hw, u16 vsi_id,\n+\t\t\t     struct ice_fltr_mgmt_list_entry *fm_list_itr)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tenum ice_status status = 0;\n+\tenum ice_sw_lkup_type lkup_type;\n+\tbool is_last_elem = true;\n+\tbool conv_list = false;\n+\tbool del_list = false;\n+\tu16 vsi_list_id;\n+\n+\tlkup_type = fm_list_itr->fltr_info.lkup_type;\n+\tvsi_list_id = fm_list_itr->fltr_info.fwd_id.vsi_list_id;\n+\n+\tif (fm_list_itr->vsi_count > 1) {\n+\t\tstatus = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id,\n+\t\t\t\t\t\t  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+\t\tfm_list_itr->vsi_count--;\n+\t\tis_last_elem = false;\n+\t\tclear_bit(vsi_id, fm_list_itr->vsi_list_info->vsi_map);\n+\t}\n+\n+\t/* For non-VLAN rules that forward packets to a VSI list, convert them\n+\t * to forwarding packets to a VSI if there is only one VSI left in the\n+\t * list.  Unused lists are then removed.\n+\t * VLAN rules need to use VSI lists even with only one VSI.\n+\t */\n+\tif (fm_list_itr->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST) {\n+\t\tif (lkup_type == ICE_SW_LKUP_VLAN) {\n+\t\t\tdel_list = is_last_elem;\n+\t\t} else if (fm_list_itr->vsi_count == 1) {\n+\t\t\tconv_list = true;\n+\t\t\tdel_list = true;\n+\t\t}\n+\t}\n+\n+\tif (del_list) {\n+\t\t/* Remove the VSI list since it is no longer used */\n+\t\tstruct ice_vsi_list_map_info *vsi_list_info =\n+\t\t\tfm_list_itr->vsi_list_info;\n+\n+\t\tstatus = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\tif (conv_list) {\n+\t\t\tu16 rem_vsi_id;\n+\n+\t\t\trem_vsi_id = find_first_bit(vsi_list_info->vsi_map,\n+\t\t\t\t\t\t    ICE_MAX_VSI);\n+\n+\t\t\t/* Error out when the expected last element is not in\n+\t\t\t * the VSI list map\n+\t\t\t */\n+\t\t\tif (rem_vsi_id == ICE_MAX_VSI)\n+\t\t\t\treturn ICE_ERR_OUT_OF_RANGE;\n+\n+\t\t\t/* Change the list entry action from VSI_LIST to VSI */\n+\t\t\tfm_list_itr->fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\t\t\tfm_list_itr->fltr_info.fwd_id.vsi_id = rem_vsi_id;\n+\t\t}\n+\n+\t\tlist_del(&vsi_list_info->list_entry);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), vsi_list_info);\n+\t\tfm_list_itr->vsi_list_info = NULL;\n+\t}\n+\n+\tif (conv_list) {\n+\t\t/* Convert the rule's forward action to forwarding packets to\n+\t\t * a VSI\n+\t\t */\n+\t\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\n+\t\ts_rule = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t\t      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE,\n+\t\t\t\t      GFP_KERNEL);\n+\t\tif (!s_rule)\n+\t\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t\tice_fill_sw_rule(hw, &fm_list_itr->fltr_info, s_rule,\n+\t\t\t\t ice_aqc_opc_update_sw_rules);\n+\n+\t\ts_rule->pdata.lkup_tx_rx.index =\n+\t\t\tcpu_to_le16(fm_list_itr->fltr_info.fltr_rule_id);\n+\n+\t\tstatus = ice_aq_sw_rules(hw, s_rule,\n+\t\t\t\t\t ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,\n+\t\t\t\t\t ice_aqc_opc_update_sw_rules, NULL);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), s_rule);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\tif (is_last_elem) {\n+\t\t/* Remove the lookup rule */\n+\t\tstruct ice_aqc_sw_rules_elem *s_rule;\n+\n+\t\ts_rule = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t\t      ICE_SW_RULE_RX_TX_NO_HDR_SIZE,\n+\t\t\t\t      GFP_KERNEL);\n+\t\tif (!s_rule)\n+\t\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t\tice_fill_sw_rule(hw, &fm_list_itr->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\treturn status;\n+\n+\t\t/* Remove a book keeping entry from the MAC address list */\n+\t\tmutex_lock(&sw->mac_list_lock);\n+\t\tlist_del(&fm_list_itr->list_entry);\n+\t\tmutex_unlock(&sw->mac_list_lock);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), fm_list_itr);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), s_rule);\n+\t}\n+\treturn status;\n+}\n+\n+/**\n+ * ice_remove_mac_entry\n+ * @hw: pointer to the hardware structure\n+ * @f_entry: structure containing MAC forwarding information\n+ */\n+static enum ice_status\n+ice_remove_mac_entry(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *m_entry;\n+\tu16 vsi_id;\n+\tu8 *add;\n+\n+\tadd = &f_entry->fltr_info.l_data.mac.mac_addr[0];\n+\n+\tm_entry = ice_find_mac_entry(hw, add);\n+\tif (!m_entry)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tvsi_id = f_entry->fltr_info.fwd_id.vsi_id;\n+\treturn ice_handle_rem_vsi_list_mgmt(hw, vsi_id, m_entry);\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 *m_list)\n+{\n+\tstruct ice_aqc_sw_rules_elem *s_rule, *r_iter;\n+\tu8 s_rule_size = ICE_SW_RULE_RX_TX_NO_HDR_SIZE;\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tstruct ice_fltr_mgmt_list_entry *m_entry;\n+\tstruct ice_fltr_list_entry *m_list_itr;\n+\tu16 elem_sent, total_elem_left;\n+\tenum ice_status status = 0;\n+\tu16 num_unicast = 0;\n+\n+\tif (!m_list)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tlist_for_each_entry(m_list_itr, m_list, list_entry) {\n+\t\tu8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr;\n+\n+\t\tif (is_unicast_ether_addr(addr) && !hw->ucast_shared)\n+\t\t\tnum_unicast++;\n+\t\telse if (is_multicast_ether_addr(addr) ||\n+\t\t\t (is_unicast_ether_addr(addr) && hw->ucast_shared))\n+\t\t\tice_remove_mac_entry(hw, m_list_itr);\n+\t}\n+\n+\t/* Exit if no unicast addresses found. Multicast switch rules\n+\t * were added individually\n+\t */\n+\tif (!num_unicast)\n+\t\treturn 0;\n+\n+\t/* Allocate switch rule buffer for the bulk update for unicast */\n+\ts_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,\n+\t\t\t      GFP_KERNEL);\n+\tif (!s_rule)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tr_iter = s_rule;\n+\tlist_for_each_entry(m_list_itr, m_list, list_entry) {\n+\t\tu8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr;\n+\n+\t\tif (is_unicast_ether_addr(addr)) {\n+\t\t\tm_entry = ice_find_mac_entry(hw, addr);\n+\t\t\tif (!m_entry) {\n+\t\t\t\tstatus = ICE_ERR_DOES_NOT_EXIST;\n+\t\t\t\tgoto ice_remove_mac_exit;\n+\t\t\t}\n+\n+\t\t\tice_fill_sw_rule(hw, &m_entry->fltr_info,\n+\t\t\t\t\t r_iter, ice_aqc_opc_remove_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_remove_sw_rules,\n+\t\t\t\t\t NULL);\n+\t\tif (status)\n+\t\t\tbreak;\n+\t\tr_iter = (struct ice_aqc_sw_rules_elem *)\n+\t\t\t((u8 *)r_iter + s_rule_size);\n+\t}\n+\n+\tlist_for_each_entry(m_list_itr, m_list, list_entry) {\n+\t\tu8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr;\n+\n+\t\tif (is_unicast_ether_addr(addr)) {\n+\t\t\tm_entry = ice_find_mac_entry(hw, addr);\n+\t\t\tif (!m_entry)\n+\t\t\t\treturn ICE_ERR_OUT_OF_RANGE;\n+\t\t\tmutex_lock(&sw->mac_list_lock);\n+\t\t\tlist_del(&m_entry->list_entry);\n+\t\t\tmutex_unlock(&sw->mac_list_lock);\n+\t\t\tdevm_kfree(ice_hw_to_dev(hw), m_entry);\n+\t\t}\n+\t}\n+\n+ice_remove_mac_exit:\n+\tdevm_kfree(ice_hw_to_dev(hw), s_rule);\n+\treturn status;\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_id: ID of VSI 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_id\n+ */\n+static enum ice_status\n+ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id,\n+\t\t\t struct list_head *lkup_list_head,\n+\t\t\t struct list_head *vsi_list_head)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *fm_entry;\n+\n+\t/* check to make sure VSI id is valid and within boundary */\n+\tif (vsi_id >=\n+\t    (sizeof(fm_entry->vsi_list_info->vsi_map) * BITS_PER_BYTE - 1))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tlist_for_each_entry(fm_entry, lkup_list_head, list_entry) {\n+\t\tstruct ice_fltr_info *fi;\n+\n+\t\tfi = &fm_entry->fltr_info;\n+\t\tif ((fi->fltr_act == ICE_FWD_TO_VSI &&\n+\t\t     fi->fwd_id.vsi_id == vsi_id) ||\n+\t\t    (fi->fltr_act == ICE_FWD_TO_VSI_LIST &&\n+\t\t     (test_bit(vsi_id, fm_entry->vsi_list_info->vsi_map)))) {\n+\t\t\tstruct ice_fltr_list_entry *tmp;\n+\n+\t\t\t/* this memory is freed up in the caller function\n+\t\t\t * ice_remove_vsi_lkup_fltr() once filters for\n+\t\t\t * this VSI are removed\n+\t\t\t */\n+\t\t\ttmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp),\n+\t\t\t\t\t   GFP_KERNEL);\n+\t\t\tif (!tmp)\n+\t\t\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t\t\tmemcpy(&tmp->fltr_info, fi, sizeof(*fi));\n+\n+\t\t\t/* Expected below fields to be set to ICE_FWD_TO_VSI and\n+\t\t\t * the particular VSI id since we are only removing this\n+\t\t\t * one VSI\n+\t\t\t */\n+\t\t\tif (fi->fltr_act == ICE_FWD_TO_VSI_LIST) {\n+\t\t\t\ttmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\t\t\t\ttmp->fltr_info.fwd_id.vsi_id = vsi_id;\n+\t\t\t}\n+\n+\t\t\tlist_add(&tmp->list_entry, vsi_list_head);\n+\t\t}\n+\t}\n+\treturn 0;\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_id: ID of VSI 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_id,\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 remove_list_head;\n+\tstruct ice_fltr_list_entry *tmp;\n+\tenum ice_status status;\n+\n+\tINIT_LIST_HEAD(&remove_list_head);\n+\tswitch (lkup) {\n+\tcase ICE_SW_LKUP_MAC:\n+\t\tmutex_lock(&sw->mac_list_lock);\n+\t\tstatus = ice_add_to_vsi_fltr_list(hw, vsi_id,\n+\t\t\t\t\t\t  &sw->mac_list_head,\n+\t\t\t\t\t\t  &remove_list_head);\n+\t\tmutex_unlock(&sw->mac_list_lock);\n+\t\tif (!status) {\n+\t\t\tice_remove_mac(hw, &remove_list_head);\n+\t\t\tgoto free_fltr_list;\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_SW_LKUP_VLAN:\n+\tcase ICE_SW_LKUP_MAC_VLAN:\n+\tcase ICE_SW_LKUP_ETHERTYPE:\n+\tcase ICE_SW_LKUP_ETHERTYPE_MAC:\n+\tcase ICE_SW_LKUP_PROMISC:\n+\tcase ICE_SW_LKUP_PROMISC_VLAN:\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+\t}\n+\n+\treturn;\n+free_fltr_list:\n+\tlist_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {\n+\t\tlist_del(&fm_entry->list_entry);\n+\t\tdevm_kfree(ice_hw_to_dev(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_id: ID of VSI to remove filters from\n+ */\n+void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id)\n+{\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC_VLAN);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_VLAN);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_DFLT);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE_MAC);\n+\tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC_VLAN);\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h\nindex d04ff160df70..8039a8e38331 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.h\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.h\n@@ -33,6 +33,122 @@ struct ice_vsi_ctx {\n \tbool alloc_from_pool;\n };\n \n+enum ice_sw_fwd_act_type {\n+\tICE_FWD_TO_VSI = 0,\n+\tICE_FWD_TO_VSI_LIST, /* Do not use this when adding filter */\n+\tICE_FWD_TO_Q,\n+\tICE_FWD_TO_QGRP,\n+\tICE_DROP_PACKET,\n+\tICE_INVAL_ACT\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+};\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+\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;\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 vsi_id:10;\n+\t\tu16 vsi_list_id:10;\n+\t} fwd_id;\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 */\n+\tu8 qgrp_size;\n+\n+\t/* Rule creations populate these indicators basing on the switch type */\n+\tbool lb_en;\t/* Indicate if packet can be looped back */\n+\tbool lan_en;\t/* Indicate if packet can be forwarded to the uplink */\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_head list_entry;\n+\tDECLARE_BITMAP(vsi_map, ICE_MAX_VSI);\n+\tu16 vsi_list_id;\n+};\n+\n+enum ice_sw_fltr_status {\n+\tICE_FLTR_STATUS_NEW = 0,\n+\tICE_FLTR_STATUS_FW_SUCCESS,\n+\tICE_FLTR_STATUS_FW_FAIL,\n+};\n+\n+struct ice_fltr_list_entry {\n+\tstruct list_head list_entry;\n+\tenum ice_sw_fltr_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 VLAN address.\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_head list_entry;\n+\tstruct ice_fltr_info fltr_info;\n+#define ICE_INVAL_COUNTER_ID 0xff\n+\tu8 counter_index;\n+};\n+\n /* VSI related commands */\n enum ice_status\n ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n@@ -46,4 +162,8 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n \n enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);\n \n+/* Switch/bridge related commands */\n+enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);\n+enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);\n+void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id);\n #endif /* _ICE_SWITCH_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h\nindex 8bfd9ff7edda..796c3d0a3c47 100644\n--- a/drivers/net/ethernet/intel/ice/ice_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_type.h\n@@ -237,6 +237,22 @@ struct ice_port_info {\n \tbool is_vf;\n };\n \n+struct ice_switch_info {\n+\t/* Switch VSI lists to MAC/VLAN translation */\n+\tstruct mutex mac_list_lock;\t\t/* protect MAC list */\n+\tstruct list_head mac_list_head;\n+\tstruct mutex vlan_list_lock;\t\t/* protect VLAN list */\n+\tstruct list_head vlan_list_head;\n+\tstruct mutex eth_m_list_lock;\t/* protect ethtype list */\n+\tstruct list_head eth_m_list_head;\n+\tstruct mutex promisc_list_lock;\t/* protect promisc mode list */\n+\tstruct list_head promisc_list_head;\n+\tstruct mutex mac_vlan_list_lock;\t/* protect MAC-VLAN list */\n+\tstruct list_head mac_vlan_list_head;\n+\n+\tstruct list_head vsi_list_map_head;\n+};\n+\n /* Port hardware description */\n struct ice_hw {\n \tu8 __iomem *hw_addr;\n@@ -262,11 +278,14 @@ struct ice_hw {\n \tu8 max_cgds;\n \tu8 sw_entry_point_layer;\n \n+\tbool evb_veb;\t\t/* true for VEB, false for VEPA */\n \tstruct ice_bus_info bus;\n \tstruct ice_nvm_info nvm;\n \tstruct ice_hw_dev_caps dev_caps;\t/* device capabilities */\n \tstruct ice_hw_func_caps func_caps;\t/* function capabilities */\n \n+\tstruct ice_switch_info *switch_info;\t/* switch filter lists */\n+\n \t/* Control Queue info */\n \tstruct ice_ctl_q_info adminq;\n \n@@ -290,6 +309,8 @@ struct ice_hw {\n \tu8 itr_gran_100;\n \tu8 itr_gran_50;\n \tu8 itr_gran_25;\n+\tbool ucast_shared;\t/* true if VSIs can share unicast addr */\n+\n };\n \n /* Checksum and Shadow RAM pointers */\n",
    "prefixes": [
        "v3",
        "08/15"
    ]
}