get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1288152,
    "url": "http://patchwork.ozlabs.org/api/patches/1288152/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20200512010146.41303-1-anthony.l.nguyen@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": "<20200512010146.41303-1-anthony.l.nguyen@intel.com>",
    "list_archive_url": null,
    "date": "2020-05-12T01:01:40",
    "name": "[S42,1/7] ice: Initialize Flow Director resources",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "de128a46a2b4eeecd546c4467ea59f08db594bf6",
    "submitter": {
        "id": 68875,
        "url": "http://patchwork.ozlabs.org/api/people/68875/?format=api",
        "name": "Tony Nguyen",
        "email": "anthony.l.nguyen@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/20200512010146.41303-1-anthony.l.nguyen@intel.com/mbox/",
    "series": [
        {
            "id": 176248,
            "url": "http://patchwork.ozlabs.org/api/series/176248/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=176248",
            "date": "2020-05-12T01:01:45",
            "name": "[S42,1/7] ice: Initialize Flow Director resources",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/176248/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1288152/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1288152/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 spf=pass (sender SPF authorized) smtp.mailfrom=osuosl.org\n (client-ip=140.211.166.133; helo=hemlock.osuosl.org;\n envelope-from=intel-wired-lan-bounces@osuosl.org; receiver=<UNKNOWN>)",
            "ozlabs.org;\n dmarc=fail (p=none dis=none) header.from=intel.com"
        ],
        "Received": [
            "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 49Lfj96wpBz9sRf\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 12 May 2020 11:04:45 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 3AF29887A5;\n\tTue, 12 May 2020 01:04:44 +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 zF4DeqejufV6; Tue, 12 May 2020 01:04:37 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id D724C886A3;\n\tTue, 12 May 2020 01:04:37 +0000 (UTC)",
            "from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n by ash.osuosl.org (Postfix) with ESMTP id 319AD1BF2C2\n for <intel-wired-lan@lists.osuosl.org>; Tue, 12 May 2020 01:04:36 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by whitealder.osuosl.org (Postfix) with ESMTP id 153A186BC9\n for <intel-wired-lan@lists.osuosl.org>; Tue, 12 May 2020 01:04:36 +0000 (UTC)",
            "from whitealder.osuosl.org ([127.0.0.1])\n by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id nK3U-WK6x5uX for <intel-wired-lan@lists.osuosl.org>;\n Tue, 12 May 2020 01:04:20 +0000 (UTC)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n by whitealder.osuosl.org (Postfix) with ESMTPS id 0BF8986788\n for <intel-wired-lan@lists.osuosl.org>; Tue, 12 May 2020 01:04:19 +0000 (UTC)",
            "from orsmga004.jf.intel.com ([10.7.209.38])\n by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 11 May 2020 18:04:19 -0700",
            "from unknown (HELO localhost.jf.intel.com) ([10.166.241.65])\n by orsmga004.jf.intel.com with ESMTP; 11 May 2020 18:04:18 -0700"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6",
        "IronPort-SDR": [
            "\n NqXAUx+8YrEF14rS5k0CaiE7TzKu+6xCaU3N4IWxp0ZeTRHL2vlm9n8KYkwZRAHzbyp4JiiNNK\n aDwnt88ohsiw==",
            "\n GJTwt8fo4uWb3sut2nL+xPJ+huZEwhzaoHiLgPQPl5s8ZkDG/riIz4Am2VEOzk9lsVpkYqXPJ/\n XL/2pq2Q6dSg=="
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.73,381,1583222400\"; d=\"scan'208\";a=\"409116462\"",
        "From": "Tony Nguyen <anthony.l.nguyen@intel.com>",
        "To": "intel-wired-lan@lists.osuosl.org",
        "Date": "Mon, 11 May 2020 18:01:40 -0700",
        "Message-Id": "<20200512010146.41303-1-anthony.l.nguyen@intel.com>",
        "X-Mailer": "git-send-email 2.20.1",
        "MIME-Version": "1.0",
        "Subject": "[Intel-wired-lan] [PATCH S42 1/7] ice: Initialize Flow Director\n resources",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n <intel-wired-lan.osuosl.org>",
        "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>,\n <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 <mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>",
        "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: Henry Tieman <henry.w.tieman@intel.com>\n\nFlow Director allows for redirection based on ntuple rules. Rules are\nprogrammed using the ethtool set-ntuple interface. Supported actions are\nredirect to queue and drop.\n\nSetup the initial framework to process Flow Director filters. Create and\nallocate resources to manage and program filters to the hardware. Filters\nare processed via a sideband interface; a control VSI is created to manage\ncommunication and process requests through the sideband. Upon allocation of\nresources, update the hardware tables to accept perfect filters.\n\nSigned-off-by: Henry Tieman <henry.w.tieman@intel.com>\nSigned-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>\n---\n drivers/net/ethernet/intel/ice/Makefile       |   2 +\n drivers/net/ethernet/intel/ice/ice.h          |  24 ++\n .../net/ethernet/intel/ice/ice_adminq_cmd.h   |   9 +\n drivers/net/ethernet/intel/ice/ice_base.c     |   1 +\n drivers/net/ethernet/intel/ice/ice_common.c   |  36 ++\n drivers/net/ethernet/intel/ice/ice_ethtool.c  |  11 +-\n .../net/ethernet/intel/ice/ice_ethtool_fdir.c | 399 ++++++++++++++++++\n drivers/net/ethernet/intel/ice/ice_fdir.c     |  54 +++\n drivers/net/ethernet/intel/ice/ice_fdir.h     |  12 +\n .../net/ethernet/intel/ice/ice_flex_pipe.c    | 224 ++++++++++\n drivers/net/ethernet/intel/ice/ice_flow.c     | 169 +++++++-\n drivers/net/ethernet/intel/ice/ice_flow.h     |  32 +-\n .../net/ethernet/intel/ice/ice_hw_autogen.h   |  11 +\n drivers/net/ethernet/intel/ice/ice_lib.c      | 210 +++++++--\n drivers/net/ethernet/intel/ice/ice_lib.h      |   2 +\n drivers/net/ethernet/intel/ice/ice_main.c     | 160 ++++++-\n .../ethernet/intel/ice/ice_protocol_type.h    |   1 +\n drivers/net/ethernet/intel/ice/ice_switch.c   |  75 ++++\n drivers/net/ethernet/intel/ice/ice_switch.h   |   7 +\n drivers/net/ethernet/intel/ice/ice_txrx.c     | 100 ++++-\n drivers/net/ethernet/intel/ice/ice_txrx.h     |   7 +-\n drivers/net/ethernet/intel/ice/ice_type.h     |  45 +-\n 22 files changed, 1552 insertions(+), 39 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c\n create mode 100644 drivers/net/ethernet/intel/ice/ice_fdir.c\n create mode 100644 drivers/net/ethernet/intel/ice/ice_fdir.h",
    "diff": "diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile\nindex 0d9741cf000c..8bda3796a853 100644\n--- a/drivers/net/ethernet/intel/ice/Makefile\n+++ b/drivers/net/ethernet/intel/ice/Makefile\n@@ -18,6 +18,8 @@ ice-y := ice_main.o\t\\\n \t ice_txrx_lib.o\t\\\n \t ice_txrx.o\t\\\n \t ice_fltr.o\t\\\n+\t ice_fdir.o\t\\\n+\t ice_ethtool_fdir.o \\\n \t ice_flex_pipe.o \\\n \t ice_flow.o\t\\\n \t ice_devlink.o\t\\\ndiff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex adb4f1366e9f..a070ddcc2cb3 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -51,6 +51,7 @@\n #include \"ice_idc_int.h\"\n #include \"ice_virtchnl_pf.h\"\n #include \"ice_sriov.h\"\n+#include \"ice_fdir.h\"\n #include \"ice_xsk.h\"\n \n extern const char ice_drv_ver[];\n@@ -67,6 +68,7 @@ extern const char ice_drv_ver[];\n #define ICE_AQ_LEN\t\t64\n #define ICE_MBXSQ_LEN\t\t64\n #define ICE_MIN_MSIX\t\t2\n+#define ICE_FDIR_MSIX\t\t1\n #define ICE_NO_VSI\t\t0xffff\n #define ICE_VSI_MAP_CONTIG\t0\n #define ICE_VSI_MAP_SCATTER\t1\n@@ -260,6 +262,8 @@ struct ice_vsi {\n \ts16 vf_id;\t\t\t/* VF ID for SR-IOV VSIs */\n \n \tu16 ethtype;\t\t\t/* Ethernet protocol for pause frame */\n+\tu16 num_gfltr;\n+\tu16 num_bfltr;\n \n \t/* RSS config */\n \tu16 rss_table_size;\t/* HW RSS table size */\n@@ -344,6 +348,7 @@ enum ice_pf_flags {\n \tICE_FLAG_SRIOV_CAPABLE,\n \tICE_FLAG_DCB_CAPABLE,\n \tICE_FLAG_DCB_ENA,\n+\tICE_FLAG_FD_ENA,\n \tICE_FLAG_PEER_ENA,\n \tICE_FLAG_ADV_FEATURES,\n \tICE_FLAG_LINK_DOWN_ON_CLOSE_ENA,\n@@ -373,6 +378,8 @@ struct ice_pf {\n \t */\n \tu16 sriov_base_vector;\n \n+\tu16 ctrl_vsi_idx;\t\t/* control VSI index in pf->vsi array */\n+\n \tstruct ice_vsi **vsi;\t\t/* VSIs created by the driver */\n \tstruct ice_sw *first_sw;\t/* first switch created by firmware */\n \t/* Virtchnl/SR-IOV config info */\n@@ -515,8 +522,22 @@ static inline struct ice_vsi *ice_get_main_vsi(struct ice_pf *pf)\n \treturn NULL;\n }\n \n+/**\n+ * ice_get_ctrl_vsi - Get the control VSI\n+ * @pf: PF instance\n+ */\n+static inline struct ice_vsi *ice_get_ctrl_vsi(struct ice_pf *pf)\n+{\n+\t/* if pf->ctrl_vsi_idx is ICE_NO_VSI, control VSI was not set up */\n+\tif (!pf->vsi || pf->ctrl_vsi_idx == ICE_NO_VSI)\n+\t\treturn NULL;\n+\n+\treturn pf->vsi[pf->ctrl_vsi_idx];\n+}\n+\n int ice_vsi_setup_tx_rings(struct ice_vsi *vsi);\n int ice_vsi_setup_rx_rings(struct ice_vsi *vsi);\n+int ice_vsi_open_ctrl(struct ice_vsi *vsi);\n void ice_set_ethtool_ops(struct net_device *netdev);\n void ice_set_ethtool_safe_mode_ops(struct net_device *netdev);\n u16 ice_get_avail_txq_count(struct ice_pf *pf);\n@@ -544,6 +565,9 @@ ice_for_each_peer(struct ice_pf *pf, void *data,\n \t\t  int (*fn)(struct ice_peer_dev_int *, void *));\n const char *ice_stat_str(enum ice_status stat_err);\n const char *ice_aq_str(enum ice_aq_err aq_err);\n+void ice_vsi_manage_fdir(struct ice_vsi *vsi, bool ena);\n+void ice_fdir_release_flows(struct ice_hw *hw);\n+int ice_fdir_create_dflt_rules(struct ice_pf *pf);\n int ice_open(struct net_device *netdev);\n int ice_stop(struct net_device *netdev);\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 6988727ce82c..745f58a86a1d 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -107,6 +107,7 @@ struct ice_aqc_list_caps_elem {\n #define ICE_AQC_CAPS_RXQS\t\t\t\t0x0041\n #define ICE_AQC_CAPS_TXQS\t\t\t\t0x0042\n #define ICE_AQC_CAPS_MSIX\t\t\t\t0x0043\n+#define ICE_AQC_CAPS_FD\t\t\t\t\t0x0045\n #define ICE_AQC_CAPS_MAX_MTU\t\t\t\t0x0047\n #define ICE_AQC_CAPS_IWARP\t\t\t\t0x0051\n \n@@ -233,6 +234,11 @@ struct ice_aqc_get_sw_cfg_resp {\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+#define ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK\t\t0x21\n+#define ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES\t0x22\n+#define ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES\t\t0x23\n+#define ICE_AQC_RES_TYPE_FD_PROF_BLDR_PROFID\t\t0x58\n+#define ICE_AQC_RES_TYPE_FD_PROF_BLDR_TCAM\t\t0x59\n #define ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID\t\t0x60\n #define ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM\t\t0x61\n \n@@ -241,6 +247,9 @@ struct ice_aqc_get_sw_cfg_resp {\n \n #define ICE_AQC_RES_TYPE_FLAG_DEDICATED\t\t\t0x00\n \n+#define ICE_AQC_RES_TYPE_S\t0\n+#define ICE_AQC_RES_TYPE_M\t(0x07F << ICE_AQC_RES_TYPE_S)\n+\n /* Allocate Resources command (indirect 0x0208)\n  * Free Resources command (indirect 0x0209)\n  */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c\nindex 4c835c144907..00c072f61a32 100644\n--- a/drivers/net/ethernet/intel/ice/ice_base.c\n+++ b/drivers/net/ethernet/intel/ice/ice_base.c\n@@ -246,6 +246,7 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q)\n \t */\n \tswitch (vsi->type) {\n \tcase ICE_VSI_LB:\n+\tcase ICE_VSI_CTRL:\n \tcase ICE_VSI_PF:\n \t\ttlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF;\n \t\tbreak;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex 0caa2df94ceb..aa3cad00a78a 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -653,6 +653,10 @@ enum ice_status ice_init_hw(struct ice_hw *hw)\n \tif (status)\n \t\tgoto err_unroll_cqinit;\n \n+\t/* Set bit to enable Flow Director filters */\n+\twr32(hw, PFQF_FD_ENA, PFQF_FD_ENA_FD_ENA_M);\n+\tINIT_LIST_HEAD(&hw->fdir_list_head);\n+\n \tice_clear_pxe_mode(hw);\n \n \tstatus = ice_init_nvm(hw);\n@@ -741,6 +745,10 @@ enum ice_status ice_init_hw(struct ice_hw *hw)\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_fltr_mgmt_struct;\n+\t/* Obtain counter base index which would be used by flow director */\n+\tstatus = ice_alloc_fd_res_cntr(hw, &hw->fd_ctr_base);\n \tif (status)\n \t\tgoto err_unroll_fltr_mgmt_struct;\n \tstatus = ice_init_hw_tbls(hw);\n@@ -770,6 +778,7 @@ enum ice_status ice_init_hw(struct ice_hw *hw)\n  */\n void ice_deinit_hw(struct ice_hw *hw)\n {\n+\tice_free_fd_res_cntr(hw, hw->fd_ctr_base);\n \tice_cleanup_fltr_mgmt_struct(hw);\n \n \tice_sched_cleanup_all(hw);\n@@ -1681,6 +1690,33 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,\n \t\t\t\t  \"%s: msix_vector_first_id = %d\\n\", prefix,\n \t\t\t\t  caps->msix_vector_first_id);\n \t\t\tbreak;\n+\t\tcase ICE_AQC_CAPS_FD:\n+\t\t\tif (dev_p) {\n+\t\t\t\tdev_p->num_flow_director_fltr = number;\n+\t\t\t\tice_debug(hw, ICE_DBG_INIT,\n+\t\t\t\t\t  \"%s: num_flow_director_fltr = %d\\n\",\n+\t\t\t\t\t  prefix,\n+\t\t\t\t\t  dev_p->num_flow_director_fltr);\n+\t\t\t}\n+\t\t\tif (func_p) {\n+\t\t\t\tu32 reg_val, val;\n+\n+\t\t\t\treg_val = rd32(hw, GLQF_FD_SIZE);\n+\t\t\t\tval = (reg_val & GLQF_FD_SIZE_FD_GSIZE_M) >>\n+\t\t\t\t      GLQF_FD_SIZE_FD_GSIZE_S;\n+\t\t\t\tfunc_p->fd_fltr_guar =\n+\t\t\t\t\tice_get_num_per_func(hw, val);\n+\t\t\t\tval = (reg_val & GLQF_FD_SIZE_FD_BSIZE_M) >>\n+\t\t\t\t      GLQF_FD_SIZE_FD_BSIZE_S;\n+\t\t\t\tfunc_p->fd_fltr_best_effort = val;\n+\t\t\t\tice_debug(hw, ICE_DBG_INIT,\n+\t\t\t\t\t  \"%s: fd_fltr_guar = %d\\n\",\n+\t\t\t\t\t  prefix, func_p->fd_fltr_guar);\n+\t\t\t\tice_debug(hw, ICE_DBG_INIT,\n+\t\t\t\t\t  \"%s: fd_fltr_best_effort = %d\\n\",\n+\t\t\t\t\t  prefix, func_p->fd_fltr_best_effort);\n+\t\t\t}\n+\t\t\tbreak;\n \t\tcase ICE_AQC_CAPS_IWARP:\n \t\t\tcaps->iwarp = (number == 1);\n \t\t\tice_debug(hw, ICE_DBG_INIT,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c\nindex 9fb82c993df9..d11960b21474 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c\n@@ -3184,6 +3184,10 @@ ice_get_channels(struct net_device *dev, struct ethtool_channels *ch)\n \tch->combined_count = ice_get_combined_cnt(vsi);\n \tch->rx_count = vsi->num_rxq - ch->combined_count;\n \tch->tx_count = vsi->num_txq - ch->combined_count;\n+\n+\t/* report other queues */\n+\tch->other_count = test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1 : 0;\n+\tch->max_other = ch->other_count;\n }\n \n /**\n@@ -3256,9 +3260,14 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch)\n \t\treturn -EOPNOTSUPP;\n \t}\n \t/* do not support changing other_count */\n-\tif (ch->other_count)\n+\tif (ch->other_count != (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1U : 0U))\n \t\treturn -EINVAL;\n \n+\tif (test_bit(ICE_FLAG_FD_ENA, pf->flags) && pf->hw.fdir_active_fltr) {\n+\t\tnetdev_err(dev, \"Cannot set channels when Flow Director filters are active\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n \tcurr_combined = ice_get_combined_cnt(vsi);\n \n \t/* these checks are for cases where user didn't specify a particular\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c\nnew file mode 100644\nindex 000000000000..f07f40cb70bd\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c\n@@ -0,0 +1,399 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (C) 2018-2019, Intel Corporation. */\n+\n+/* flow director ethtool support for ice */\n+\n+#include \"ice.h\"\n+#include \"ice_lib.h\"\n+#include \"ice_flow.h\"\n+\n+/* calls to ice_flow_add_prof require the number of segments in the array\n+ * for segs_cnt. In this code that is one more than the index.\n+ */\n+#define TNL_SEG_CNT(_TNL_) ((_TNL_) + 1)\n+\n+/**\n+ * ice_fdir_get_hw_prof - return the ice_fd_hw_proc associated with a flow\n+ * @hw: hardware structure containing the filter list\n+ * @blk: hardware block\n+ * @flow: FDir flow type to release\n+ */\n+static struct ice_fd_hw_prof *\n+ice_fdir_get_hw_prof(struct ice_hw *hw, enum ice_block blk, int flow)\n+{\n+\tif (blk == ICE_BLK_FD && hw->fdir_prof)\n+\t\treturn hw->fdir_prof[flow];\n+\n+\treturn NULL;\n+}\n+\n+/**\n+ * ice_fdir_erase_flow_from_hw - remove a flow from the HW profile tables\n+ * @hw: hardware structure containing the filter list\n+ * @blk: hardware block\n+ * @flow: FDir flow type to release\n+ */\n+static void\n+ice_fdir_erase_flow_from_hw(struct ice_hw *hw, enum ice_block blk, int flow)\n+{\n+\tstruct ice_fd_hw_prof *prof = ice_fdir_get_hw_prof(hw, blk, flow);\n+\tint tun;\n+\n+\tif (!prof)\n+\t\treturn;\n+\n+\tfor (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {\n+\t\tu64 prof_id;\n+\t\tint j;\n+\n+\t\tprof_id = flow + tun * ICE_FLTR_PTYPE_MAX;\n+\t\tfor (j = 0; j < prof->cnt; j++) {\n+\t\t\tu16 vsi_num;\n+\n+\t\t\tif (!prof->entry_h[j][tun] || !prof->vsi_h[j])\n+\t\t\t\tcontinue;\n+\t\t\tvsi_num = ice_get_hw_vsi_num(hw, prof->vsi_h[j]);\n+\t\t\tice_rem_prof_id_flow(hw, blk, vsi_num, prof_id);\n+\t\t\tice_flow_rem_entry(hw, blk, prof->entry_h[j][tun]);\n+\t\t\tprof->entry_h[j][tun] = 0;\n+\t\t}\n+\t\tice_flow_rem_prof(hw, blk, prof_id);\n+\t}\n+}\n+\n+/**\n+ * ice_fdir_rem_flow - release the ice_flow structures for a filter type\n+ * @hw: hardware structure containing the filter list\n+ * @blk: hardware block\n+ * @flow_type: FDir flow type to release\n+ */\n+static void\n+ice_fdir_rem_flow(struct ice_hw *hw, enum ice_block blk,\n+\t\t  enum ice_fltr_ptype flow_type)\n+{\n+\tint flow = (int)flow_type & ~FLOW_EXT;\n+\tstruct ice_fd_hw_prof *prof;\n+\tint tun, i;\n+\n+\tprof = ice_fdir_get_hw_prof(hw, blk, flow);\n+\tif (!prof)\n+\t\treturn;\n+\n+\tice_fdir_erase_flow_from_hw(hw, blk, flow);\n+\tfor (i = 0; i < prof->cnt; i++)\n+\t\tprof->vsi_h[i] = 0;\n+\tfor (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {\n+\t\tif (!prof->fdir_seg[tun])\n+\t\t\tcontinue;\n+\t\tdevm_kfree(ice_hw_to_dev(hw), prof->fdir_seg[tun]);\n+\t\tprof->fdir_seg[tun] = NULL;\n+\t}\n+\tprof->cnt = 0;\n+}\n+\n+/**\n+ * ice_fdir_release_flows - release all flows in use for later replay\n+ * @hw: pointer to HW instance\n+ */\n+void ice_fdir_release_flows(struct ice_hw *hw)\n+{\n+\tint flow;\n+\n+\t/* release Flow Director HW table entries */\n+\tfor (flow = 0; flow < ICE_FLTR_PTYPE_MAX; flow++)\n+\t\tice_fdir_erase_flow_from_hw(hw, ICE_BLK_FD, flow);\n+}\n+\n+/**\n+ * ice_fdir_alloc_flow_prof - allocate FDir flow profile structure(s)\n+ * @hw: HW structure containing the FDir flow profile structure(s)\n+ * @flow: flow type to allocate the flow profile for\n+ *\n+ * Allocate the fdir_prof and fdir_prof[flow] if not already created. Return 0\n+ * on success and negative on error.\n+ */\n+static int\n+ice_fdir_alloc_flow_prof(struct ice_hw *hw, enum ice_fltr_ptype flow)\n+{\n+\tif (!hw)\n+\t\treturn -EINVAL;\n+\n+\tif (!hw->fdir_prof) {\n+\t\thw->fdir_prof = devm_kcalloc(ice_hw_to_dev(hw),\n+\t\t\t\t\t     ICE_FLTR_PTYPE_MAX,\n+\t\t\t\t\t     sizeof(*hw->fdir_prof),\n+\t\t\t\t\t     GFP_KERNEL);\n+\t\tif (!hw->fdir_prof)\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n+\tif (!hw->fdir_prof[flow]) {\n+\t\thw->fdir_prof[flow] = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t\t\t\t   sizeof(**hw->fdir_prof),\n+\t\t\t\t\t\t   GFP_KERNEL);\n+\t\tif (!hw->fdir_prof[flow])\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_fdir_set_hw_fltr_rule - Configure HW tables to generate a FDir rule\n+ * @pf: pointer to the PF structure\n+ * @seg: protocol header description pointer\n+ * @flow: filter enum\n+ * @tun: FDir segment to program\n+ */\n+static int\n+ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg,\n+\t\t\t  enum ice_fltr_ptype flow, enum ice_fd_hw_seg tun)\n+{\n+\tstruct device *dev = ice_pf_to_dev(pf);\n+\tstruct ice_vsi *main_vsi, *ctrl_vsi;\n+\tstruct ice_flow_seg_info *old_seg;\n+\tstruct ice_flow_prof *prof = NULL;\n+\tstruct ice_fd_hw_prof *hw_prof;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tenum ice_status status;\n+\tu64 entry1_h = 0;\n+\tu64 entry2_h = 0;\n+\tu64 prof_id;\n+\tint err;\n+\n+\tmain_vsi = ice_get_main_vsi(pf);\n+\tif (!main_vsi)\n+\t\treturn -EINVAL;\n+\n+\tctrl_vsi = ice_get_ctrl_vsi(pf);\n+\tif (!ctrl_vsi)\n+\t\treturn -EINVAL;\n+\n+\terr = ice_fdir_alloc_flow_prof(hw, flow);\n+\tif (err)\n+\t\treturn err;\n+\n+\thw_prof = hw->fdir_prof[flow];\n+\told_seg = hw_prof->fdir_seg[tun];\n+\tif (old_seg) {\n+\t\t/* This flow_type already has a changed input set.\n+\t\t * If it matches the requested input set then we are\n+\t\t * done. Or, if it's different then it's an error.\n+\t\t */\n+\t\tif (!memcmp(old_seg, seg, sizeof(*seg)))\n+\t\t\treturn -EEXIST;\n+\n+\t\t/* remove HW filter definition */\n+\t\tice_fdir_rem_flow(hw, ICE_BLK_FD, flow);\n+\t}\n+\n+\t/* Adding a profile, but there is only one header supported.\n+\t * That is the final parameters are 1 header (segment), no\n+\t * actions (NULL) and zero actions 0.\n+\t */\n+\tprof_id = flow + tun * ICE_FLTR_PTYPE_MAX;\n+\tstatus = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg,\n+\t\t\t\t   TNL_SEG_CNT(tun), &prof);\n+\tif (status)\n+\t\treturn ice_status_to_errno(status);\n+\tstatus = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, main_vsi->idx,\n+\t\t\t\t    main_vsi->idx, ICE_FLOW_PRIO_NORMAL,\n+\t\t\t\t    seg, &entry1_h);\n+\tif (status) {\n+\t\terr = ice_status_to_errno(status);\n+\t\tgoto err_prof;\n+\t}\n+\tstatus = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, main_vsi->idx,\n+\t\t\t\t    ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL,\n+\t\t\t\t    seg, &entry2_h);\n+\tif (status) {\n+\t\terr = ice_status_to_errno(status);\n+\t\tgoto err_entry;\n+\t}\n+\n+\thw_prof->fdir_seg[tun] = seg;\n+\thw_prof->entry_h[0][tun] = entry1_h;\n+\thw_prof->entry_h[1][tun] = entry2_h;\n+\thw_prof->vsi_h[0] = main_vsi->idx;\n+\thw_prof->vsi_h[1] = ctrl_vsi->idx;\n+\tif (!hw_prof->cnt)\n+\t\thw_prof->cnt = 2;\n+\n+\treturn 0;\n+\n+err_entry:\n+\tice_rem_prof_id_flow(hw, ICE_BLK_FD,\n+\t\t\t     ice_get_hw_vsi_num(hw, main_vsi->idx), prof_id);\n+\tice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h);\n+err_prof:\n+\tice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);\n+\tdev_err(dev, \"Failed to add filter.  Flow director filters on each port must have the same input set.\\n\");\n+\n+\treturn err;\n+}\n+\n+/**\n+ * ice_set_init_fdir_seg\n+ * @seg: flow segment for programming\n+ * @l4_proto: ICE_FLOW_SEG_HDR_TCP or ICE_FLOW_SEG_HDR_UDP\n+ *\n+ * Set the configuration for perfect filters to the provided flow segment for\n+ * programming the HW filter. This is to be called only when initializing\n+ * filters as this function it assumes no filters exist.\n+ */\n+static int\n+ice_set_init_fdir_seg(struct ice_flow_seg_info *seg,\n+\t\t      enum ice_flow_seg_hdr l4_proto)\n+{\n+\tenum ice_flow_field src_port, dst_port;\n+\n+\tif (!seg)\n+\t\treturn -EINVAL;\n+\n+\tif (l4_proto == ICE_FLOW_SEG_HDR_TCP) {\n+\t\tsrc_port = ICE_FLOW_FIELD_IDX_TCP_SRC_PORT;\n+\t\tdst_port = ICE_FLOW_FIELD_IDX_TCP_DST_PORT;\n+\t} else if (l4_proto == ICE_FLOW_SEG_HDR_UDP) {\n+\t\tsrc_port = ICE_FLOW_FIELD_IDX_UDP_SRC_PORT;\n+\t\tdst_port = ICE_FLOW_FIELD_IDX_UDP_DST_PORT;\n+\t} else {\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | l4_proto);\n+\n+\t/* IP source address */\n+\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_SA,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n+\n+\t/* IP destination address */\n+\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_DA,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n+\n+\t/* Layer 4 source port */\n+\tice_flow_set_fld(seg, src_port, ICE_FLOW_FLD_OFF_INVAL,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false);\n+\n+\t/* Layer 4 destination port */\n+\tice_flow_set_fld(seg, dst_port, ICE_FLOW_FLD_OFF_INVAL,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_create_init_fdir_rule\n+ * @pf: PF structure\n+ * @flow: filter enum\n+ *\n+ * Return error value or 0 on success.\n+ */\n+static int\n+ice_create_init_fdir_rule(struct ice_pf *pf, enum ice_fltr_ptype flow)\n+{\n+\tstruct ice_flow_seg_info *seg, *tun_seg;\n+\tstruct device *dev = ice_pf_to_dev(pf);\n+\tstruct ice_hw *hw = &pf->hw;\n+\tint ret;\n+\n+\t/* if there is already a filter rule for kind return -EINVAL */\n+\tif (hw->fdir_prof && hw->fdir_prof[flow] &&\n+\t    hw->fdir_prof[flow]->fdir_seg[0])\n+\t\treturn -EINVAL;\n+\n+\tseg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL);\n+\tif (!seg)\n+\t\treturn -ENOMEM;\n+\n+\ttun_seg = devm_kzalloc(dev, sizeof(*seg) * ICE_FD_HW_SEG_MAX,\n+\t\t\t       GFP_KERNEL);\n+\tif (!tun_seg) {\n+\t\tdevm_kfree(dev, seg);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tif (flow == ICE_FLTR_PTYPE_NONF_IPV4_TCP)\n+\t\tret = ice_set_init_fdir_seg(seg, ICE_FLOW_SEG_HDR_TCP);\n+\telse if (flow == ICE_FLTR_PTYPE_NONF_IPV4_UDP)\n+\t\tret = ice_set_init_fdir_seg(seg, ICE_FLOW_SEG_HDR_UDP);\n+\telse\n+\t\tret = -EINVAL;\n+\tif (ret)\n+\t\tgoto err_exit;\n+\n+\t/* add filter for outer headers */\n+\tret = ice_fdir_set_hw_fltr_rule(pf, seg, flow, ICE_FD_HW_SEG_NON_TUN);\n+\tif (ret)\n+\t\t/* could not write filter, free memory */\n+\t\tgoto err_exit;\n+\n+\t/* make tunneled filter HW entries if possible */\n+\tmemcpy(&tun_seg[1], seg, sizeof(*seg));\n+\tret = ice_fdir_set_hw_fltr_rule(pf, tun_seg, flow, ICE_FD_HW_SEG_TUN);\n+\tif (ret)\n+\t\t/* could not write tunnel filter, but outer header filter\n+\t\t * exists\n+\t\t */\n+\t\tdevm_kfree(dev, tun_seg);\n+\n+\tset_bit(flow, hw->fdir_perfect_fltr);\n+\treturn ret;\n+err_exit:\n+\tdevm_kfree(dev, tun_seg);\n+\tdevm_kfree(dev, seg);\n+\n+\treturn -EOPNOTSUPP;\n+}\n+\n+/**\n+ * ice_fdir_create_dflt_rules - create default perfect filters\n+ * @pf: PF data structure\n+ *\n+ * Returns 0 for success or error.\n+ */\n+int ice_fdir_create_dflt_rules(struct ice_pf *pf)\n+{\n+\tint err;\n+\n+\t/* Create perfect TCP and UDP rules in hardware. */\n+\terr = ice_create_init_fdir_rule(pf, ICE_FLTR_PTYPE_NONF_IPV4_TCP);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ice_create_init_fdir_rule(pf, ICE_FLTR_PTYPE_NONF_IPV4_UDP);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * ice_vsi_manage_fdir - turn on/off flow director\n+ * @vsi: the VSI being changed\n+ * @ena: boolean value indicating if this is an enable or disable request\n+ */\n+void ice_vsi_manage_fdir(struct ice_vsi *vsi, bool ena)\n+{\n+\tstruct ice_pf *pf = vsi->back;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tenum ice_fltr_ptype flow;\n+\n+\tif (ena) {\n+\t\tset_bit(ICE_FLAG_FD_ENA, pf->flags);\n+\t\tice_fdir_create_dflt_rules(pf);\n+\t\treturn;\n+\t}\n+\n+\tmutex_lock(&hw->fdir_fltr_lock);\n+\tif (!test_and_clear_bit(ICE_FLAG_FD_ENA, pf->flags))\n+\t\tgoto release_lock;\n+\n+\tif (hw->fdir_prof)\n+\t\tfor (flow = ICE_FLTR_PTYPE_NONF_NONE; flow < ICE_FLTR_PTYPE_MAX;\n+\t\t     flow++)\n+\t\t\tif (hw->fdir_prof[flow])\n+\t\t\t\tice_fdir_rem_flow(hw, ICE_BLK_FD, flow);\n+\n+release_lock:\n+\tmutex_unlock(&hw->fdir_fltr_lock);\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_fdir.c b/drivers/net/ethernet/intel/ice/ice_fdir.c\nnew file mode 100644\nindex 000000000000..c43f79d0bd5a\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_fdir.c\n@@ -0,0 +1,54 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (C) 2018-2019, Intel Corporation. */\n+\n+#include \"ice_common.h\"\n+\n+/**\n+ * ice_alloc_fd_res_cntr - obtain counter resource for FD type\n+ * @hw: pointer to the hardware structure\n+ * @cntr_id: returns counter index\n+ */\n+enum ice_status ice_alloc_fd_res_cntr(struct ice_hw *hw, u16 *cntr_id)\n+{\n+\treturn ice_alloc_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK,\n+\t\t\t\t  ICE_AQC_RES_TYPE_FLAG_DEDICATED, 1, cntr_id);\n+}\n+\n+/**\n+ * ice_free_fd_res_cntr - Free counter resource for FD type\n+ * @hw: pointer to the hardware structure\n+ * @cntr_id: counter index to be freed\n+ */\n+enum ice_status ice_free_fd_res_cntr(struct ice_hw *hw, u16 cntr_id)\n+{\n+\treturn ice_free_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK,\n+\t\t\t\t ICE_AQC_RES_TYPE_FLAG_DEDICATED, 1, cntr_id);\n+}\n+\n+/**\n+ * ice_alloc_fd_guar_item - allocate resource for FD guaranteed entries\n+ * @hw: pointer to the hardware structure\n+ * @cntr_id: returns counter index\n+ * @num_fltr: number of filter entries to be allocated\n+ */\n+enum ice_status\n+ice_alloc_fd_guar_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr)\n+{\n+\treturn ice_alloc_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES,\n+\t\t\t\t  ICE_AQC_RES_TYPE_FLAG_DEDICATED, num_fltr,\n+\t\t\t\t  cntr_id);\n+}\n+\n+/**\n+ * ice_alloc_fd_shrd_item - allocate resource for flow director shared entries\n+ * @hw: pointer to the hardware structure\n+ * @cntr_id: returns counter index\n+ * @num_fltr: number of filter entries to be allocated\n+ */\n+enum ice_status\n+ice_alloc_fd_shrd_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr)\n+{\n+\treturn ice_alloc_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES,\n+\t\t\t\t  ICE_AQC_RES_TYPE_FLAG_DEDICATED, num_fltr,\n+\t\t\t\t  cntr_id);\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_fdir.h b/drivers/net/ethernet/intel/ice/ice_fdir.h\nnew file mode 100644\nindex 000000000000..2cb8cb089d9f\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_fdir.h\n@@ -0,0 +1,12 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (C) 2018-2019, Intel Corporation. */\n+\n+#ifndef _ICE_FDIR_H_\n+#define _ICE_FDIR_H_\n+enum ice_status ice_alloc_fd_res_cntr(struct ice_hw *hw, u16 *cntr_id);\n+enum ice_status ice_free_fd_res_cntr(struct ice_hw *hw, u16 cntr_id);\n+enum ice_status\n+ice_alloc_fd_guar_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr);\n+enum ice_status\n+ice_alloc_fd_shrd_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr);\n+#endif /* _ICE_FDIR_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\nindex 38c37f506257..fe2f04f706e7 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\n+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\n@@ -2353,6 +2353,9 @@ ice_find_prof_id(struct ice_hw *hw, enum ice_block blk,\n static bool ice_prof_id_rsrc_type(enum ice_block blk, u16 *rsrc_type)\n {\n \tswitch (blk) {\n+\tcase ICE_BLK_FD:\n+\t\t*rsrc_type = ICE_AQC_RES_TYPE_FD_PROF_BLDR_PROFID;\n+\t\tbreak;\n \tcase ICE_BLK_RSS:\n \t\t*rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID;\n \t\tbreak;\n@@ -2370,6 +2373,9 @@ static bool ice_prof_id_rsrc_type(enum ice_block blk, u16 *rsrc_type)\n static bool ice_tcam_ent_rsrc_type(enum ice_block blk, u16 *rsrc_type)\n {\n \tswitch (blk) {\n+\tcase ICE_BLK_FD:\n+\t\t*rsrc_type = ICE_AQC_RES_TYPE_FD_PROF_BLDR_TCAM;\n+\t\tbreak;\n \tcase ICE_BLK_RSS:\n \t\t*rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM;\n \t\tbreak;\n@@ -2813,6 +2819,12 @@ static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx)\n \n \tmutex_lock(&hw->fl_profs_locks[blk_idx]);\n \tlist_for_each_entry_safe(p, tmp, &hw->fl_profs[blk_idx], l_entry) {\n+\t\tstruct ice_flow_entry *e, *t;\n+\n+\t\tlist_for_each_entry_safe(e, t, &p->entries, l_entry)\n+\t\t\tice_flow_rem_entry(hw, (enum ice_block)blk_idx,\n+\t\t\t\t\t   ICE_FLOW_ENTRY_HNDL(e));\n+\n \t\tlist_del(&p->l_entry);\n \t\tdevm_kfree(ice_hw_to_dev(hw), p);\n \t}\n@@ -3441,6 +3453,206 @@ ice_upd_prof_hw(struct ice_hw *hw, enum ice_block blk,\n \treturn status;\n }\n \n+/**\n+ * ice_update_fd_mask - set Flow Director Field Vector mask for a profile\n+ * @hw: pointer to the HW struct\n+ * @prof_id: profile ID\n+ * @mask_sel: mask select\n+ *\n+ * This function enable any of the masks selected by the mask select parameter\n+ * for the profile specified.\n+ */\n+static void ice_update_fd_mask(struct ice_hw *hw, u16 prof_id, u32 mask_sel)\n+{\n+\twr32(hw, GLQF_FDMASK_SEL(prof_id), mask_sel);\n+\n+\tice_debug(hw, ICE_DBG_INIT, \"fd mask(%d): %x = %x\\n\", prof_id,\n+\t\t  GLQF_FDMASK_SEL(prof_id), mask_sel);\n+}\n+\n+struct ice_fd_src_dst_pair {\n+\tu8 prot_id;\n+\tu8 count;\n+\tu16 off;\n+};\n+\n+static const struct ice_fd_src_dst_pair ice_fd_pairs[] = {\n+\t/* These are defined in pairs */\n+\t{ ICE_PROT_IPV4_OF_OR_S, 2, 12 },\n+\t{ ICE_PROT_IPV4_OF_OR_S, 2, 16 },\n+\n+\t{ ICE_PROT_IPV4_IL, 2, 12 },\n+\t{ ICE_PROT_IPV4_IL, 2, 16 },\n+\n+\t{ ICE_PROT_TCP_IL, 1, 0 },\n+\t{ ICE_PROT_TCP_IL, 1, 2 },\n+\n+\t{ ICE_PROT_UDP_OF, 1, 0 },\n+\t{ ICE_PROT_UDP_OF, 1, 2 },\n+\n+\t{ ICE_PROT_UDP_IL_OR_S, 1, 0 },\n+\t{ ICE_PROT_UDP_IL_OR_S, 1, 2 },\n+\n+\t{ ICE_PROT_SCTP_IL, 1, 0 },\n+\t{ ICE_PROT_SCTP_IL, 1, 2 }\n+};\n+\n+#define ICE_FD_SRC_DST_PAIR_COUNT\tARRAY_SIZE(ice_fd_pairs)\n+\n+/**\n+ * ice_update_fd_swap - set register appropriately for a FD FV extraction\n+ * @hw: pointer to the HW struct\n+ * @prof_id: profile ID\n+ * @es: extraction sequence (length of array is determined by the block)\n+ */\n+static enum ice_status\n+ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es)\n+{\n+\tDECLARE_BITMAP(pair_list, ICE_FD_SRC_DST_PAIR_COUNT);\n+\tu8 pair_start[ICE_FD_SRC_DST_PAIR_COUNT] = { 0 };\n+#define ICE_FD_FV_NOT_FOUND (-2)\n+\ts8 first_free = ICE_FD_FV_NOT_FOUND;\n+\tu8 used[ICE_MAX_FV_WORDS] = { 0 };\n+\ts8 orig_free, si;\n+\tu32 mask_sel = 0;\n+\tu8 i, j, k;\n+\n+\tbitmap_zero(pair_list, ICE_FD_SRC_DST_PAIR_COUNT);\n+\n+\t/* This code assumes that the Flow Director field vectors are assigned\n+\t * from the end of the FV indexes working towards the zero index, that\n+\t * only complete fields will be included and will be consecutive, and\n+\t * that there are no gaps between valid indexes.\n+\t */\n+\n+\t/* Determine swap fields present */\n+\tfor (i = 0; i < hw->blk[ICE_BLK_FD].es.fvw; i++) {\n+\t\t/* Find the first free entry, assuming right to left population.\n+\t\t * This is where we can start adding additional pairs if needed.\n+\t\t */\n+\t\tif (first_free == ICE_FD_FV_NOT_FOUND && es[i].prot_id !=\n+\t\t    ICE_PROT_INVALID)\n+\t\t\tfirst_free = i - 1;\n+\n+\t\tfor (j = 0; j < ICE_FD_SRC_DST_PAIR_COUNT; j++)\n+\t\t\tif (es[i].prot_id == ice_fd_pairs[j].prot_id &&\n+\t\t\t    es[i].off == ice_fd_pairs[j].off) {\n+\t\t\t\tset_bit(j, pair_list);\n+\t\t\t\tpair_start[j] = i;\n+\t\t\t}\n+\t}\n+\n+\torig_free = first_free;\n+\n+\t/* determine missing swap fields that need to be added */\n+\tfor (i = 0; i < ICE_FD_SRC_DST_PAIR_COUNT; i += 2) {\n+\t\tu8 bit1 = test_bit(i + 1, pair_list);\n+\t\tu8 bit0 = test_bit(i, pair_list);\n+\n+\t\tif (bit0 ^ bit1) {\n+\t\t\tu8 index;\n+\n+\t\t\t/* add the appropriate 'paired' entry */\n+\t\t\tif (!bit0)\n+\t\t\t\tindex = i;\n+\t\t\telse\n+\t\t\t\tindex = i + 1;\n+\n+\t\t\t/* check for room */\n+\t\t\tif (first_free + 1 < (s8)ice_fd_pairs[index].count)\n+\t\t\t\treturn ICE_ERR_MAX_LIMIT;\n+\n+\t\t\t/* place in extraction sequence */\n+\t\t\tfor (k = 0; k < ice_fd_pairs[index].count; k++) {\n+\t\t\t\tes[first_free - k].prot_id =\n+\t\t\t\t\tice_fd_pairs[index].prot_id;\n+\t\t\t\tes[first_free - k].off =\n+\t\t\t\t\tice_fd_pairs[index].off + (k * 2);\n+\n+\t\t\t\tif (k > first_free)\n+\t\t\t\t\treturn ICE_ERR_OUT_OF_RANGE;\n+\n+\t\t\t\t/* keep track of non-relevant fields */\n+\t\t\t\tmask_sel |= BIT(first_free - k);\n+\t\t\t}\n+\n+\t\t\tpair_start[index] = first_free;\n+\t\t\tfirst_free -= ice_fd_pairs[index].count;\n+\t\t}\n+\t}\n+\n+\t/* fill in the swap array */\n+\tsi = hw->blk[ICE_BLK_FD].es.fvw - 1;\n+\twhile (si >= 0) {\n+\t\tu8 indexes_used = 1;\n+\n+\t\t/* assume flat at this index */\n+#define ICE_SWAP_VALID\t0x80\n+\t\tused[si] = si | ICE_SWAP_VALID;\n+\n+\t\tif (orig_free == ICE_FD_FV_NOT_FOUND || si <= orig_free) {\n+\t\t\tsi -= indexes_used;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* check for a swap location */\n+\t\tfor (j = 0; j < ICE_FD_SRC_DST_PAIR_COUNT; j++)\n+\t\t\tif (es[si].prot_id == ice_fd_pairs[j].prot_id &&\n+\t\t\t    es[si].off == ice_fd_pairs[j].off) {\n+\t\t\t\tu8 idx;\n+\n+\t\t\t\t/* determine the appropriate matching field */\n+\t\t\t\tidx = j + ((j % 2) ? -1 : 1);\n+\n+\t\t\t\tindexes_used = ice_fd_pairs[idx].count;\n+\t\t\t\tfor (k = 0; k < indexes_used; k++) {\n+\t\t\t\t\tused[si - k] = (pair_start[idx] - k) |\n+\t\t\t\t\t\tICE_SWAP_VALID;\n+\t\t\t\t}\n+\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\tsi -= indexes_used;\n+\t}\n+\n+\t/* for each set of 4 swap and 4 inset indexes, write the appropriate\n+\t * register\n+\t */\n+\tfor (j = 0; j < hw->blk[ICE_BLK_FD].es.fvw / 4; j++) {\n+\t\tu32 raw_swap = 0;\n+\t\tu32 raw_in = 0;\n+\n+\t\tfor (k = 0; k < 4; k++) {\n+\t\t\tu8 idx;\n+\n+\t\t\tidx = (j * 4) + k;\n+\t\t\tif (used[idx] && !(mask_sel & BIT(idx))) {\n+\t\t\t\traw_swap |= used[idx] << (k * BITS_PER_BYTE);\n+#define ICE_INSET_DFLT 0x9f\n+\t\t\t\traw_in |= ICE_INSET_DFLT << (k * BITS_PER_BYTE);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* write the appropriate swap register set */\n+\t\twr32(hw, GLQF_FDSWAP(prof_id, j), raw_swap);\n+\n+\t\tice_debug(hw, ICE_DBG_INIT, \"swap wr(%d, %d): %x = %08x\\n\",\n+\t\t\t  prof_id, j, GLQF_FDSWAP(prof_id, j), raw_swap);\n+\n+\t\t/* write the appropriate inset register set */\n+\t\twr32(hw, GLQF_FDINSET(prof_id, j), raw_in);\n+\n+\t\tice_debug(hw, ICE_DBG_INIT, \"inset wr(%d, %d): %x = %08x\\n\",\n+\t\t\t  prof_id, j, GLQF_FDINSET(prof_id, j), raw_in);\n+\t}\n+\n+\t/* initially clear the mask select for this profile */\n+\tice_update_fd_mask(hw, prof_id, 0);\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_add_prof - add profile\n  * @hw: pointer to the HW struct\n@@ -3476,6 +3688,18 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],\n \t\tstatus = ice_alloc_prof_id(hw, blk, &prof_id);\n \t\tif (status)\n \t\t\tgoto err_ice_add_prof;\n+\t\tif (blk == ICE_BLK_FD) {\n+\t\t\t/* For Flow Director block, the extraction sequence may\n+\t\t\t * need to be altered in the case where there are paired\n+\t\t\t * fields that have no match. This is necessary because\n+\t\t\t * for Flow Director, src and dest fields need to paired\n+\t\t\t * for filter programming and these values are swapped\n+\t\t\t * during Tx.\n+\t\t\t */\n+\t\t\tstatus = ice_update_fd_swap(hw, prof_id, es);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof;\n+\t\t}\n \n \t\t/* and write new es */\n \t\tice_write_es(hw, blk, prof_id, es);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flow.c b/drivers/net/ethernet/intel/ice/ice_flow.c\nindex 07875db08c3f..f4b6c3933564 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flow.c\n+++ b/drivers/net/ethernet/intel/ice/ice_flow.c\n@@ -397,10 +397,8 @@ ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)\n \t\treturn status;\n \n \tswitch (params->blk) {\n+\tcase ICE_BLK_FD:\n \tcase ICE_BLK_RSS:\n-\t\t/* Only header information is provided for RSS configuration.\n-\t\t * No further processing is needed.\n-\t\t */\n \t\tstatus = 0;\n \t\tbreak;\n \tdefault:\n@@ -481,6 +479,43 @@ ice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id)\n \treturn NULL;\n }\n \n+/**\n+ * ice_dealloc_flow_entry - Deallocate flow entry memory\n+ * @hw: pointer to the HW struct\n+ * @entry: flow entry to be removed\n+ */\n+static void\n+ice_dealloc_flow_entry(struct ice_hw *hw, struct ice_flow_entry *entry)\n+{\n+\tif (!entry)\n+\t\treturn;\n+\n+\tif (entry->entry)\n+\t\tdevm_kfree(ice_hw_to_dev(hw), entry->entry);\n+\n+\tdevm_kfree(ice_hw_to_dev(hw), entry);\n+}\n+\n+/**\n+ * ice_flow_rem_entry_sync - Remove a flow entry\n+ * @hw: pointer to the HW struct\n+ * @blk: classification stage\n+ * @entry: flow entry to be removed\n+ */\n+static enum ice_status\n+ice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk,\n+\t\t\tstruct ice_flow_entry *entry)\n+{\n+\tif (!entry)\n+\t\treturn ICE_ERR_BAD_PTR;\n+\n+\tlist_del(&entry->l_entry);\n+\n+\tice_dealloc_flow_entry(hw, entry);\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_flow_add_prof_sync - Add a flow profile for packet segments and fields\n  * @hw: pointer to the HW struct\n@@ -568,6 +603,21 @@ ice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk,\n {\n \tenum ice_status status;\n \n+\t/* Remove all remaining flow entries before removing the flow profile */\n+\tif (!list_empty(&prof->entries)) {\n+\t\tstruct ice_flow_entry *e, *t;\n+\n+\t\tmutex_lock(&prof->entries_lock);\n+\n+\t\tlist_for_each_entry_safe(e, t, &prof->entries, l_entry) {\n+\t\t\tstatus = ice_flow_rem_entry_sync(hw, blk, e);\n+\t\t\tif (status)\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\tmutex_unlock(&prof->entries_lock);\n+\t}\n+\n \t/* Remove all hardware profiles associated with this flow profile */\n \tstatus = ice_rem_prof(hw, blk, prof->id);\n \tif (!status) {\n@@ -653,7 +703,7 @@ ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,\n  * @segs_cnt: number of packet segments provided\n  * @prof: stores the returned flow profile added\n  */\n-static enum ice_status\n+enum ice_status\n ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,\n \t\t  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,\n \t\t  struct ice_flow_prof **prof)\n@@ -691,7 +741,7 @@ ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,\n  * @blk: the block for which the flow profile is to be removed\n  * @prof_id: unique ID of the flow profile to be removed\n  */\n-static enum ice_status\n+enum ice_status\n ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id)\n {\n \tstruct ice_flow_prof *prof;\n@@ -714,6 +764,113 @@ ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id)\n \treturn status;\n }\n \n+/**\n+ * ice_flow_add_entry - Add a flow entry\n+ * @hw: pointer to the HW struct\n+ * @blk: classification stage\n+ * @prof_id: ID of the profile to add a new flow entry to\n+ * @entry_id: unique ID to identify this flow entry\n+ * @vsi_handle: software VSI handle for the flow entry\n+ * @prio: priority of the flow entry\n+ * @data: pointer to a data buffer containing flow entry's match values/masks\n+ * @entry_h: pointer to buffer that receives the new flow entry's handle\n+ */\n+enum ice_status\n+ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,\n+\t\t   u64 entry_id, u16 vsi_handle, enum ice_flow_priority prio,\n+\t\t   void *data, u64 *entry_h)\n+{\n+\tstruct ice_flow_entry *e = NULL;\n+\tstruct ice_flow_prof *prof;\n+\tenum ice_status status;\n+\n+\t/* No flow entry data is expected for RSS */\n+\tif (!entry_h || (!data && blk != ICE_BLK_RSS))\n+\t\treturn ICE_ERR_BAD_PTR;\n+\n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tmutex_lock(&hw->fl_profs_locks[blk]);\n+\n+\tprof = ice_flow_find_prof_id(hw, blk, prof_id);\n+\tif (!prof) {\n+\t\tstatus = ICE_ERR_DOES_NOT_EXIST;\n+\t} else {\n+\t\t/* Allocate memory for the entry being added and associate\n+\t\t * the VSI to the found flow profile\n+\t\t */\n+\t\te = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*e), GFP_KERNEL);\n+\t\tif (!e)\n+\t\t\tstatus = ICE_ERR_NO_MEMORY;\n+\t\telse\n+\t\t\tstatus = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);\n+\t}\n+\n+\tmutex_unlock(&hw->fl_profs_locks[blk]);\n+\tif (status)\n+\t\tgoto out;\n+\n+\te->id = entry_id;\n+\te->vsi_handle = vsi_handle;\n+\te->prof = prof;\n+\te->priority = prio;\n+\n+\tswitch (blk) {\n+\tcase ICE_BLK_FD:\n+\tcase ICE_BLK_RSS:\n+\t\tbreak;\n+\tdefault:\n+\t\tstatus = ICE_ERR_NOT_IMPL;\n+\t\tgoto out;\n+\t}\n+\n+\tmutex_lock(&prof->entries_lock);\n+\tlist_add(&e->l_entry, &prof->entries);\n+\tmutex_unlock(&prof->entries_lock);\n+\n+\t*entry_h = ICE_FLOW_ENTRY_HNDL(e);\n+\n+out:\n+\tif (status && e) {\n+\t\tif (e->entry)\n+\t\t\tdevm_kfree(ice_hw_to_dev(hw), e->entry);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), e);\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_flow_rem_entry - Remove a flow entry\n+ * @hw: pointer to the HW struct\n+ * @blk: classification stage\n+ * @entry_h: handle to the flow entry to be removed\n+ */\n+enum ice_status ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk,\n+\t\t\t\t   u64 entry_h)\n+{\n+\tstruct ice_flow_entry *entry;\n+\tstruct ice_flow_prof *prof;\n+\tenum ice_status status = 0;\n+\n+\tif (entry_h == ICE_FLOW_ENTRY_HANDLE_INVAL)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tentry = ICE_FLOW_ENTRY_PTR(entry_h);\n+\n+\t/* Retain the pointer to the flow profile as the entry will be freed */\n+\tprof = entry->prof;\n+\n+\tif (prof) {\n+\t\tmutex_lock(&prof->entries_lock);\n+\t\tstatus = ice_flow_rem_entry_sync(hw, blk, entry);\n+\t\tmutex_unlock(&prof->entries_lock);\n+\t}\n+\n+\treturn status;\n+}\n+\n /**\n  * ice_flow_set_fld_ext - specifies locations of field from entry's input buffer\n  * @seg: packet segment the field being set belongs to\n@@ -776,7 +933,7 @@ ice_flow_set_fld_ext(struct ice_flow_seg_info *seg, enum ice_flow_field fld,\n  * create the content of a match entry. This function should only be used for\n  * fixed-size data structures.\n  */\n-static void\n+void\n ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,\n \t\t u16 val_loc, u16 mask_loc, u16 last_loc, bool range)\n {\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flow.h b/drivers/net/ethernet/intel/ice/ice_flow.h\nindex 00f2b7a9feed..3c784c3b5db2 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flow.h\n+++ b/drivers/net/ethernet/intel/ice/ice_flow.h\n@@ -172,6 +172,22 @@ struct ice_flow_seg_info {\n \tstruct ice_flow_fld_info fields[ICE_FLOW_FIELD_IDX_MAX];\n };\n \n+/* This structure describes a flow entry, and is tracked only in this file */\n+struct ice_flow_entry {\n+\tstruct list_head l_entry;\n+\n+\tu64 id;\n+\tstruct ice_flow_prof *prof;\n+\t/* Flow entry's content */\n+\tvoid *entry;\n+\tenum ice_flow_priority priority;\n+\tu16 vsi_handle;\n+\tu16 entry_sz;\n+};\n+\n+#define ICE_FLOW_ENTRY_HNDL(e)\t((u64)e)\n+#define ICE_FLOW_ENTRY_PTR(h)\t((struct ice_flow_entry *)(h))\n+\n struct ice_flow_prof {\n \tstruct list_head l_entry;\n \n@@ -197,7 +213,21 @@ struct ice_rss_cfg {\n \tu32 packet_hdr;\n };\n \n-enum ice_status ice_flow_rem_entry(struct ice_hw *hw, u64 entry_h);\n+enum ice_status\n+ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,\n+\t\t  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,\n+\t\t  struct ice_flow_prof **prof);\n+enum ice_status\n+ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id);\n+enum ice_status\n+ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,\n+\t\t   u64 entry_id, u16 vsi, enum ice_flow_priority prio,\n+\t\t   void *data, u64 *entry_h);\n+enum ice_status\n+ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk, u64 entry_h);\n+void\n+ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,\n+\t\t u16 val_loc, u16 mask_loc, u16 last_loc, bool range);\n void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle);\n enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle);\n enum ice_status\ndiff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\nindex 3f40736a8295..3a85138d526b 100644\n--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n@@ -290,6 +290,17 @@\n #define GL_PWR_MODE_CTL\t\t\t\t0x000B820C\n #define GL_PWR_MODE_CTL_CAR_MAX_BW_S\t\t30\n #define GL_PWR_MODE_CTL_CAR_MAX_BW_M\t\tICE_M(0x3, 30)\n+#define GLQF_FD_SIZE\t\t\t\t0x00460010\n+#define GLQF_FD_SIZE_FD_GSIZE_S\t\t\t0\n+#define GLQF_FD_SIZE_FD_GSIZE_M\t\t\tICE_M(0x7FFF, 0)\n+#define GLQF_FD_SIZE_FD_BSIZE_S\t\t\t16\n+#define GLQF_FD_SIZE_FD_BSIZE_M\t\t\tICE_M(0x7FFF, 16)\n+#define GLQF_FDINSET(_i, _j)\t\t\t(0x00412000 + ((_i) * 4 + (_j) * 512))\n+#define GLQF_FDMASK_SEL(_i)\t\t\t(0x00410400 + ((_i) * 4))\n+#define GLQF_FDSWAP(_i, _j)\t\t\t(0x00413000 + ((_i) * 4 + (_j) * 512))\n+#define PFQF_FD_ENA\t\t\t\t0x0043A000\n+#define PFQF_FD_ENA_FD_ENA_M\t\t\tBIT(0)\n+#define PFQF_FD_SIZE\t\t\t\t0x00460100\n #define GLDCB_RTCTQ_RXQNUM_S\t\t\t0\n #define GLDCB_RTCTQ_RXQNUM_M\t\t\tICE_M(0x7FF, 0)\n #define GLPRT_BPRCL(_i)\t\t\t\t(0x00381380 + ((_i) * 8))\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c\nindex 6e23a87b75ed..7649ff2bf3e1 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.c\n@@ -19,6 +19,8 @@ const char *ice_vsi_type_str(enum ice_vsi_type vsi_type)\n \t\treturn \"ICE_VSI_PF\";\n \tcase ICE_VSI_VF:\n \t\treturn \"ICE_VSI_VF\";\n+\tcase ICE_VSI_CTRL:\n+\t\treturn \"ICE_VSI_CTRL\";\n \tcase ICE_VSI_LB:\n \t\treturn \"ICE_VSI_LB\";\n \tdefault:\n@@ -123,6 +125,7 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi)\n {\n \tswitch (vsi->type) {\n \tcase ICE_VSI_PF:\n+\tcase ICE_VSI_CTRL:\n \tcase ICE_VSI_LB:\n \t\tvsi->num_rx_desc = ICE_DFLT_NUM_RX_DESC;\n \t\tvsi->num_tx_desc = ICE_DFLT_NUM_TX_DESC;\n@@ -187,6 +190,11 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)\n \t\t */\n \t\tvsi->num_q_vectors = pf->num_msix_per_vf - ICE_NONQ_VECS_VF;\n \t\tbreak;\n+\tcase ICE_VSI_CTRL:\n+\t\tvsi->alloc_txq = 1;\n+\t\tvsi->alloc_rxq = 1;\n+\t\tvsi->num_q_vectors = 1;\n+\t\tbreak;\n \tcase ICE_VSI_LB:\n \t\tvsi->alloc_txq = 1;\n \t\tvsi->alloc_rxq = 1;\n@@ -322,7 +330,7 @@ int ice_vsi_clear(struct ice_vsi *vsi)\n \t/* updates the PF for this cleared VSI */\n \n \tpf->vsi[vsi->idx] = NULL;\n-\tif (vsi->idx < pf->next_vsi)\n+\tif (vsi->idx < pf->next_vsi && vsi->type != ICE_VSI_CTRL)\n \t\tpf->next_vsi = vsi->idx;\n \n \tice_vsi_free_arrays(vsi);\n@@ -332,6 +340,25 @@ int ice_vsi_clear(struct ice_vsi *vsi)\n \treturn 0;\n }\n \n+/**\n+ * ice_msix_clean_ctrl_vsi - MSIX mode interrupt handler for ctrl VSI\n+ * @irq: interrupt number\n+ * @data: pointer to a q_vector\n+ */\n+static irqreturn_t ice_msix_clean_ctrl_vsi(int __always_unused irq, void *data)\n+{\n+\tstruct ice_q_vector *q_vector = (struct ice_q_vector *)data;\n+\n+\tif (!q_vector->tx.ring)\n+\t\treturn IRQ_HANDLED;\n+\n+#define FDIR_RX_DESC_CLEAN_BUDGET 64\n+\tice_clean_rx_irq(q_vector->rx.ring, FDIR_RX_DESC_CLEAN_BUDGET);\n+\tice_clean_ctrl_tx_irq(q_vector->tx.ring);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n /**\n  * ice_msix_clean_rings - MSIX mode Interrupt Handler\n  * @irq: interrupt number\n@@ -383,8 +410,6 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id)\n \tvsi->back = pf;\n \tset_bit(__ICE_DOWN, vsi->state);\n \n-\tvsi->idx = pf->next_vsi;\n-\n \tif (vsi_type == ICE_VSI_VF)\n \t\tice_vsi_set_num_qs(vsi, vf_id);\n \telse\n@@ -398,6 +423,13 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id)\n \t\t/* Setup default MSIX irq handler for VSI */\n \t\tvsi->irq_handler = ice_msix_clean_rings;\n \t\tbreak;\n+\tcase ICE_VSI_CTRL:\n+\t\tif (ice_vsi_alloc_arrays(vsi))\n+\t\t\tgoto err_rings;\n+\n+\t\t/* Setup ctrl VSI MSIX irq handler */\n+\t\tvsi->irq_handler = ice_msix_clean_ctrl_vsi;\n+\t\tbreak;\n \tcase ICE_VSI_VF:\n \t\tif (ice_vsi_alloc_arrays(vsi))\n \t\t\tgoto err_rings;\n@@ -411,12 +443,20 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id)\n \t\tgoto unlock_pf;\n \t}\n \n-\t/* fill VSI slot in the PF struct */\n-\tpf->vsi[pf->next_vsi] = vsi;\n+\tif (vsi->type == ICE_VSI_CTRL) {\n+\t\t/* Use the last VSI slot as the index for the control VSI */\n+\t\tvsi->idx = pf->num_alloc_vsi - 1;\n+\t\tpf->ctrl_vsi_idx = vsi->idx;\n+\t\tpf->vsi[vsi->idx] = vsi;\n+\t} else {\n+\t\t/* fill slot and make note of the index */\n+\t\tvsi->idx = pf->next_vsi;\n+\t\tpf->vsi[pf->next_vsi] = vsi;\n \n-\t/* prepare pf->next_vsi for next use */\n-\tpf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi,\n-\t\t\t\t\t pf->next_vsi);\n+\t\t/* prepare pf->next_vsi for next use */\n+\t\tpf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi,\n+\t\t\t\t\t\t pf->next_vsi);\n+\t}\n \tgoto unlock_pf;\n \n err_rings:\n@@ -427,6 +467,48 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id)\n \treturn vsi;\n }\n \n+/**\n+ * ice_alloc_fd_res - Allocate FD resource for a VSI\n+ * @vsi: pointer to the ice_vsi\n+ *\n+ * This allocates the FD resources\n+ *\n+ * Returns 0 on success, -EPERM on no-op or -EIO on failure\n+ */\n+static int ice_alloc_fd_res(struct ice_vsi *vsi)\n+{\n+\tstruct ice_pf *pf = vsi->back;\n+\tu32 g_val, b_val;\n+\n+\t/* Flow Director filters are only allocated/assigned to the PF VSI which\n+\t * passes the traffic. The CTRL VSI is only used to add/delete filters\n+\t * so we don't allocate resources to it\n+\t */\n+\n+\t/* FD filters from guaranteed pool per VSI */\n+\tg_val = pf->hw.func_caps.fd_fltr_guar;\n+\tif (!g_val)\n+\t\treturn -EPERM;\n+\n+\t/* FD filters from best effort pool */\n+\tb_val = pf->hw.func_caps.fd_fltr_best_effort;\n+\tif (!b_val)\n+\t\treturn -EPERM;\n+\n+\tif (vsi->type != ICE_VSI_PF)\n+\t\treturn -EPERM;\n+\n+\tif (!test_bit(ICE_FLAG_FD_ENA, pf->flags))\n+\t\treturn -EPERM;\n+\n+\tvsi->num_gfltr = g_val / pf->num_alloc_vsi;\n+\n+\t/* each VSI gets same \"best_effort\" quota */\n+\tvsi->num_bfltr = b_val;\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_vsi_get_qs - Assign queues from PF to VSI\n  * @vsi: the VSI to assign queues to\n@@ -594,8 +676,8 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)\n \tcase ICE_VSI_LB:\n \t\tbreak;\n \tdefault:\n-\t\tdev_warn(ice_pf_to_dev(pf), \"Unknown VSI type %d\\n\",\n-\t\t\t vsi->type);\n+\t\tdev_dbg(ice_pf_to_dev(pf), \"Unsupported VSI type %s\\n\",\n+\t\t\tice_vsi_type_str(vsi->type));\n \t\tbreak;\n \t}\n }\n@@ -764,6 +846,51 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)\n \tctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq);\n }\n \n+/**\n+ * ice_set_fd_vsi_ctx - Set FD VSI context before adding a VSI\n+ * @ctxt: the VSI context being set\n+ * @vsi: the VSI being configured\n+ */\n+static void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)\n+{\n+\tu8 dflt_q_group, dflt_q_prio;\n+\tu16 dflt_q, report_q, val;\n+\n+\tif (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_CTRL)\n+\t\treturn;\n+\n+\tval = ICE_AQ_VSI_PROP_FLOW_DIR_VALID;\n+\tctxt->info.valid_sections |= cpu_to_le16(val);\n+\tdflt_q = 0;\n+\tdflt_q_group = 0;\n+\treport_q = 0;\n+\tdflt_q_prio = 0;\n+\n+\t/* enable flow director filtering/programming */\n+\tval = ICE_AQ_VSI_FD_ENABLE | ICE_AQ_VSI_FD_PROG_ENABLE;\n+\tctxt->info.fd_options = cpu_to_le16(val);\n+\t/* max of allocated flow director filters */\n+\tctxt->info.max_fd_fltr_dedicated =\n+\t\t\tcpu_to_le16(vsi->num_gfltr);\n+\t/* max of shared flow director filters any VSI may program */\n+\tctxt->info.max_fd_fltr_shared =\n+\t\t\tcpu_to_le16(vsi->num_bfltr);\n+\t/* default queue index within the VSI of the default FD */\n+\tval = ((dflt_q << ICE_AQ_VSI_FD_DEF_Q_S) &\n+\t       ICE_AQ_VSI_FD_DEF_Q_M);\n+\t/* target queue or queue group to the FD filter */\n+\tval |= ((dflt_q_group << ICE_AQ_VSI_FD_DEF_GRP_S) &\n+\t\tICE_AQ_VSI_FD_DEF_GRP_M);\n+\tctxt->info.fd_def_q = cpu_to_le16(val);\n+\t/* queue index on which FD filter completion is reported */\n+\tval = ((report_q << ICE_AQ_VSI_FD_REPORT_Q_S) &\n+\t       ICE_AQ_VSI_FD_REPORT_Q_M);\n+\t/* priority of the default qindex action */\n+\tval |= ((dflt_q_prio << ICE_AQ_VSI_FD_DEF_PRIORITY_S) &\n+\t\tICE_AQ_VSI_FD_DEF_PRIORITY_M);\n+\tctxt->info.fd_report_opt = cpu_to_le16(val);\n+}\n+\n /**\n  * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI\n  * @ctxt: the VSI context being set\n@@ -789,13 +916,10 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)\n \t\tlut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;\n \t\thash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;\n \t\tbreak;\n-\tcase ICE_VSI_LB:\n+\tdefault:\n \t\tdev_dbg(dev, \"Unsupported VSI type %s\\n\",\n \t\t\tice_vsi_type_str(vsi->type));\n \t\treturn;\n-\tdefault:\n-\t\tdev_warn(dev, \"Unknown VSI type %d\\n\", vsi->type);\n-\t\treturn;\n \t}\n \n \tctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &\n@@ -827,6 +951,7 @@ static int ice_vsi_init(struct ice_vsi *vsi, bool init_vsi)\n \n \tctxt->info = vsi->info;\n \tswitch (vsi->type) {\n+\tcase ICE_VSI_CTRL:\n \tcase ICE_VSI_LB:\n \tcase ICE_VSI_PF:\n \t\tctxt->flags = ICE_AQ_VSI_TYPE_PF;\n@@ -842,12 +967,15 @@ static int ice_vsi_init(struct ice_vsi *vsi, bool init_vsi)\n \t}\n \n \tice_set_dflt_vsi_ctx(ctxt);\n+\tif (test_bit(ICE_FLAG_FD_ENA, pf->flags))\n+\t\tice_set_fd_vsi_ctx(ctxt, vsi);\n \t/* if the switch is in VEB mode, allow VSI loopback */\n \tif (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB)\n \t\tctxt->info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;\n \n \t/* Set LUT type and HASH type if RSS is enabled */\n-\tif (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {\n+\tif (test_bit(ICE_FLAG_RSS_ENA, pf->flags) &&\n+\t    vsi->type != ICE_VSI_CTRL) {\n \t\tice_set_rss_vsi_ctx(ctxt, vsi);\n \t\t/* if updating VSI context, make sure to set valid_section:\n \t\t * to indicate which section of VSI context being updated\n@@ -2021,10 +2149,12 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,\n \tif (vsi->type == ICE_VSI_VF)\n \t\tvsi->vf_id = vf_id;\n \n+\tice_alloc_fd_res(vsi);\n+\n \tif (ice_vsi_get_qs(vsi)) {\n \t\tdev_err(dev, \"Failed to allocate queues. vsi->idx = %d\\n\",\n \t\t\tvsi->idx);\n-\t\tgoto unroll_get_qs;\n+\t\tgoto unroll_vsi_alloc;\n \t}\n \n \t/* set RSS capabilities */\n@@ -2039,6 +2169,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,\n \t\tgoto unroll_get_qs;\n \n \tswitch (vsi->type) {\n+\tcase ICE_VSI_CTRL:\n \tcase ICE_VSI_PF:\n \t\tret = ice_vsi_alloc_q_vectors(vsi);\n \t\tif (ret)\n@@ -2069,14 +2200,16 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,\n \n \t\tice_vsi_map_rings_to_vectors(vsi);\n \n-\t\t/* Do not exit if configuring RSS had an issue, at least\n-\t\t * receive traffic on first queue. Hence no need to capture\n-\t\t * return value\n-\t\t */\n-\t\tif (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {\n-\t\t\tice_vsi_cfg_rss_lut_key(vsi);\n-\t\t\tice_vsi_set_rss_flow_fld(vsi);\n-\t\t}\n+\t\t/* ICE_VSI_CTRL does not need RSS so skip RSS processing */\n+\t\tif (vsi->type != ICE_VSI_CTRL)\n+\t\t\t/* Do not exit if configuring RSS had an issue, at\n+\t\t\t * least receive traffic on first queue. Hence no\n+\t\t\t * need to capture return value\n+\t\t\t */\n+\t\t\tif (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {\n+\t\t\t\tice_vsi_cfg_rss_lut_key(vsi);\n+\t\t\t\tice_vsi_set_rss_flow_fld(vsi);\n+\t\t\t}\n \t\tbreak;\n \tcase ICE_VSI_VF:\n \t\t/* VF driver will take care of creating netdev for this type and\n@@ -2157,6 +2290,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,\n \tice_vsi_delete(vsi);\n unroll_get_qs:\n \tice_vsi_put_qs(vsi);\n+unroll_vsi_alloc:\n \tice_vsi_clear(vsi);\n \n \treturn NULL;\n@@ -2324,6 +2458,8 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked)\n \t\t\tif (!locked)\n \t\t\t\trtnl_unlock();\n \t\t}\n+\t} else if (vsi->type == ICE_VSI_CTRL) {\n+\t\terr = ice_vsi_open_ctrl(vsi);\n \t}\n \n \treturn err;\n@@ -2353,6 +2489,8 @@ void ice_dis_vsi(struct ice_vsi *vsi, bool locked)\n \t\t} else {\n \t\t\tice_vsi_close(vsi);\n \t\t}\n+\t} else if (vsi->type == ICE_VSI_CTRL) {\n+\t\tice_vsi_close(vsi);\n \t}\n }\n \n@@ -2898,6 +3036,30 @@ void ice_update_rx_ring_stats(struct ice_ring *rx_ring, u64 pkts, u64 bytes)\n \tu64_stats_update_end(&rx_ring->syncp);\n }\n \n+/**\n+ * ice_status_to_errno - convert from enum ice_status to Linux errno\n+ * @err: ice_status value to convert\n+ */\n+int ice_status_to_errno(enum ice_status err)\n+{\n+\tswitch (err) {\n+\tcase ICE_SUCCESS:\n+\t\treturn 0;\n+\tcase ICE_ERR_DOES_NOT_EXIST:\n+\t\treturn -ENOENT;\n+\tcase ICE_ERR_OUT_OF_RANGE:\n+\t\treturn -ENOTTY;\n+\tcase ICE_ERR_PARAM:\n+\t\treturn -EINVAL;\n+\tcase ICE_ERR_NO_MEMORY:\n+\t\treturn -ENOMEM;\n+\tcase ICE_ERR_MAX_LIMIT:\n+\t\treturn -EAGAIN;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n /**\n  * ice_is_dflt_vsi_in_use - check if the default forwarding VSI is being used\n  * @sw: switch to check if its default forwarding VSI is free\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h\nindex c9e1aaea55f7..0d11a3dbed78 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.h\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.h\n@@ -94,6 +94,8 @@ void ice_update_rx_ring_stats(struct ice_ring *ring, u64 pkts, u64 bytes);\n \n void ice_vsi_cfg_frame_size(struct ice_vsi *vsi);\n \n+int ice_status_to_errno(enum ice_status err);\n+\n u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran);\n \n enum ice_status\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex d2152cd22b5d..83457d8ca587 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -2326,6 +2326,7 @@ static void ice_set_netdev_features(struct net_device *netdev)\n \n \tdflt_features = NETIF_F_SG\t|\n \t\t\tNETIF_F_HIGHDMA\t|\n+\t\t\tNETIF_F_NTUPLE\t|\n \t\t\tNETIF_F_RXHASH;\n \n \tcsumo_features = NETIF_F_RXCSUM\t  |\n@@ -2465,6 +2466,20 @@ ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)\n \treturn ice_vsi_setup(pf, pi, ICE_VSI_PF, ICE_INVAL_VFID);\n }\n \n+/**\n+ * ice_ctrl_vsi_setup - Set up a control VSI\n+ * @pf: board private structure\n+ * @pi: pointer to the port_info instance\n+ *\n+ * Returns pointer to the successfully allocated VSI software struct\n+ * on success, otherwise returns NULL on failure.\n+ */\n+static struct ice_vsi *\n+ice_ctrl_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)\n+{\n+\treturn ice_vsi_setup(pf, pi, ICE_VSI_CTRL, ICE_INVAL_VFID);\n+}\n+\n /**\n  * ice_lb_vsi_setup - Set up a loopback VSI\n  * @pf: board private structure\n@@ -2719,6 +2734,23 @@ static void ice_set_pf_caps(struct ice_pf *pf)\n \tif (func_caps->common_cap.rss_table_size)\n \t\tset_bit(ICE_FLAG_RSS_ENA, pf->flags);\n \n+\tclear_bit(ICE_FLAG_FD_ENA, pf->flags);\n+\tif (func_caps->fd_fltr_guar > 0 || func_caps->fd_fltr_best_effort > 0) {\n+\t\tu16 unused;\n+\n+\t\t/* ctrl_vsi_idx will be set to a valid value when flow director\n+\t\t * is setup by ice_init_fdir\n+\t\t */\n+\t\tpf->ctrl_vsi_idx = ICE_NO_VSI;\n+\t\tset_bit(ICE_FLAG_FD_ENA, pf->flags);\n+\t\t/* force guaranteed filter pool for PF */\n+\t\tice_alloc_fd_guar_item(&pf->hw, &unused,\n+\t\t\t\t       func_caps->fd_fltr_guar);\n+\t\t/* force shared filter pool for PF */\n+\t\tice_alloc_fd_shrd_item(&pf->hw, &unused,\n+\t\t\t\t       func_caps->fd_fltr_best_effort);\n+\t}\n+\n \tpf->max_pf_txqs = func_caps->common_cap.num_txq;\n \tpf->max_pf_rxqs = func_caps->common_cap.num_rxq;\n }\n@@ -2785,6 +2817,15 @@ static int ice_ena_msix_range(struct ice_pf *pf)\n \tv_budget += needed;\n \tv_left -= needed;\n \n+\t/* reserve one vector for flow director */\n+\tif (test_bit(ICE_FLAG_FD_ENA, pf->flags)) {\n+\t\tneeded = ICE_FDIR_MSIX;\n+\t\tif (v_left < needed)\n+\t\t\tgoto no_hw_vecs_left_err;\n+\t\tv_budget += needed;\n+\t\tv_left -= needed;\n+\t}\n+\n \t/* reserve vectors for RDMA peer driver */\n \tif (test_bit(ICE_FLAG_IWARP_ENA, pf->flags)) {\n \t\tneeded = ICE_RDMA_NUM_VECS;\n@@ -2819,10 +2860,10 @@ static int ice_ena_msix_range(struct ice_pf *pf)\n \tif (v_actual < v_budget) {\n \t\tdev_warn(dev, \"not enough OS MSI-X vectors. requested = %d, obtained = %d\\n\",\n \t\t\t v_budget, v_actual);\n-/* 2 vectors for LAN and RDMA (traffic + OICR) */\n+/* 2 vectors each for LAN and RDMA (traffic + OICR), one for flow director */\n #define ICE_MIN_LAN_VECS 2\n #define ICE_MIN_RDMA_VECS 2\n-#define ICE_MIN_VECS (ICE_MIN_LAN_VECS + ICE_MIN_RDMA_VECS)\n+#define ICE_MIN_VECS (ICE_MIN_LAN_VECS + ICE_MIN_RDMA_VECS + 1)\n \n \t\tif (v_actual < ICE_MIN_VECS) {\n \t\t\t/* error if we can't get minimum vectors */\n@@ -3129,6 +3170,53 @@ static enum ice_status ice_send_version(struct ice_pf *pf)\n \treturn ice_aq_send_driver_ver(&pf->hw, &dv, NULL);\n }\n \n+/**\n+ * ice_init_fdir - Initialize flow director VSI and configuration\n+ * @pf: pointer to the PF instance\n+ *\n+ * returns 0 on success, negative on error\n+ */\n+static int ice_init_fdir(struct ice_pf *pf)\n+{\n+\tstruct device *dev = ice_pf_to_dev(pf);\n+\tstruct ice_vsi *ctrl_vsi;\n+\tint err;\n+\n+\t/* Side Band Flow Director needs to have a control VSI.\n+\t * Allocate it and store it in the PF.\n+\t */\n+\tctrl_vsi = ice_ctrl_vsi_setup(pf, pf->hw.port_info);\n+\tif (!ctrl_vsi) {\n+\t\tdev_dbg(dev, \"could not create control VSI\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\terr = ice_vsi_open_ctrl(ctrl_vsi);\n+\tif (err) {\n+\t\tdev_dbg(dev, \"could not open control VSI\\n\");\n+\t\tgoto err_vsi_open;\n+\t}\n+\n+\tmutex_init(&pf->hw.fdir_fltr_lock);\n+\n+\terr = ice_fdir_create_dflt_rules(pf);\n+\tif (err)\n+\t\tgoto err_fdir_rule;\n+\n+\treturn 0;\n+\n+err_fdir_rule:\n+\tice_fdir_release_flows(&pf->hw);\n+\tice_vsi_close(ctrl_vsi);\n+err_vsi_open:\n+\tice_vsi_release(ctrl_vsi);\n+\tif (pf->ctrl_vsi_idx != ICE_NO_VSI) {\n+\t\tpf->vsi[pf->ctrl_vsi_idx] = NULL;\n+\t\tpf->ctrl_vsi_idx = ICE_NO_VSI;\n+\t}\n+\treturn err;\n+}\n+\n /**\n  * ice_get_opt_fw_name - return optional firmware file name or NULL\n  * @pf: pointer to the PF instance\n@@ -3389,6 +3477,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)\n \n \t/* initialize DDP driven features */\n \n+\t/* Note: Flow director init failure is non-fatal to load */\n+\tif (ice_init_fdir(pf))\n+\t\tdev_err(dev, \"could not initialize flow director\\n\");\n+\n \t/* init peers only if supported */\n \tif (ice_is_peer_ena(pf)) {\n \t\tpf->peers = devm_kcalloc(dev, IIDC_MAX_NUM_PEERS,\n@@ -3484,6 +3576,7 @@ static void ice_remove(struct pci_dev *pdev)\n \t}\n \tset_bit(__ICE_DOWN, pf->state);\n \n+\tmutex_destroy(&(&pf->hw)->fdir_fltr_lock);\n \tice_devlink_destroy_port(pf);\n \tice_vsi_release_all(pf);\n \tif (ice_is_peer_ena(pf)) {\n@@ -4004,6 +4097,13 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)\n \t\t (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER))\n \t\tret = ice_cfg_vlan_pruning(vsi, false, false);\n \n+\tif ((features & NETIF_F_NTUPLE) &&\n+\t    !(netdev->features & NETIF_F_NTUPLE))\n+\t\tice_vsi_manage_fdir(vsi, true);\n+\telse if (!(features & NETIF_F_NTUPLE) &&\n+\t\t (netdev->features & NETIF_F_NTUPLE))\n+\t\tice_vsi_manage_fdir(vsi, false);\n+\n \treturn ret;\n }\n \n@@ -4558,6 +4658,62 @@ int ice_vsi_setup_rx_rings(struct ice_vsi *vsi)\n \treturn err;\n }\n \n+/**\n+ * ice_vsi_open_ctrl - open control VSI for use\n+ * @vsi: the VSI to open\n+ *\n+ * Initialization of the Control VSI\n+ *\n+ * Returns 0 on success, negative value on error\n+ */\n+int ice_vsi_open_ctrl(struct ice_vsi *vsi)\n+{\n+\tchar int_name[ICE_INT_NAME_STR_LEN];\n+\tstruct ice_pf *pf = vsi->back;\n+\tstruct device *dev;\n+\tint err;\n+\n+\tdev = ice_pf_to_dev(pf);\n+\t/* allocate descriptors */\n+\terr = ice_vsi_setup_tx_rings(vsi);\n+\tif (err)\n+\t\tgoto err_setup_tx;\n+\n+\terr = ice_vsi_setup_rx_rings(vsi);\n+\tif (err)\n+\t\tgoto err_setup_rx;\n+\n+\terr = ice_vsi_cfg(vsi);\n+\tif (err)\n+\t\tgoto err_setup_rx;\n+\n+\tsnprintf(int_name, sizeof(int_name) - 1, \"%s-%s:ctrl\",\n+\t\t dev_driver_string(dev), dev_name(dev));\n+\terr = ice_vsi_req_irq_msix(vsi, int_name);\n+\tif (err)\n+\t\tgoto err_setup_rx;\n+\n+\tice_vsi_cfg_msix(vsi);\n+\n+\terr = ice_vsi_start_all_rx_rings(vsi);\n+\tif (err)\n+\t\tgoto err_up_complete;\n+\n+\tclear_bit(__ICE_DOWN, vsi->state);\n+\tice_vsi_ena_irq(vsi);\n+\n+\treturn 0;\n+\n+err_up_complete:\n+\tice_down(vsi);\n+err_setup_rx:\n+\tice_vsi_free_rx_rings(vsi);\n+err_setup_tx:\n+\tice_vsi_free_tx_rings(vsi);\n+\n+\treturn err;\n+}\n+\n /**\n  * ice_vsi_open - Called when a network interface is made active\n  * @vsi: the VSI to open\ndiff --git a/drivers/net/ethernet/intel/ice/ice_protocol_type.h b/drivers/net/ethernet/intel/ice/ice_protocol_type.h\nindex 678db6bf7f57..babe4a485fd6 100644\n--- a/drivers/net/ethernet/intel/ice/ice_protocol_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_protocol_type.h\n@@ -17,6 +17,7 @@ enum ice_prot_id {\n \tICE_PROT_IPV6_OF_OR_S\t= 40,\n \tICE_PROT_IPV6_IL\t= 41,\n \tICE_PROT_TCP_IL\t\t= 49,\n+\tICE_PROT_UDP_OF\t\t= 52,\n \tICE_PROT_UDP_IL_OR_S\t= 53,\n \tICE_PROT_GRE_OF\t\t= 64,\n \tICE_PROT_SCTP_IL\t= 96,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c\nindex b672edeba7bc..5760f2a3a8a4 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.c\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.c\n@@ -2704,6 +2704,81 @@ void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)\n \tice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN);\n }\n \n+/**\n+ * ice_alloc_res_cntr - allocating resource counter\n+ * @hw: pointer to the hardware structure\n+ * @type: type of resource\n+ * @alloc_shared: if set it is shared else dedicated\n+ * @num_items: number of entries requested for FD resource type\n+ * @counter_id: counter index returned by AQ call\n+ */\n+enum ice_status\n+ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,\n+\t\t   u16 *counter_id)\n+{\n+\tstruct ice_aqc_alloc_free_res_elem *buf;\n+\tenum ice_status status;\n+\tu16 buf_len;\n+\n+\t/* Allocate resource */\n+\tbuf_len = sizeof(*buf);\n+\tbuf = kzalloc(buf_len, GFP_KERNEL);\n+\tif (!buf)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tbuf->num_elems = cpu_to_le16(num_items);\n+\tbuf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &\n+\t\t\t\t      ICE_AQC_RES_TYPE_M) | alloc_shared);\n+\n+\tstatus = ice_aq_alloc_free_res(hw, 1, buf, buf_len,\n+\t\t\t\t       ice_aqc_opc_alloc_res, NULL);\n+\tif (status)\n+\t\tgoto exit;\n+\n+\t*counter_id = le16_to_cpu(buf->elem[0].e.sw_resp);\n+\n+exit:\n+\tkfree(buf);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_free_res_cntr - free resource counter\n+ * @hw: pointer to the hardware structure\n+ * @type: type of resource\n+ * @alloc_shared: if set it is shared else dedicated\n+ * @num_items: number of entries to be freed for FD resource type\n+ * @counter_id: counter ID resource which needs to be freed\n+ */\n+enum ice_status\n+ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,\n+\t\t  u16 counter_id)\n+{\n+\tstruct ice_aqc_alloc_free_res_elem *buf;\n+\tenum ice_status status;\n+\tu16 buf_len;\n+\n+\t/* Free resource */\n+\tbuf_len = sizeof(*buf);\n+\tbuf = kzalloc(buf_len, GFP_KERNEL);\n+\tif (!buf)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tbuf->num_elems = cpu_to_le16(num_items);\n+\tbuf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &\n+\t\t\t\t      ICE_AQC_RES_TYPE_M) | alloc_shared);\n+\tbuf->elem[0].e.sw_resp = cpu_to_le16(counter_id);\n+\n+\tstatus = ice_aq_alloc_free_res(hw, 1, buf, buf_len,\n+\t\t\t\t       ice_aqc_opc_free_res, NULL);\n+\tif (status)\n+\t\tice_debug(hw, ICE_DBG_SW,\n+\t\t\t  \"counter resource could not be freed\\n\");\n+\n+\tkfree(buf);\n+\treturn status;\n+}\n+\n /**\n  * ice_replay_vsi_fltr - Replay filters for requested VSI\n  * @hw: pointer to the hardware structure\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h\nindex acd2f150c30b..2232c17cbbaf 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.h\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.h\n@@ -210,6 +210,13 @@ 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_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,\n+\t\t   u16 *counter_id);\n+enum ice_status\n+ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,\n+\t\t  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 ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c\nindex e3b72368af3c..df802f0d1938 100644\n--- a/drivers/net/ethernet/intel/ice/ice_txrx.c\n+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c\n@@ -15,6 +15,8 @@\n \n #define ICE_RX_HDR_SIZE\t\t256\n \n+#define FDIR_DESC_RXDID 0x40\n+\n /**\n  * ice_unmap_and_free_tx_buf - Release a Tx buffer\n  * @ring: the ring that owns the buffer\n@@ -24,7 +26,9 @@ static void\n ice_unmap_and_free_tx_buf(struct ice_ring *ring, struct ice_tx_buf *tx_buf)\n {\n \tif (tx_buf->skb) {\n-\t\tif (ice_ring_is_xdp(ring))\n+\t\tif (tx_buf->tx_flags & ICE_TX_FLAGS_DUMMY_PKT)\n+\t\t\tdevm_kfree(ring->dev, tx_buf->raw_buf);\n+\t\telse if (ice_ring_is_xdp(ring))\n \t\t\tpage_frag_free(tx_buf->raw_buf);\n \t\telse\n \t\t\tdev_kfree_skb_any(tx_buf->skb);\n@@ -583,7 +587,8 @@ bool ice_alloc_rx_bufs(struct ice_ring *rx_ring, u16 cleaned_count)\n \tstruct ice_rx_buf *bi;\n \n \t/* do nothing if no valid netdev defined */\n-\tif (!rx_ring->netdev || !cleaned_count)\n+\tif ((!rx_ring->netdev && rx_ring->vsi->type != ICE_VSI_CTRL) ||\n+\t    !cleaned_count)\n \t\treturn false;\n \n \t/* get the Rx descriptor and buffer based on next_to_use */\n@@ -981,7 +986,7 @@ ice_is_non_eop(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc,\n  *\n  * Returns amount of work completed\n  */\n-static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)\n+int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)\n {\n \tunsigned int total_rx_bytes = 0, total_rx_pkts = 0;\n \tu16 cleaned_count = ICE_DESC_UNUSED(rx_ring);\n@@ -1020,6 +1025,12 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)\n \t\t */\n \t\tdma_rmb();\n \n+\t\tif (rx_desc->wb.rxdid == FDIR_DESC_RXDID || !rx_ring->netdev) {\n+\t\t\tice_put_rx_buf(rx_ring, NULL);\n+\t\t\tcleaned_count++;\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\tsize = le16_to_cpu(rx_desc->wb.pkt_len) &\n \t\t\tICE_RX_FLX_DESC_PKT_LEN_M;\n \n@@ -2362,3 +2373,86 @@ netdev_tx_t ice_start_xmit(struct sk_buff *skb, struct net_device *netdev)\n \n \treturn ice_xmit_frame_ring(skb, tx_ring);\n }\n+\n+/**\n+ * ice_clean_ctrl_tx_irq - interrupt handler for flow director Tx queue\n+ * @tx_ring: tx_ring to clean\n+ */\n+void ice_clean_ctrl_tx_irq(struct ice_ring *tx_ring)\n+{\n+\tstruct ice_vsi *vsi = tx_ring->vsi;\n+\ts16 i = tx_ring->next_to_clean;\n+\tint budget = ICE_DFLT_IRQ_WORK;\n+\tstruct ice_tx_desc *tx_desc;\n+\tstruct ice_tx_buf *tx_buf;\n+\n+\ttx_buf = &tx_ring->tx_buf[i];\n+\ttx_desc = ICE_TX_DESC(tx_ring, i);\n+\ti -= tx_ring->count;\n+\n+\tdo {\n+\t\tstruct ice_tx_desc *eop_desc = tx_buf->next_to_watch;\n+\n+\t\t/* if next_to_watch is not set then there is no pending work */\n+\t\tif (!eop_desc)\n+\t\t\tbreak;\n+\n+\t\t/* prevent any other reads prior to eop_desc */\n+\t\tsmp_rmb();\n+\n+\t\t/* if the descriptor isn't done, no work to do */\n+\t\tif (!(eop_desc->cmd_type_offset_bsz &\n+\t\t      cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE)))\n+\t\t\tbreak;\n+\n+\t\t/* clear next_to_watch to prevent false hangs */\n+\t\ttx_buf->next_to_watch = NULL;\n+\t\ttx_desc->buf_addr = 0;\n+\t\ttx_desc->cmd_type_offset_bsz = 0;\n+\n+\t\t/* move past filter desc */\n+\t\ttx_buf++;\n+\t\ttx_desc++;\n+\t\ti++;\n+\t\tif (unlikely(!i)) {\n+\t\t\ti -= tx_ring->count;\n+\t\t\ttx_buf = tx_ring->tx_buf;\n+\t\t\ttx_desc = ICE_TX_DESC(tx_ring, 0);\n+\t\t}\n+\n+\t\t/* unmap the data header */\n+\t\tif (dma_unmap_len(tx_buf, len))\n+\t\t\tdma_unmap_single(tx_ring->dev,\n+\t\t\t\t\t dma_unmap_addr(tx_buf, dma),\n+\t\t\t\t\t dma_unmap_len(tx_buf, len),\n+\t\t\t\t\t DMA_TO_DEVICE);\n+\t\tif (tx_buf->tx_flags & ICE_TX_FLAGS_DUMMY_PKT)\n+\t\t\tdevm_kfree(tx_ring->dev, tx_buf->raw_buf);\n+\n+\t\t/* clear next_to_watch to prevent false hangs */\n+\t\ttx_buf->raw_buf = NULL;\n+\t\ttx_buf->tx_flags = 0;\n+\t\ttx_buf->next_to_watch = NULL;\n+\t\tdma_unmap_len_set(tx_buf, len, 0);\n+\t\ttx_desc->buf_addr = 0;\n+\t\ttx_desc->cmd_type_offset_bsz = 0;\n+\n+\t\t/* move past eop_desc for start of next FD desc */\n+\t\ttx_buf++;\n+\t\ttx_desc++;\n+\t\ti++;\n+\t\tif (unlikely(!i)) {\n+\t\t\ti -= tx_ring->count;\n+\t\t\ttx_buf = tx_ring->tx_buf;\n+\t\t\ttx_desc = ICE_TX_DESC(tx_ring, 0);\n+\t\t}\n+\n+\t\tbudget--;\n+\t} while (likely(budget));\n+\n+\ti += tx_ring->count;\n+\ttx_ring->next_to_clean = i;\n+\n+\t/* re-enable interrupt if needed */\n+\tice_irq_dynamic_ena(&vsi->back->hw, vsi, vsi->q_vectors[0]);\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h\nindex 025dd642cf28..2209583c993e 100644\n--- a/drivers/net/ethernet/intel/ice/ice_txrx.h\n+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h\n@@ -113,6 +113,10 @@ static inline int ice_skb_pad(void)\n #define ICE_TX_FLAGS_TSO\tBIT(0)\n #define ICE_TX_FLAGS_HW_VLAN\tBIT(1)\n #define ICE_TX_FLAGS_SW_VLAN\tBIT(2)\n+/* ICE_TX_FLAGS_DUMMY_PKT is used to mark dummy packets that should be\n+ * freed instead of returned like skb packets.\n+ */\n+#define ICE_TX_FLAGS_DUMMY_PKT\tBIT(3)\n #define ICE_TX_FLAGS_IPV4\tBIT(5)\n #define ICE_TX_FLAGS_IPV6\tBIT(6)\n #define ICE_TX_FLAGS_TUNNEL\tBIT(7)\n@@ -376,5 +380,6 @@ int ice_setup_rx_ring(struct ice_ring *rx_ring);\n void ice_free_tx_ring(struct ice_ring *tx_ring);\n void ice_free_rx_ring(struct ice_ring *rx_ring);\n int ice_napi_poll(struct napi_struct *napi, int budget);\n-\n+int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget);\n+void ice_clean_ctrl_tx_irq(struct ice_ring *tx_ring);\n #endif /* _ICE_TXRX_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h\nindex 002eb6506303..571f707544c6 100644\n--- a/drivers/net/ethernet/intel/ice/ice_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_type.h\n@@ -119,7 +119,8 @@ enum ice_media_type {\n \n enum ice_vsi_type {\n \tICE_VSI_PF = 0,\n-\tICE_VSI_VF,\n+\tICE_VSI_VF = 1,\n+\tICE_VSI_CTRL = 3,\t/* equates to ICE_VSI_PF with 1 queue pair */\n \tICE_VSI_LB = 6,\n };\n \n@@ -162,6 +163,34 @@ struct ice_phy_info {\n \tu8 get_link_info;\n };\n \n+/* protocol enumeration for filters */\n+enum ice_fltr_ptype {\n+\t/* NONE - used for undef/error */\n+\tICE_FLTR_PTYPE_NONF_NONE = 0,\n+\tICE_FLTR_PTYPE_NONF_IPV4_UDP,\n+\tICE_FLTR_PTYPE_NONF_IPV4_TCP,\n+\tICE_FLTR_PTYPE_NONF_IPV4_SCTP,\n+\tICE_FLTR_PTYPE_NONF_IPV4_OTHER,\n+\tICE_FLTR_PTYPE_FRAG_IPV4,\n+\tICE_FLTR_PTYPE_MAX,\n+};\n+\n+enum ice_fd_hw_seg {\n+\tICE_FD_HW_SEG_NON_TUN = 0,\n+\tICE_FD_HW_SEG_TUN,\n+\tICE_FD_HW_SEG_MAX,\n+};\n+\n+/* 2 VSI = 1 ICE_VSI_PF + 1 ICE_VSI_CTRL */\n+#define ICE_MAX_FDIR_VSI_PER_FILTER\t2\n+\n+struct ice_fd_hw_prof {\n+\tstruct ice_flow_seg_info *fdir_seg[ICE_FD_HW_SEG_MAX];\n+\tint cnt;\n+\tu64 entry_h[ICE_MAX_FDIR_VSI_PER_FILTER][ICE_FD_HW_SEG_MAX];\n+\tu16 vsi_h[ICE_MAX_FDIR_VSI_PER_FILTER];\n+};\n+\n /* Common HW capabilities for SW use */\n struct ice_hw_common_caps {\n \tu32 valid_functions;\n@@ -199,6 +228,8 @@ struct ice_hw_func_caps {\n \tu32 num_allocd_vfs;\t\t/* Number of allocated VFs */\n \tu32 vf_base_id;\t\t\t/* Logical ID of the first VF */\n \tu32 guar_num_vsi;\n+\tu32 fd_fltr_guar;\t\t/* Number of filters guaranteed */\n+\tu32 fd_fltr_best_effort;\t/* Number of best effort filters */\n };\n \n /* Device wide capabilities */\n@@ -206,6 +237,7 @@ struct ice_hw_dev_caps {\n \tstruct ice_hw_common_caps common_cap;\n \tu32 num_vfs_exposed;\t\t/* Total number of VFs exposed */\n \tu32 num_vsi_allocd_to_host;\t/* Excluding EMP VSI */\n+\tu32 num_flow_director_fltr;\t/* Number of FD filters available */\n \tu32 num_funcs;\n };\n \n@@ -493,6 +525,8 @@ struct ice_hw {\n \tu64 debug_mask;\t\t/* bitmap for debug mask */\n \tenum ice_mac_type mac_type;\n \n+\tu16 fd_ctr_base;\t/* FD counter base index */\n+\n \t/* pci info */\n \tu16 device_id;\n \tu16 vendor_id;\n@@ -591,6 +625,15 @@ struct ice_hw {\n \tstruct ice_blk_info blk[ICE_BLK_COUNT];\n \tstruct mutex fl_profs_locks[ICE_BLK_COUNT];\t/* lock fltr profiles */\n \tstruct list_head fl_profs[ICE_BLK_COUNT];\n+\n+\t/* Flow Director filter info */\n+\tint fdir_active_fltr;\n+\n+\tstruct mutex fdir_fltr_lock;\t/* protect Flow Director */\n+\tstruct list_head fdir_list_head;\n+\n+\tstruct ice_fd_hw_prof **fdir_prof;\n+\tDECLARE_BITMAP(fdir_perfect_fltr, ICE_FLTR_PTYPE_MAX);\n \tstruct mutex rss_locks;\t/* protect RSS configuration */\n \tstruct list_head rss_list_head;\n };\n",
    "prefixes": [
        "S42",
        "1/7"
    ]
}