Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1288150/?format=api
{ "id": 1288150, "url": "http://patchwork.ozlabs.org/api/patches/1288150/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20200512010146.41303-7-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-7-anthony.l.nguyen@intel.com>", "list_archive_url": null, "date": "2020-05-12T01:01:46", "name": "[S42,7/7] ice: Implement aRFS", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "7042c1bc9c14a5163481819a7999579aaf11bd22", "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-7-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/1288150/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1288150/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.138; helo=whitealder.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 whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\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 49Lfj6043Dz9sSW\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 12 May 2020 11:04:42 +1000 (AEST)", "from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 832EE8696A;\n\tTue, 12 May 2020 01:04:40 +0000 (UTC)", "from whitealder.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id ubXBOcZF-nTV; Tue, 12 May 2020 01:04:28 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id BCFA1869F8;\n\tTue, 12 May 2020 01:04:26 +0000 (UTC)", "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n by ash.osuosl.org (Postfix) with ESMTP id A915B1BF841\n for <intel-wired-lan@lists.osuosl.org>; Tue, 12 May 2020 01:04:23 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n by fraxinus.osuosl.org (Postfix) with ESMTP id A4245875C9\n for <intel-wired-lan@lists.osuosl.org>; Tue, 12 May 2020 01:04:23 +0000 (UTC)", "from fraxinus.osuosl.org ([127.0.0.1])\n by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id Q0MySbGBadpL for <intel-wired-lan@lists.osuosl.org>;\n Tue, 12 May 2020 01:04:21 +0000 (UTC)", "from mga18.intel.com (mga18.intel.com [134.134.136.126])\n by fraxinus.osuosl.org (Postfix) with ESMTPS id 2B7E2875BF\n for <intel-wired-lan@lists.osuosl.org>; Tue, 12 May 2020 01:04:21 +0000 (UTC)", "from orsmga004.jf.intel.com ([10.7.209.38])\n by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 11 May 2020 18:04:20 -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:19 -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 d00lQwnRMPfmqBdb4TFWT9VualW3/64Bece8a1661EiLfzibQq2l9jHD1/43zlrW+0UeOBOd2D\n tOXbdBOH+5Pw==", "\n tEAkvU9nPCyAVP6052uqvXDgOf7dKB0IFGbdkMw0PLHbZCh9tMfGXriQyRB/Sso3R3+u7MSCRd\n v9Fp6nmKyA5A==" ], "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=\"409116470\"", "From": "Tony Nguyen <anthony.l.nguyen@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Mon, 11 May 2020 18:01:46 -0700", "Message-Id": "<20200512010146.41303-7-anthony.l.nguyen@intel.com>", "X-Mailer": "git-send-email 2.20.1", "In-Reply-To": "<20200512010146.41303-1-anthony.l.nguyen@intel.com>", "References": "<20200512010146.41303-1-anthony.l.nguyen@intel.com>", "MIME-Version": "1.0", "Subject": "[Intel-wired-lan] [PATCH S42 7/7] ice: Implement aRFS", "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: Brett Creeley <brett.creeley@intel.com>\n\nEnable accelerated Receive Flow Steering (aRFS). It is used to steer Rx\nflows to a specific queue. This functionality is triggerred by the network\nstack through ndo_rx_flow_steer and requires Flow Director (ntuple on) to\nfunction.\n\nThe fltr_info is used to add/remove/update flow rules in the HW, the\nfltr_state is used to determine what to do with the filter with respect\nto HW and/or SW, and the flow_id is used in co-ordination with the\nnetwork stack.\n\nThe work for aRFS is split into two paths: the ndo_rx_flow_steer\noperation and the ice_service_task. The former is where the kernel hands\nus an Rx SKB among other items to setup aRFS and the latter is where\nthe driver adds/updates/removes filter rules from HW and updates filter\nstate.\n\nIn the Rx path the following things can happen:\n 1. New aRFS entries are added to the hash table and the state is\n set to ICE_ARFS_INACTIVE so the filter can be updated in HW\n by the ice_service_task path.\n 2. aRFS entries have their Rx Queue updated if we receive a\n pre-existing flow_id and the filter state is ICE_ARFS_ACTIVE.\n The state is set to ICE_ARFS_INACTIVE so the filter can be\n updated in HW by the ice_service_task path.\n 3. aRFS entries marked as ICE_ARFS_TODEL are deleted\n\nIn the ice_service_task path the following things can happen:\n 1. New aRFS entries marked as ICE_ARFS_INACTIVE are added or\n updated in HW.\n and their state is updated to ICE_ARFS_ACTIVE.\n 2. aRFS entries are deleted from HW and their state is updated\n to ICE_ARFS_TODEL.\n\nSigned-off-by: Brett Creeley <brett.creeley@intel.com>\nSigned-off-by: Madhu Chittim <madhu.chittim@intel.com>\nSigned-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>\n---\n drivers/net/ethernet/intel/ice/Makefile | 1 +\n drivers/net/ethernet/intel/ice/ice.h | 14 +\n drivers/net/ethernet/intel/ice/ice_arfs.c | 663 ++++++++++++++++++\n drivers/net/ethernet/intel/ice/ice_arfs.h | 82 +++\n .../net/ethernet/intel/ice/ice_ethtool_fdir.c | 8 +-\n drivers/net/ethernet/intel/ice/ice_lib.c | 1 +\n drivers/net/ethernet/intel/ice/ice_main.c | 48 +-\n 7 files changed, 805 insertions(+), 12 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/ice/ice_arfs.c\n create mode 100644 drivers/net/ethernet/intel/ice/ice_arfs.h", "diff": "diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile\nindex 8bda3796a853..14b27a4f5d45 100644\n--- a/drivers/net/ethernet/intel/ice/Makefile\n+++ b/drivers/net/ethernet/intel/ice/Makefile\n@@ -27,4 +27,5 @@ ice-y := ice_main.o\t\\\n \t ice_ethtool.o\n ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o\n ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o\n+ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o\n ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o\ndiff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex 4d011def973a..8e877860a96f 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -34,6 +34,7 @@\n #include <linux/ctype.h>\n #include <linux/bpf.h>\n #include <linux/avf/virtchnl.h>\n+#include <linux/cpu_rmap.h>\n #include <net/devlink.h>\n #include <net/ipv6.h>\n #include <net/xdp_sock.h>\n@@ -53,6 +54,7 @@\n #include \"ice_sriov.h\"\n #include \"ice_fdir.h\"\n #include \"ice_xsk.h\"\n+#include \"ice_arfs.h\"\n \n extern const char ice_drv_ver[];\n #define ICE_BAR0\t\t0\n@@ -274,6 +276,14 @@ struct ice_vsi {\n \tu8 *rss_lut_user;\t/* User configured lookup table entries */\n \tu8 rss_lut_type;\t/* used to configure Get/Set RSS LUT AQ call */\n \n+\t/* aRFS members only allocated for the PF VSI */\n+#define ICE_MAX_ARFS_LIST\t1024\n+#define ICE_ARFS_LST_MASK\t(ICE_MAX_ARFS_LIST - 1)\n+\tstruct hlist_head *arfs_fltr_list;\n+\tstruct ice_arfs_active_fltr_cntrs *arfs_fltr_cntrs;\n+\tspinlock_t arfs_lock;\t/* protects aRFS hash table and filter state */\n+\tatomic_t *arfs_last_fltr_id;\n+\n \tu16 max_frame;\n \tu16 rx_buf_len;\n \n@@ -572,6 +582,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+int\n+ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add,\n+\t\t bool is_tun);\n void ice_vsi_manage_fdir(struct ice_vsi *vsi, bool ena);\n int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd);\n int ice_del_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd);\n@@ -585,5 +598,6 @@ void ice_fdir_replay_fltrs(struct ice_pf *pf);\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+void ice_service_task_schedule(struct ice_pf *pf);\n \n #endif /* _ICE_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_arfs.c b/drivers/net/ethernet/intel/ice/ice_arfs.c\nnew file mode 100644\nindex 000000000000..bed8c2f9177e\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_arfs.c\n@@ -0,0 +1,663 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (C) 2018-2019, Intel Corporation. */\n+\n+#include \"ice.h\"\n+\n+/**\n+ * ice_is_arfs_active - helper to check is aRFS is active\n+ * @vsi: VSI to check\n+ */\n+static bool ice_is_arfs_active(struct ice_vsi *vsi)\n+{\n+\treturn !!vsi->arfs_fltr_list;\n+}\n+\n+/**\n+ * ice_is_arfs_using_perfect_flow - check if aRFS has active perfect filters\n+ * @hw: pointer to the HW structure\n+ * @flow_type: flow type as Flow Director understands it\n+ *\n+ * Flow Director will query this function to see if aRFS is currently using\n+ * the specified flow_type for perfect (4-tuple) filters.\n+ */\n+bool\n+ice_is_arfs_using_perfect_flow(struct ice_hw *hw, enum ice_fltr_ptype flow_type)\n+{\n+\tstruct ice_arfs_active_fltr_cntrs *arfs_fltr_cntrs;\n+\tstruct ice_pf *pf = hw->back;\n+\tstruct ice_vsi *vsi;\n+\n+\tvsi = ice_get_main_vsi(pf);\n+\tif (!vsi)\n+\t\treturn false;\n+\n+\tarfs_fltr_cntrs = vsi->arfs_fltr_cntrs;\n+\n+\t/* active counters can be updated by multiple CPUs */\n+\tsmp_mb__before_atomic();\n+\tswitch (flow_type) {\n+\tcase ICE_FLTR_PTYPE_NONF_IPV4_UDP:\n+\t\treturn atomic_read(&arfs_fltr_cntrs->active_udpv4_cnt) > 0;\n+\tcase ICE_FLTR_PTYPE_NONF_IPV6_UDP:\n+\t\treturn atomic_read(&arfs_fltr_cntrs->active_udpv6_cnt) > 0;\n+\tcase ICE_FLTR_PTYPE_NONF_IPV4_TCP:\n+\t\treturn atomic_read(&arfs_fltr_cntrs->active_tcpv4_cnt) > 0;\n+\tcase ICE_FLTR_PTYPE_NONF_IPV6_TCP:\n+\t\treturn atomic_read(&arfs_fltr_cntrs->active_tcpv6_cnt) > 0;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+}\n+\n+/**\n+ * ice_arfs_update_active_fltr_cntrs - update active filter counters for aRFS\n+ * @vsi: VSI that aRFS is active on\n+ * @entry: aRFS entry used to change counters\n+ * @add: true to increment counter, false to decrement\n+ */\n+static void\n+ice_arfs_update_active_fltr_cntrs(struct ice_vsi *vsi,\n+\t\t\t\t struct ice_arfs_entry *entry, bool add)\n+{\n+\tstruct ice_arfs_active_fltr_cntrs *fltr_cntrs = vsi->arfs_fltr_cntrs;\n+\n+\tswitch (entry->fltr_info.flow_type) {\n+\tcase ICE_FLTR_PTYPE_NONF_IPV4_TCP:\n+\t\tif (add)\n+\t\t\tatomic_inc(&fltr_cntrs->active_tcpv4_cnt);\n+\t\telse\n+\t\t\tatomic_dec(&fltr_cntrs->active_tcpv4_cnt);\n+\t\tbreak;\n+\tcase ICE_FLTR_PTYPE_NONF_IPV6_TCP:\n+\t\tif (add)\n+\t\t\tatomic_inc(&fltr_cntrs->active_tcpv6_cnt);\n+\t\telse\n+\t\t\tatomic_dec(&fltr_cntrs->active_tcpv6_cnt);\n+\t\tbreak;\n+\tcase ICE_FLTR_PTYPE_NONF_IPV4_UDP:\n+\t\tif (add)\n+\t\t\tatomic_inc(&fltr_cntrs->active_udpv4_cnt);\n+\t\telse\n+\t\t\tatomic_dec(&fltr_cntrs->active_udpv4_cnt);\n+\t\tbreak;\n+\tcase ICE_FLTR_PTYPE_NONF_IPV6_UDP:\n+\t\tif (add)\n+\t\t\tatomic_inc(&fltr_cntrs->active_udpv6_cnt);\n+\t\telse\n+\t\t\tatomic_dec(&fltr_cntrs->active_udpv6_cnt);\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_err(ice_pf_to_dev(vsi->back), \"aRFS: Failed to update filter counters, invalid filter type %d\\n\",\n+\t\t\tentry->fltr_info.flow_type);\n+\t}\n+}\n+\n+/**\n+ * ice_arfs_del_flow_rules - delete the rules passed in from HW\n+ * @vsi: VSI for the flow rules that need to be deleted\n+ * @del_list_head: head of the list of ice_arfs_entry(s) for rule deletion\n+ *\n+ * Loop through the delete list passed in and remove the rules from HW. After\n+ * each rule is deleted, disconnect and free the ice_arfs_entry because it is no\n+ * longer being referenced by the aRFS hash table.\n+ */\n+static void\n+ice_arfs_del_flow_rules(struct ice_vsi *vsi, struct hlist_head *del_list_head)\n+{\n+\tstruct ice_arfs_entry *e;\n+\tstruct hlist_node *n;\n+\tstruct device *dev;\n+\n+\tdev = ice_pf_to_dev(vsi->back);\n+\n+\thlist_for_each_entry_safe(e, n, del_list_head, list_entry) {\n+\t\tint result;\n+\n+\t\tresult = ice_fdir_write_fltr(vsi->back, &e->fltr_info, false,\n+\t\t\t\t\t false);\n+\t\tif (!result)\n+\t\t\tice_arfs_update_active_fltr_cntrs(vsi, e, false);\n+\t\telse\n+\t\t\tdev_dbg(dev, \"Unable to delete aRFS entry, err %d fltr_state %d fltr_id %d flow_id %d Q %d\\n\",\n+\t\t\t\tresult, e->fltr_state, e->fltr_info.fltr_id,\n+\t\t\t\te->flow_id, e->fltr_info.q_index);\n+\n+\t\t/* The aRFS hash table is no longer referencing this entry */\n+\t\thlist_del(&e->list_entry);\n+\t\tdevm_kfree(dev, e);\n+\t}\n+}\n+\n+/**\n+ * ice_arfs_add_flow_rules - add the rules passed in from HW\n+ * @vsi: VSI for the flow rules that need to be added\n+ * @add_list_head: head of the list of ice_arfs_entry_ptr(s) for rule addition\n+ *\n+ * Loop through the add list passed in and remove the rules from HW. After each\n+ * rule is added, disconnect and free the ice_arfs_entry_ptr node. Don't free\n+ * the ice_arfs_entry(s) because they are still being referenced in the aRFS\n+ * hash table.\n+ */\n+static void\n+ice_arfs_add_flow_rules(struct ice_vsi *vsi, struct hlist_head *add_list_head)\n+{\n+\tstruct ice_arfs_entry_ptr *ep;\n+\tstruct hlist_node *n;\n+\tstruct device *dev;\n+\n+\tdev = ice_pf_to_dev(vsi->back);\n+\n+\thlist_for_each_entry_safe(ep, n, add_list_head, list_entry) {\n+\t\tint result;\n+\n+\t\tresult = ice_fdir_write_fltr(vsi->back,\n+\t\t\t\t\t &ep->arfs_entry->fltr_info, true,\n+\t\t\t\t\t false);\n+\t\tif (!result)\n+\t\t\tice_arfs_update_active_fltr_cntrs(vsi, ep->arfs_entry,\n+\t\t\t\t\t\t\t true);\n+\t\telse\n+\t\t\tdev_dbg(dev, \"Unable to add aRFS entry, err %d fltr_state %d fltr_id %d flow_id %d Q %d\\n\",\n+\t\t\t\tresult, ep->arfs_entry->fltr_state,\n+\t\t\t\tep->arfs_entry->fltr_info.fltr_id,\n+\t\t\t\tep->arfs_entry->flow_id,\n+\t\t\t\tep->arfs_entry->fltr_info.q_index);\n+\n+\t\thlist_del(&ep->list_entry);\n+\t\tdevm_kfree(dev, ep);\n+\t}\n+}\n+\n+/**\n+ * ice_arfs_is_flow_expired - check if the aRFS entry has expired\n+ * @vsi: VSI containing the aRFS entry\n+ * @arfs_entry: aRFS entry that's being checked for expiration\n+ *\n+ * Return true if the flow has expired, else false. This function should be used\n+ * to determine whether or not an aRFS entry should be removed from the hardware\n+ * and software structures.\n+ */\n+static bool\n+ice_arfs_is_flow_expired(struct ice_vsi *vsi, struct ice_arfs_entry *arfs_entry)\n+{\n+#define ICE_ARFS_TIME_DELTA_EXPIRATION\tmsecs_to_jiffies(5000)\n+\tif (rps_may_expire_flow(vsi->netdev, arfs_entry->fltr_info.q_index,\n+\t\t\t\tarfs_entry->flow_id,\n+\t\t\t\tarfs_entry->fltr_info.fltr_id))\n+\t\treturn true;\n+\n+\t/* expiration timer only used for UDP filters */\n+\tif (arfs_entry->fltr_info.flow_type != ICE_FLTR_PTYPE_NONF_IPV4_UDP &&\n+\t arfs_entry->fltr_info.flow_type != ICE_FLTR_PTYPE_NONF_IPV6_UDP)\n+\t\treturn false;\n+\n+\treturn time_in_range64(arfs_entry->time_activated +\n+\t\t\t ICE_ARFS_TIME_DELTA_EXPIRATION,\n+\t\t\t arfs_entry->time_activated, get_jiffies_64());\n+}\n+\n+/**\n+ * ice_arfs_update_flow_rules - add/delete aRFS rules in HW\n+ * @vsi: the VSI to be forwarded to\n+ * @idx: index into the table of aRFS filter lists. Obtained from skb->hash\n+ * @add_list: list to populate with filters to be added to Flow Director\n+ * @del_list: list to populate with filters to be deleted from Flow Director\n+ *\n+ * Iterate over the hlist at the index given in the aRFS hash table and\n+ * determine if there are any aRFS entries that need to be either added or\n+ * deleted in the HW. If the aRFS entry is marked as ICE_ARFS_INACTIVE the\n+ * filter needs to be added to HW, else if it's marked as ICE_ARFS_ACTIVE and\n+ * the flow has expired delete the filter from HW. The caller of this function\n+ * is expected to add/delete rules on the add_list/del_list respectively.\n+ */\n+static void\n+ice_arfs_update_flow_rules(struct ice_vsi *vsi, u16 idx,\n+\t\t\t struct hlist_head *add_list,\n+\t\t\t struct hlist_head *del_list)\n+{\n+\tstruct ice_arfs_entry *e;\n+\tstruct hlist_node *n;\n+\tstruct device *dev;\n+\n+\tdev = ice_pf_to_dev(vsi->back);\n+\n+\t/* go through the aRFS hlist at this idx and check for needed updates */\n+\thlist_for_each_entry_safe(e, n, &vsi->arfs_fltr_list[idx], list_entry)\n+\t\t/* check if filter needs to be added to HW */\n+\t\tif (e->fltr_state == ICE_ARFS_INACTIVE) {\n+\t\t\tenum ice_fltr_ptype flow_type = e->fltr_info.flow_type;\n+\t\t\tstruct ice_arfs_entry_ptr *ep =\n+\t\t\t\tdevm_kzalloc(dev, sizeof(*ep), GFP_ATOMIC);\n+\n+\t\t\tif (!ep)\n+\t\t\t\tcontinue;\n+\t\t\tINIT_HLIST_NODE(&ep->list_entry);\n+\t\t\t/* reference aRFS entry to add HW filter */\n+\t\t\tep->arfs_entry = e;\n+\t\t\thlist_add_head(&ep->list_entry, add_list);\n+\t\t\te->fltr_state = ICE_ARFS_ACTIVE;\n+\t\t\t/* expiration timer only used for UDP flows */\n+\t\t\tif (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||\n+\t\t\t flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP)\n+\t\t\t\te->time_activated = get_jiffies_64();\n+\t\t} else if (e->fltr_state == ICE_ARFS_ACTIVE) {\n+\t\t\t/* check if filter needs to be removed from HW */\n+\t\t\tif (ice_arfs_is_flow_expired(vsi, e)) {\n+\t\t\t\t/* remove aRFS entry from hash table for delete\n+\t\t\t\t * and to prevent referencing it the next time\n+\t\t\t\t * through this hlist index\n+\t\t\t\t */\n+\t\t\t\thlist_del(&e->list_entry);\n+\t\t\t\te->fltr_state = ICE_ARFS_TODEL;\n+\t\t\t\t/* save reference to aRFS entry for delete */\n+\t\t\t\thlist_add_head(&e->list_entry, del_list);\n+\t\t\t}\n+\t\t}\n+}\n+\n+/**\n+ * ice_sync_arfs_fltrs - update all aRFS filters\n+ * @pf: board private structure\n+ */\n+void ice_sync_arfs_fltrs(struct ice_pf *pf)\n+{\n+\tHLIST_HEAD(tmp_del_list);\n+\tHLIST_HEAD(tmp_add_list);\n+\tstruct ice_vsi *pf_vsi;\n+\tunsigned int i;\n+\n+\tpf_vsi = ice_get_main_vsi(pf);\n+\tif (!pf_vsi)\n+\t\treturn;\n+\n+\tif (!ice_is_arfs_active(pf_vsi))\n+\t\treturn;\n+\n+\tspin_lock_bh(&pf_vsi->arfs_lock);\n+\t/* Once we process aRFS for the PF VSI get out */\n+\tfor (i = 0; i < ICE_MAX_ARFS_LIST; i++)\n+\t\tice_arfs_update_flow_rules(pf_vsi, i, &tmp_add_list,\n+\t\t\t\t\t &tmp_del_list);\n+\tspin_unlock_bh(&pf_vsi->arfs_lock);\n+\n+\t/* use list of ice_arfs_entry(s) for delete */\n+\tice_arfs_del_flow_rules(pf_vsi, &tmp_del_list);\n+\n+\t/* use list of ice_arfs_entry_ptr(s) for add */\n+\tice_arfs_add_flow_rules(pf_vsi, &tmp_add_list);\n+}\n+\n+/**\n+ * ice_arfs_build_entry - builds an aRFS entry based on input\n+ * @vsi: destination VSI for this flow\n+ * @fk: flow dissector keys for creating the tuple\n+ * @rxq_idx: Rx queue to steer this flow to\n+ * @flow_id: passed down from the stack and saved for flow expiration\n+ *\n+ * returns an aRFS entry on success and NULL on failure\n+ */\n+static struct ice_arfs_entry *\n+ice_arfs_build_entry(struct ice_vsi *vsi, const struct flow_keys *fk,\n+\t\t u16 rxq_idx, u32 flow_id)\n+{\n+\tstruct ice_arfs_entry *arfs_entry;\n+\tstruct ice_fdir_fltr *fltr_info;\n+\tu8 ip_proto;\n+\n+\tarfs_entry = devm_kzalloc(ice_pf_to_dev(vsi->back),\n+\t\t\t\t sizeof(*arfs_entry),\n+\t\t\t\t GFP_ATOMIC | __GFP_NOWARN);\n+\tif (!arfs_entry)\n+\t\treturn NULL;\n+\n+\tfltr_info = &arfs_entry->fltr_info;\n+\tfltr_info->q_index = rxq_idx;\n+\tfltr_info->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX;\n+\tfltr_info->dest_vsi = vsi->idx;\n+\tip_proto = fk->basic.ip_proto;\n+\n+\tif (fk->basic.n_proto == htons(ETH_P_IP)) {\n+\t\tfltr_info->ip.v4.proto = ip_proto;\n+\t\tfltr_info->flow_type = (ip_proto == IPPROTO_TCP) ?\n+\t\t\tICE_FLTR_PTYPE_NONF_IPV4_TCP :\n+\t\t\tICE_FLTR_PTYPE_NONF_IPV4_UDP;\n+\t\tfltr_info->ip.v4.src_ip = fk->addrs.v4addrs.src;\n+\t\tfltr_info->ip.v4.dst_ip = fk->addrs.v4addrs.dst;\n+\t\tfltr_info->ip.v4.src_port = fk->ports.src;\n+\t\tfltr_info->ip.v4.dst_port = fk->ports.dst;\n+\t} else { /* ETH_P_IPV6 */\n+\t\tfltr_info->ip.v6.proto = ip_proto;\n+\t\tfltr_info->flow_type = (ip_proto == IPPROTO_TCP) ?\n+\t\t\tICE_FLTR_PTYPE_NONF_IPV6_TCP :\n+\t\t\tICE_FLTR_PTYPE_NONF_IPV6_UDP;\n+\t\tmemcpy(&fltr_info->ip.v6.src_ip, &fk->addrs.v6addrs.src,\n+\t\t sizeof(struct in6_addr));\n+\t\tmemcpy(&fltr_info->ip.v6.dst_ip, &fk->addrs.v6addrs.dst,\n+\t\t sizeof(struct in6_addr));\n+\t\tfltr_info->ip.v6.src_port = fk->ports.src;\n+\t\tfltr_info->ip.v6.dst_port = fk->ports.dst;\n+\t}\n+\n+\tarfs_entry->flow_id = flow_id;\n+\tfltr_info->fltr_id =\n+\t\tatomic_inc_return(vsi->arfs_last_fltr_id) % RPS_NO_FILTER;\n+\n+\treturn arfs_entry;\n+}\n+\n+/**\n+ * ice_arfs_is_perfect_flow_set - Check to see if perfect flow is set\n+ * @hw: pointer to HW structure\n+ * @l3_proto: ETH_P_IP or ETH_P_IPV6 in network order\n+ * @l4_proto: IPPROTO_UDP or IPPROTO_TCP\n+ *\n+ * We only support perfect (4-tuple) filters for aRFS. This function allows aRFS\n+ * to check if perfect (4-tuple) flow rules are currently in place by Flow\n+ * Director.\n+ */\n+static bool\n+ice_arfs_is_perfect_flow_set(struct ice_hw *hw, __be16 l3_proto, u8 l4_proto)\n+{\n+\tunsigned long *perfect_fltr = hw->fdir_perfect_fltr;\n+\n+\t/* advanced Flow Director disabled, perfect filters always supported */\n+\tif (!perfect_fltr)\n+\t\treturn true;\n+\n+\tif (l3_proto == htons(ETH_P_IP) && l4_proto == IPPROTO_UDP)\n+\t\treturn test_bit(ICE_FLTR_PTYPE_NONF_IPV4_UDP, perfect_fltr);\n+\telse if (l3_proto == htons(ETH_P_IP) && l4_proto == IPPROTO_TCP)\n+\t\treturn test_bit(ICE_FLTR_PTYPE_NONF_IPV4_TCP, perfect_fltr);\n+\telse if (l3_proto == htons(ETH_P_IPV6) && l4_proto == IPPROTO_UDP)\n+\t\treturn test_bit(ICE_FLTR_PTYPE_NONF_IPV6_UDP, perfect_fltr);\n+\telse if (l3_proto == htons(ETH_P_IPV6) && l4_proto == IPPROTO_TCP)\n+\t\treturn test_bit(ICE_FLTR_PTYPE_NONF_IPV6_TCP, perfect_fltr);\n+\n+\treturn false;\n+}\n+\n+/**\n+ * ice_rx_flow_steer - steer the Rx flow to where application is being run\n+ * @netdev: ptr to the netdev being adjusted\n+ * @skb: buffer with required header information\n+ * @rxq_idx: queue to which the flow needs to move\n+ * @flow_id: flow identifier provided by the netdev\n+ *\n+ * Based on the skb, rxq_idx, and flow_id passed in add/update an entry in the\n+ * aRFS hash table. Iterate over one of the hlists in the aRFS hash table and\n+ * if the flow_id already exists in the hash table but the rxq_idx has changed\n+ * mark the entry as ICE_ARFS_INACTIVE so it can get updated in HW, else\n+ * if the entry is marked as ICE_ARFS_TODEL delete it from the aRFS hash table.\n+ * If neither of the previous conditions are true then add a new entry in the\n+ * aRFS hash table, which gets set to ICE_ARFS_INACTIVE by default so it can be\n+ * added to HW.\n+ */\n+int\n+ice_rx_flow_steer(struct net_device *netdev, const struct sk_buff *skb,\n+\t\t u16 rxq_idx, u32 flow_id)\n+{\n+\tstruct ice_netdev_priv *np = netdev_priv(netdev);\n+\tstruct ice_arfs_entry *arfs_entry;\n+\tstruct ice_vsi *vsi = np->vsi;\n+\tstruct flow_keys fk;\n+\tstruct ice_pf *pf;\n+\t__be16 n_proto;\n+\tu8 ip_proto;\n+\tu16 idx;\n+\tint ret;\n+\n+\t/* failed to allocate memory for aRFS so don't crash */\n+\tif (unlikely(!vsi->arfs_fltr_list))\n+\t\treturn -ENODEV;\n+\n+\tpf = vsi->back;\n+\n+\tif (skb->encapsulation)\n+\t\treturn -EPROTONOSUPPORT;\n+\n+\tif (!skb_flow_dissect_flow_keys(skb, &fk, 0))\n+\t\treturn -EPROTONOSUPPORT;\n+\n+\tn_proto = fk.basic.n_proto;\n+\t/* Support only IPV4 and IPV6 */\n+\tif ((n_proto == htons(ETH_P_IP) && !ip_is_fragment(ip_hdr(skb))) ||\n+\t n_proto == htons(ETH_P_IPV6))\n+\t\tip_proto = fk.basic.ip_proto;\n+\telse\n+\t\treturn -EPROTONOSUPPORT;\n+\n+\t/* Support only TCP and UDP */\n+\tif (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP)\n+\t\treturn -EPROTONOSUPPORT;\n+\n+\t/* only support 4-tuple filters for aRFS */\n+\tif (!ice_arfs_is_perfect_flow_set(&pf->hw, n_proto, ip_proto))\n+\t\treturn -EOPNOTSUPP;\n+\n+\t/* choose the aRFS list bucket based on skb hash */\n+\tidx = skb_get_hash_raw(skb) & ICE_ARFS_LST_MASK;\n+\t/* search for entry in the bucket */\n+\tspin_lock_bh(&vsi->arfs_lock);\n+\thlist_for_each_entry(arfs_entry, &vsi->arfs_fltr_list[idx],\n+\t\t\t list_entry) {\n+\t\tstruct ice_fdir_fltr *fltr_info;\n+\n+\t\t/* keep searching for the already existing arfs_entry flow */\n+\t\tif (arfs_entry->flow_id != flow_id)\n+\t\t\tcontinue;\n+\n+\t\tfltr_info = &arfs_entry->fltr_info;\n+\t\tret = fltr_info->fltr_id;\n+\n+\t\tif (fltr_info->q_index == rxq_idx ||\n+\t\t arfs_entry->fltr_state != ICE_ARFS_ACTIVE)\n+\t\t\tgoto out;\n+\n+\t\t/* update the queue to forward to on an already existing flow */\n+\t\tfltr_info->q_index = rxq_idx;\n+\t\tarfs_entry->fltr_state = ICE_ARFS_INACTIVE;\n+\t\tice_arfs_update_active_fltr_cntrs(vsi, arfs_entry, false);\n+\t\tgoto out_schedule_service_task;\n+\t}\n+\n+\tarfs_entry = ice_arfs_build_entry(vsi, &fk, rxq_idx, flow_id);\n+\tif (!arfs_entry) {\n+\t\tret = -ENOMEM;\n+\t\tgoto out;\n+\t}\n+\n+\tret = arfs_entry->fltr_info.fltr_id;\n+\tINIT_HLIST_NODE(&arfs_entry->list_entry);\n+\thlist_add_head(&arfs_entry->list_entry, &vsi->arfs_fltr_list[idx]);\n+out_schedule_service_task:\n+\tice_service_task_schedule(pf);\n+out:\n+\tspin_unlock_bh(&vsi->arfs_lock);\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_init_arfs_cntrs - initialize aRFS counter values\n+ * @vsi: VSI that aRFS counters need to be initialized on\n+ */\n+static int ice_init_arfs_cntrs(struct ice_vsi *vsi)\n+{\n+\tif (!vsi || vsi->type != ICE_VSI_PF)\n+\t\treturn -EINVAL;\n+\n+\tvsi->arfs_fltr_cntrs = kzalloc(sizeof(*vsi->arfs_fltr_cntrs),\n+\t\t\t\t GFP_KERNEL);\n+\tif (!vsi->arfs_fltr_cntrs)\n+\t\treturn -ENOMEM;\n+\n+\tvsi->arfs_last_fltr_id = kzalloc(sizeof(*vsi->arfs_last_fltr_id),\n+\t\t\t\t\t GFP_KERNEL);\n+\tif (!vsi->arfs_last_fltr_id) {\n+\t\tkfree(vsi->arfs_fltr_cntrs);\n+\t\tvsi->arfs_fltr_cntrs = NULL;\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_init_arfs - initialize aRFS resources\n+ * @vsi: the VSI to be forwarded to\n+ */\n+void ice_init_arfs(struct ice_vsi *vsi)\n+{\n+\tstruct hlist_head *arfs_fltr_list;\n+\tunsigned int i;\n+\n+\tif (!vsi || vsi->type != ICE_VSI_PF)\n+\t\treturn;\n+\n+\tarfs_fltr_list = kzalloc(sizeof(*arfs_fltr_list) * ICE_MAX_ARFS_LIST,\n+\t\t\t\t GFP_KERNEL);\n+\tif (!arfs_fltr_list)\n+\t\treturn;\n+\n+\tif (ice_init_arfs_cntrs(vsi))\n+\t\tgoto free_arfs_fltr_list;\n+\n+\tfor (i = 0; i < ICE_MAX_ARFS_LIST; i++)\n+\t\tINIT_HLIST_HEAD(&arfs_fltr_list[i]);\n+\n+\tspin_lock_init(&vsi->arfs_lock);\n+\n+\tvsi->arfs_fltr_list = arfs_fltr_list;\n+\n+\treturn;\n+\n+free_arfs_fltr_list:\n+\tkfree(arfs_fltr_list);\n+}\n+\n+/**\n+ * ice_clear_arfs - clear the aRFS hash table and any memory used for aRFS\n+ * @vsi: the VSI to be forwarded to\n+ */\n+void ice_clear_arfs(struct ice_vsi *vsi)\n+{\n+\tstruct device *dev;\n+\tunsigned int i;\n+\n+\tif (!vsi || vsi->type != ICE_VSI_PF || !vsi->back ||\n+\t !vsi->arfs_fltr_list)\n+\t\treturn;\n+\n+\tdev = ice_pf_to_dev(vsi->back);\n+\tfor (i = 0; i < ICE_MAX_ARFS_LIST; i++) {\n+\t\tstruct ice_arfs_entry *r;\n+\t\tstruct hlist_node *n;\n+\n+\t\tspin_lock_bh(&vsi->arfs_lock);\n+\t\thlist_for_each_entry_safe(r, n, &vsi->arfs_fltr_list[i],\n+\t\t\t\t\t list_entry) {\n+\t\t\thlist_del(&r->list_entry);\n+\t\t\tdevm_kfree(dev, r);\n+\t\t}\n+\t\tspin_unlock_bh(&vsi->arfs_lock);\n+\t}\n+\n+\tkfree(vsi->arfs_fltr_list);\n+\tvsi->arfs_fltr_list = NULL;\n+\tkfree(vsi->arfs_last_fltr_id);\n+\tvsi->arfs_last_fltr_id = NULL;\n+\tkfree(vsi->arfs_fltr_cntrs);\n+\tvsi->arfs_fltr_cntrs = NULL;\n+}\n+\n+/**\n+ * ice_free_cpu_rx_rmap - free setup cpu reverse map\n+ * @vsi: the VSI to be forwarded to\n+ */\n+void ice_free_cpu_rx_rmap(struct ice_vsi *vsi)\n+{\n+\tstruct net_device *netdev;\n+\n+\tif (!vsi || vsi->type != ICE_VSI_PF || !vsi->arfs_fltr_list)\n+\t\treturn;\n+\n+\tnetdev = vsi->netdev;\n+\tif (!netdev || !netdev->rx_cpu_rmap ||\n+\t netdev->reg_state != NETREG_REGISTERED)\n+\t\treturn;\n+\n+\tfree_irq_cpu_rmap(netdev->rx_cpu_rmap);\n+\tnetdev->rx_cpu_rmap = NULL;\n+}\n+\n+/**\n+ * ice_set_cpu_rx_rmap - setup cpu reverse map for each queue\n+ * @vsi: the VSI to be forwarded to\n+ */\n+int ice_set_cpu_rx_rmap(struct ice_vsi *vsi)\n+{\n+\tstruct net_device *netdev;\n+\tstruct ice_pf *pf;\n+\tint base_idx, i;\n+\n+\tif (!vsi || vsi->type != ICE_VSI_PF)\n+\t\treturn -EINVAL;\n+\n+\tpf = vsi->back;\n+\tnetdev = vsi->netdev;\n+\tif (!pf || !netdev || !vsi->num_q_vectors ||\n+\t vsi->netdev->reg_state != NETREG_REGISTERED)\n+\t\treturn -EINVAL;\n+\n+\tnetdev_dbg(netdev, \"Setup CPU RMAP: vsi type 0x%x, ifname %s, q_vectors %d\\n\",\n+\t\t vsi->type, netdev->name, vsi->num_q_vectors);\n+\n+\tnetdev->rx_cpu_rmap = alloc_irq_cpu_rmap(vsi->num_q_vectors);\n+\tif (unlikely(!netdev->rx_cpu_rmap))\n+\t\treturn -EINVAL;\n+\n+\tbase_idx = vsi->base_vector;\n+\tfor (i = 0; i < vsi->num_q_vectors; i++)\n+\t\tif (irq_cpu_rmap_add(netdev->rx_cpu_rmap,\n+\t\t\t\t pf->msix_entries[base_idx + i].vector)) {\n+\t\t\tice_free_cpu_rx_rmap(vsi);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_remove_arfs - remove/clear all aRFS resources\n+ * @pf: device private structure\n+ */\n+void ice_remove_arfs(struct ice_pf *pf)\n+{\n+\tstruct ice_vsi *pf_vsi;\n+\n+\tpf_vsi = ice_get_main_vsi(pf);\n+\tif (!pf_vsi)\n+\t\treturn;\n+\n+\tice_free_cpu_rx_rmap(pf_vsi);\n+\tice_clear_arfs(pf_vsi);\n+}\n+\n+/**\n+ * ice_rebuild_arfs - remove/clear all aRFS resources and rebuild after reset\n+ * @pf: device private structure\n+ */\n+void ice_rebuild_arfs(struct ice_pf *pf)\n+{\n+\tstruct ice_vsi *pf_vsi;\n+\n+\tpf_vsi = ice_get_main_vsi(pf);\n+\tif (!pf_vsi)\n+\t\treturn;\n+\n+\tice_remove_arfs(pf);\n+\tif (ice_set_cpu_rx_rmap(pf_vsi)) {\n+\t\tdev_err(ice_pf_to_dev(pf), \"Failed to rebuild aRFS\\n\");\n+\t\treturn;\n+\t}\n+\tice_init_arfs(pf_vsi);\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_arfs.h b/drivers/net/ethernet/intel/ice/ice_arfs.h\nnew file mode 100644\nindex 000000000000..593385a669ff\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_arfs.h\n@@ -0,0 +1,82 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (C) 2018-2019, Intel Corporation. */\n+\n+#ifndef _ICE_ARFS_H_\n+#define _ICE_ARFS_H_\n+enum ice_arfs_fltr_state {\n+\tICE_ARFS_INACTIVE,\n+\tICE_ARFS_ACTIVE,\n+\tICE_ARFS_TODEL,\n+};\n+\n+struct ice_arfs_entry {\n+\tstruct ice_fdir_fltr fltr_info;\n+\tstruct hlist_node list_entry;\n+\tu64 time_activated;\t/* only valid for UDP flows */\n+\tu32 flow_id;\n+\t/* fltr_state = 0 - ICE_ARFS_INACTIVE:\n+\t *\tfilter needs to be updated or programmed in HW.\n+\t * fltr_state = 1 - ICE_ARFS_ACTIVE:\n+\t *\tfilter is active and programmed in HW.\n+\t * fltr_state = 2 - ICE_ARFS_TODEL:\n+\t *\tfilter has been deleted from HW and needs to be removed from\n+\t *\tthe aRFS hash table.\n+\t */\n+\tu8 fltr_state;\n+};\n+\n+struct ice_arfs_entry_ptr {\n+\tstruct ice_arfs_entry *arfs_entry;\n+\tstruct hlist_node list_entry;\n+};\n+\n+struct ice_arfs_active_fltr_cntrs {\n+\tatomic_t active_tcpv4_cnt;\n+\tatomic_t active_tcpv6_cnt;\n+\tatomic_t active_udpv4_cnt;\n+\tatomic_t active_udpv6_cnt;\n+};\n+\n+#ifdef CONFIG_RFS_ACCEL\n+int\n+ice_rx_flow_steer(struct net_device *netdev, const struct sk_buff *skb,\n+\t\t u16 rxq_idx, u32 flow_id);\n+void ice_clear_arfs(struct ice_vsi *vsi);\n+void ice_free_cpu_rx_rmap(struct ice_vsi *vsi);\n+void ice_init_arfs(struct ice_vsi *vsi);\n+void ice_sync_arfs_fltrs(struct ice_pf *pf);\n+int ice_set_cpu_rx_rmap(struct ice_vsi *vsi);\n+void ice_remove_arfs(struct ice_pf *pf);\n+void ice_rebuild_arfs(struct ice_pf *pf);\n+bool\n+ice_is_arfs_using_perfect_flow(struct ice_hw *hw,\n+\t\t\t enum ice_fltr_ptype flow_type);\n+#else\n+#define ice_sync_arfs_fltrs(pf) do {} while (0)\n+#define ice_init_arfs(vsi) do {} while (0)\n+#define ice_clear_arfs(vsi) do {} while (0)\n+#define ice_remove_arfs(pf) do {} while (0)\n+#define ice_free_cpu_rx_rmap(vsi) do {} while (0)\n+#define ice_rebuild_arfs(pf) do {} while (0)\n+\n+static inline int ice_set_cpu_rx_rmap(struct ice_vsi __always_unused *vsi)\n+{\n+\treturn 0;\n+}\n+\n+static inline int\n+ice_rx_flow_steer(struct net_device __always_unused *netdev,\n+\t\t const struct sk_buff __always_unused *skb,\n+\t\t u16 __always_unused rxq_idx, u32 __always_unused flow_id)\n+{\n+\treturn -EOPNOTSUPP;\n+}\n+\n+static inline bool\n+ice_is_arfs_using_perfect_flow(struct ice_hw __always_unused *hw,\n+\t\t\t enum ice_fltr_ptype __always_unused flow_type)\n+{\n+\treturn false;\n+}\n+#endif /* CONFIG_RFS_ACCEL */\n+#endif /* _ICE_ARFS_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c\nindex aa353e96b30f..22cc4167b974 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c\n@@ -566,6 +566,12 @@ ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg,\n \t\t\treturn -EINVAL;\n \t\t}\n \n+\t\tif (ice_is_arfs_using_perfect_flow(hw, flow)) {\n+\t\t\tdev_err(dev, \"aRFS using perfect flow type %d, cannot change input set\\n\",\n+\t\t\t\tflow);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n \t\t/* remove HW filter definition */\n \t\tice_fdir_rem_flow(hw, ICE_BLK_FD, flow);\n \t}\n@@ -1176,7 +1182,7 @@ ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp,\n *\n * returns 0 on success and negative value on error\n */\n-static int\n+int\n ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add,\n \t\t bool is_tun)\n {\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c\nindex 2bc260092f47..86a3a15c21c8 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.c\n@@ -2210,6 +2210,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,\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\tice_init_arfs(vsi);\n \t\tbreak;\n \tcase ICE_VSI_VF:\n \t\t/* VF driver will take care of creating netdev for this type and\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex 0eca14a1702e..f738e3046fb5 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -1117,7 +1117,7 @@ static void ice_clean_mailboxq_subtask(struct ice_pf *pf)\n *\n * If not already scheduled, this puts the task into the work queue.\n */\n-static void ice_service_task_schedule(struct ice_pf *pf)\n+void ice_service_task_schedule(struct ice_pf *pf)\n {\n \tif (!test_bit(__ICE_SERVICE_DIS, pf->state) &&\n \t !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state) &&\n@@ -1490,7 +1490,7 @@ static void ice_service_task(struct work_struct *work)\n \n \tice_process_vflr_event(pf);\n \tice_clean_mailboxq_subtask(pf);\n-\n+\tice_sync_arfs_fltrs(pf);\n \t/* Clear __ICE_SERVICE_SCHED flag to allow scheduling next event */\n \tice_service_task_complete(pf);\n \n@@ -1649,9 +1649,14 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)\n \t\t}\n \n \t\t/* register for affinity change notifications */\n-\t\tq_vector->affinity_notify.notify = ice_irq_affinity_notify;\n-\t\tq_vector->affinity_notify.release = ice_irq_affinity_release;\n-\t\tirq_set_affinity_notifier(irq_num, &q_vector->affinity_notify);\n+\t\tif (!IS_ENABLED(CONFIG_RFS_ACCEL)) {\n+\t\t\tstruct irq_affinity_notify *affinity_notify;\n+\n+\t\t\taffinity_notify = &q_vector->affinity_notify;\n+\t\t\taffinity_notify->notify = ice_irq_affinity_notify;\n+\t\t\taffinity_notify->release = ice_irq_affinity_release;\n+\t\t\tirq_set_affinity_notifier(irq_num, affinity_notify);\n+\t\t}\n \n \t\t/* assign the mask for this irq */\n \t\tirq_set_affinity_hint(irq_num, &q_vector->affinity_mask);\n@@ -1663,8 +1668,9 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)\n free_q_irqs:\n \twhile (vector) {\n \t\tvector--;\n-\t\tirq_num = pf->msix_entries[base + vector].vector,\n-\t\tirq_set_affinity_notifier(irq_num, NULL);\n+\t\tirq_num = pf->msix_entries[base + vector].vector;\n+\t\tif (!IS_ENABLED(CONFIG_RFS_ACCEL))\n+\t\t\tirq_set_affinity_notifier(irq_num, NULL);\n \t\tirq_set_affinity_hint(irq_num, NULL);\n \t\tdevm_free_irq(dev, irq_num, &vsi->q_vectors[vector]);\n \t}\n@@ -2618,12 +2624,22 @@ static int ice_setup_pf_sw(struct ice_pf *pf)\n \t */\n \tice_napi_add(vsi);\n \n+\tstatus = ice_set_cpu_rx_rmap(vsi);\n+\tif (status) {\n+\t\tdev_err(ice_pf_to_dev(pf), \"Failed to set CPU Rx map VSI %d error %d\\n\",\n+\t\t\tvsi->vsi_num, status);\n+\t\tstatus = -EINVAL;\n+\t\tgoto unroll_napi_add;\n+\t}\n \tstatus = ice_init_mac_fltr(pf);\n \tif (status)\n-\t\tgoto unroll_napi_add;\n+\t\tgoto free_cpu_rx_map;\n \n \treturn status;\n \n+free_cpu_rx_map:\n+\tice_free_cpu_rx_rmap(vsi);\n+\n unroll_napi_add:\n \tif (vsi) {\n \t\tice_napi_del(vsi);\n@@ -3577,6 +3593,8 @@ static void ice_remove(struct pci_dev *pdev)\n \tset_bit(__ICE_DOWN, pf->state);\n \n \tmutex_destroy(&(&pf->hw)->fdir_fltr_lock);\n+\tif (!ice_is_safe_mode(pf))\n+\t\tice_remove_arfs(pf);\n \tice_devlink_destroy_port(pf);\n \tice_vsi_release_all(pf);\n \tif (ice_is_peer_ena(pf)) {\n@@ -4098,11 +4116,14 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)\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 !(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_init_arfs(vsi);\n+\t} else if (!(features & NETIF_F_NTUPLE) &&\n+\t\t (netdev->features & NETIF_F_NTUPLE)) {\n \t\tice_vsi_manage_fdir(vsi, false);\n+\t\tice_clear_arfs(vsi);\n+\t}\n \n \treturn ret;\n }\n@@ -5012,6 +5033,8 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)\n \n \t\t/* replay Flow Director filters */\n \t\tice_fdir_replay_fltrs(pf);\n+\n+\t\tice_rebuild_arfs(pf);\n \t}\n \n \tice_update_pf_netdev_link(pf);\n@@ -5806,6 +5829,9 @@ static const struct net_device_ops ice_netdev_ops = {\n \t.ndo_bridge_setlink = ice_bridge_setlink,\n \t.ndo_fdb_add = ice_fdb_add,\n \t.ndo_fdb_del = ice_fdb_del,\n+#ifdef CONFIG_RFS_ACCEL\n+\t.ndo_rx_flow_steer = ice_rx_flow_steer,\n+#endif\n \t.ndo_tx_timeout = ice_tx_timeout,\n \t.ndo_bpf = ice_xdp,\n \t.ndo_xdp_xmit = ice_xdp_xmit,\n", "prefixes": [ "S42", "7/7" ] }