{"id":2221407,"url":"http://patchwork.ozlabs.org/api/1.0/patches/2221407/?format=json","project":{"id":46,"url":"http://patchwork.ozlabs.org/api/1.0/projects/46/?format=json","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":""},"msgid":"<20260409120003.2719-5-marcin.szycik@linux.intel.com>","date":"2026-04-09T11:59:57","name":"[iwl-next,v2,04/10] ice: create flow profile","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"dd9bf8de71cdfacc9f12cc27bb9ea66a6d542399","submitter":{"id":82782,"url":"http://patchwork.ozlabs.org/api/1.0/people/82782/?format=json","name":"Marcin Szycik","email":"marcin.szycik@linux.intel.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260409120003.2719-5-marcin.szycik@linux.intel.com/mbox/","series":[{"id":499287,"url":"http://patchwork.ozlabs.org/api/1.0/series/499287/?format=json","date":"2026-04-09T11:59:53","name":"Add ACL support","version":2,"mbox":"http://patchwork.ozlabs.org/series/499287/mbox/"}],"check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2221407/checks/","tags":{},"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@legolas.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=osuosl.org header.i=@osuosl.org header.a=rsa-sha256\n header.s=default header.b=H/f1GGNF;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=osuosl.org\n (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org;\n envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fs0RC5Lvsz1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 09 Apr 2026 23:00:39 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby smtp4.osuosl.org (Postfix) with ESMTP id 583314109D;\n\tThu,  9 Apr 2026 13:00:38 +0000 (UTC)","from smtp4.osuosl.org ([127.0.0.1])\n by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id 3U4FR3jwhPR9; Thu,  9 Apr 2026 13:00:34 +0000 (UTC)","from lists1.osuosl.org (lists1.osuosl.org [140.211.166.142])\n\tby smtp4.osuosl.org (Postfix) with ESMTP id E2BC44107A;\n\tThu,  9 Apr 2026 13:00:33 +0000 (UTC)","from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n by lists1.osuosl.org (Postfix) with ESMTP id 8C7A31F6\n for <intel-wired-lan@lists.osuosl.org>; Thu,  9 Apr 2026 13:00:30 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp3.osuosl.org (Postfix) with ESMTP id 78F9460890\n for <intel-wired-lan@lists.osuosl.org>; Thu,  9 Apr 2026 13:00:30 +0000 (UTC)","from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id NxCcI5jS_Rfi for <intel-wired-lan@lists.osuosl.org>;\n Thu,  9 Apr 2026 13:00:28 +0000 (UTC)","from mgamail.intel.com (mgamail.intel.com [192.198.163.19])\n by smtp3.osuosl.org (Postfix) with ESMTPS id 62190606F5\n for <intel-wired-lan@lists.osuosl.org>; Thu,  9 Apr 2026 13:00:28 +0000 (UTC)","from orviesa002.jf.intel.com ([10.64.159.142])\n by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 09 Apr 2026 06:00:21 -0700","from irvmail002.ir.intel.com ([10.43.11.120])\n by orviesa002.jf.intel.com with ESMTP; 09 Apr 2026 06:00:15 -0700","from gond.igk.intel.com (gond.igk.intel.com [10.123.220.52])\n by irvmail002.ir.intel.com (Postfix) with ESMTP id 241CC2FC5A;\n Thu,  9 Apr 2026 14:00:14 +0100 (IST)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections - client-ip=140.211.166.142;\n helo=lists1.osuosl.org; envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp4.osuosl.org E2BC44107A","OpenDKIM Filter v2.11.0 smtp3.osuosl.org 62190606F5"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=osuosl.org;\n\ts=default; t=1775739633;\n\tbh=W7ZYDv13ogV3bAA0gXRxSffxmQJaNrHSinJ72v9MjDk=;\n\th=From:To:Cc:Date:In-Reply-To:References:Subject:List-Id:\n\t List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe:\n\t From;\n\tb=H/f1GGNFcgGYRDq4oXzOPYPrNYY6X6mkGBt83H9eEd6Dau6OduMtIkjmKh4lGJ5Gs\n\t KCeJoJXoy2fGOCmid+pT1P4mFtM/4Z1rNqIjmznj2ncRot4j3CO/UsfYAO+uxGHdjH\n\t FRSmaknPVoeMsPgUnJVrfSjdMVLh70CWdcPwBYQ6HpgyQz+o8vSrmZgqEmzOAwPbCb\n\t L0tc3f1BHMDd5S4RmetmoHdxjTB3vS6Fpq3abI+zqJeCr4vPwveWfNezx6mAvBAVRi\n\t zXs99hAF7uPjEqCURsqgLH/sbx0OqnKo73hGTfrQ+YqhTotB4tsvI3NfyHyDvWcz5k\n\t zmx6wfsqSZY8w==","Received-SPF":"Pass (mailfrom) identity=mailfrom; client-ip=192.198.163.19;\n helo=mgamail.intel.com; envelope-from=marcin.szycik@linux.intel.com;\n receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp3.osuosl.org 62190606F5","X-CSE-ConnectionGUID":["LcGsmYbXQs+YJD4t0B6Gkw==","Ujzu6MHbRKqenpsZYYJcIQ=="],"X-CSE-MsgGUID":["8hRekY8oSN6gA567D5aBIQ==","Pb/lsbquTUST17i7FnELiw=="],"X-IronPort-AV":["E=McAfee;i=\"6800,10657,11753\"; a=\"75777539\"","E=Sophos;i=\"6.23,169,1770624000\"; d=\"scan'208\";a=\"75777539\"","E=Sophos;i=\"6.23,169,1770624000\"; d=\"scan'208\";a=\"259208141\""],"X-ExtLoop1":"1","From":"Marcin Szycik <marcin.szycik@linux.intel.com>","To":"intel-wired-lan@lists.osuosl.org","Cc":"netdev@vger.kernel.org, sandeep.penigalapati@intel.com,\n ananth.s@intel.com,\n alexander.duyck@gmail.com, Marcin Szycik <marcin.szycik@linux.intel.com>,\n Chinh Cao <chinh.t.cao@intel.com>,\n Tony Nguyen <anthony.l.nguyen@intel.com>,\n Aleksandr Loktionov <aleksandr.loktionov@intel.com>","Date":"Thu,  9 Apr 2026 13:59:57 +0200","Message-ID":"<20260409120003.2719-5-marcin.szycik@linux.intel.com>","X-Mailer":"git-send-email 2.49.0","In-Reply-To":"<20260409120003.2719-1-marcin.szycik@linux.intel.com>","References":"<20260409120003.2719-1-marcin.szycik@linux.intel.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Mailman-Original-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1775739628; x=1807275628;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=rf4yweCeWzxn5/KpVfOY3ySzuDEeNRwbUX0EDvZ4sCs=;\n b=LrXgT/MAnYh0wr1a755WZ3SCCZINL8lo3nSSgBpwIOyDJ9OJvIEFtXU6\n mIDfjT0Ro/qK6eT5ELoeXY0kEVjwONjGkPd3SWdcsN9IemGDBsOsyW12T\n RfI9ZDSDeLdjnSh6RzgJWOV1jLYAWN/uBaP+L9RPa1KnOI95T4Akgs6AO\n Ujzr14plr2PpmRnYGI8A0xnVcwZ/oM3NzQUMrJwaLDIal9YXcevmBWgr4\n 9eyAty0J6w8ZBY8BXLjCVvK2PXUIOTR41/boE2QOIb4DNhx2ZyWDd1M3K\n LyIqgs/RmvreWpFmfBgXBtfooKufXEvIeJjItCwGbc9dr2cRmqSS5g0zR\n g==;","X-Mailman-Original-Authentication-Results":["smtp3.osuosl.org;\n dmarc=none (p=none dis=none)\n header.from=linux.intel.com","smtp3.osuosl.org;\n dkim=pass (2048-bit key,\n unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256\n header.s=Intel header.b=LrXgT/MA"],"Subject":"[Intel-wired-lan] [PATCH iwl-next v2 04/10] ice: create flow profile","X-BeenThere":"intel-wired-lan@osuosl.org","X-Mailman-Version":"2.1.30","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>","Errors-To":"intel-wired-lan-bounces@osuosl.org","Sender":"\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"},"content":"From: Real Valiquette <real.valiquette@intel.com>\n\nImplement the initial steps for creating an ACL filter to support ntuple\nmasks. Create a flow profile based on a given mask rule and program it to\nthe hardware. Though the profile is written to hardware, no actions are\nassociated with the profile yet.\n\nCo-developed-by: Chinh Cao <chinh.t.cao@intel.com>\nSigned-off-by: Chinh Cao <chinh.t.cao@intel.com>\nSigned-off-by: Real Valiquette <real.valiquette@intel.com>\nCo-developed-by: Tony Nguyen <anthony.l.nguyen@intel.com>\nSigned-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>\nCo-developed-by: Marcin Szycik <marcin.szycik@linux.intel.com>\nSigned-off-by: Marcin Szycik <marcin.szycik@linux.intel.com>\nReviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>\n---\nv2:\n* Add ice_acl_main.h in order to not awkwardly add prototypes to ice.h.\n  This will also help avoid potential dependency issues for future\n  additions to ice_acl_main.c\n* Rename ice_acl_check_input_set() to a more fiting\n  ice_acl_prof_add_ethtool() as it adds a profile\n* Set hw->acl_prof = 0 in ice_acl_prof_add_ethtool() to avoid use after\n  free\n* Add ipv4 and port full mask defines in ice_ethtool_ntuple.c\n* Move hw->acl_prof allocation to ice_init_acl(). Previously, it was\n  being deallocated when hw->acl_prof[fltr_type] allocation failed,\n  possibly with already existing other elements. Extend array lifetime\n  to driver's lifetime\n* Change hw->acl_prof[fltr_type] alloc from devm_ to plain\n* Add hw->acl_prof[fltr_type] and hw->acl_prof deallocation in\n  ice_deinit_acl() - previously were only deallocated on failure\n* Tweak alloc/unroll logic in ice_acl_prof_add_ethtool()\n---\n drivers/net/ethernet/intel/ice/Makefile       |   1 +\n drivers/net/ethernet/intel/ice/ice.h          |   6 +\n drivers/net/ethernet/intel/ice/ice_acl_main.h |   9 +\n .../net/ethernet/intel/ice/ice_adminq_cmd.h   |  39 +++\n drivers/net/ethernet/intel/ice/ice_flow.h     |  17 +\n drivers/net/ethernet/intel/ice/ice_acl_main.c | 229 ++++++++++++++\n .../ethernet/intel/ice/ice_ethtool_ntuple.c   | 299 +++++++++++++-----\n .../net/ethernet/intel/ice/ice_flex_pipe.c    |   6 +\n drivers/net/ethernet/intel/ice/ice_flow.c     | 173 ++++++++++\n drivers/net/ethernet/intel/ice/ice_main.c     |  33 +-\n 10 files changed, 731 insertions(+), 81 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/ice/ice_acl_main.h\n create mode 100644 drivers/net/ethernet/intel/ice/ice_acl_main.c","diff":"diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile\nindex 6afe7be056ba..7f06d9bafe4a 100644\n--- a/drivers/net/ethernet/intel/ice/Makefile\n+++ b/drivers/net/ethernet/intel/ice/Makefile\n@@ -25,6 +25,7 @@ ice-y := ice_main.o\t\\\n \t ice_vsi_vlan_lib.o \\\n \t ice_fdir.o\t\\\n \t ice_ethtool_ntuple.o \\\n+\t ice_acl_main.o\t\\\n \t ice_acl.o\t\\\n \t ice_acl_ctrl.o\t\\\n \t ice_vlan_mode.o \\\ndiff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex e064323d983c..d10e67d8bf02 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -1025,6 +1025,11 @@ int ice_add_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd);\n int ice_del_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd);\n int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd);\n u32 ice_ntuple_get_max_fltr_cnt(struct ice_hw *hw);\n+int ice_ntuple_l4_proto_to_port(enum ice_flow_seg_hdr l4_proto,\n+\t\t\t\tenum ice_flow_field *src_port,\n+\t\t\t\tenum ice_flow_field *dst_port);\n+int ice_ntuple_check_ip4_seg(struct ethtool_tcpip4_spec *tcp_ip4_spec);\n+int ice_ntuple_check_ip4_usr_seg(struct ethtool_usrip4_spec *usr_ip4_spec);\n int\n ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd,\n \t\t      u32 *rule_locs);\n@@ -1033,6 +1038,7 @@ void ice_fdir_release_flows(struct ice_hw *hw);\n void ice_fdir_replay_flows(struct ice_hw *hw);\n void ice_fdir_replay_fltrs(struct ice_pf *pf);\n int ice_fdir_create_dflt_rules(struct ice_pf *pf);\n+enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth);\n \n enum ice_aq_task_state {\n \tICE_AQ_TASK_NOT_PREPARED,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_acl_main.h b/drivers/net/ethernet/intel/ice/ice_acl_main.h\nnew file mode 100644\nindex 000000000000..6665af2e7053\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_acl_main.h\n@@ -0,0 +1,9 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (C) 2026, Intel Corporation. */\n+\n+#ifndef _ICE_ACL_MAIN_H_\n+#define _ICE_ACL_MAIN_H_\n+#include \"ice.h\"\n+#include <linux/ethtool.h>\n+int ice_acl_add_rule_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd);\n+#endif /* _ICE_ACL_MAIN_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 46d2675baa4e..1a32400e70bd 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -172,6 +172,8 @@ struct ice_aqc_set_port_params {\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_ACL_PROF_BLDR_PROFID\t\t0x50\n+#define ICE_AQC_RES_TYPE_ACL_PROF_BLDR_TCAM\t\t0x51\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@@ -2175,6 +2177,43 @@ struct ice_aqc_actpair {\n \tstruct ice_acl_act_entry act[ICE_ACL_NUM_ACT_PER_ACT_PAIR];\n };\n \n+/* The first byte of the byte selection base is reserved to keep the\n+ * first byte of the field vector where the packet direction info is\n+ * available. Thus we should start at index 1 of the field vector to\n+ * map its entries to the byte selection base.\n+ */\n+#define ICE_AQC_ACL_PROF_BYTE_SEL_START_IDX\t1\n+#define ICE_AQC_ACL_PROF_BYTE_SEL_ELEMS\t\t30\n+\n+/* Input buffer format for program profile extraction admin command and\n+ * response buffer format for query profile admin command is as defined\n+ * in struct ice_aqc_acl_prof_generic_frmt\n+ */\n+\n+/* Input buffer format for program profile ranges and query profile ranges\n+ * admin commands. Same format is used for response buffer in case of query\n+ * profile ranges command\n+ */\n+struct ice_acl_rng_data {\n+\t/* The range checker output shall be sent when the value\n+\t * related to this range checker is lower than low boundary\n+\t */\n+\t__be16 low_boundary;\n+\t/* The range checker output shall be sent when the value\n+\t * related to this range checker is higher than high boundary\n+\t */\n+\t__be16 high_boundary;\n+\t/* A value of '0' in bit shall clear the relevant bit input\n+\t * to the range checker\n+\t */\n+\t__be16 mask;\n+};\n+\n+#define ICE_AQC_ACL_PROF_RANGES_NUM_CFG 8\n+struct ice_aqc_acl_profile_ranges {\n+\tstruct ice_acl_rng_data checker_cfg[ICE_AQC_ACL_PROF_RANGES_NUM_CFG];\n+};\n+\n /* Program ACL entry (indirect 0x0C20) */\n struct ice_aqc_acl_entry {\n \tu8 tcam_index;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flow.h b/drivers/net/ethernet/intel/ice/ice_flow.h\nindex a20ef320e1f9..bbfc7b4a432e 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flow.h\n+++ b/drivers/net/ethernet/intel/ice/ice_flow.h\n@@ -504,6 +504,23 @@ struct ice_rss_cfg {\n \tstruct ice_rss_hash_cfg hash;\n };\n \n+enum ice_flow_action_type {\n+\tICE_FLOW_ACT_NOP,\n+\tICE_FLOW_ACT_DROP,\n+\tICE_FLOW_ACT_CNTR_PKT,\n+\tICE_FLOW_ACT_FWD_QUEUE,\n+\tICE_FLOW_ACT_CNTR_BYTES,\n+\tICE_FLOW_ACT_CNTR_PKT_BYTES,\n+};\n+\n+struct ice_flow_action {\n+\tenum ice_flow_action_type type;\n+\tunion {\n+\t\tstruct ice_acl_act_entry acl_act;\n+\t\tu32 dummy;\n+\t} data;\n+};\n+\n int\n ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,\n \t\t  struct ice_flow_seg_info *segs, u8 segs_cnt,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_acl_main.c b/drivers/net/ethernet/intel/ice/ice_acl_main.c\nnew file mode 100644\nindex 000000000000..841e4d567ff2\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_acl_main.c\n@@ -0,0 +1,229 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (C) 2018-2026, Intel Corporation. */\n+\n+#include \"ice.h\"\n+#include \"ice_lib.h\"\n+#include \"ice_acl_main.h\"\n+\n+/* Number of action */\n+#define ICE_ACL_NUM_ACT\t\t1\n+\n+/**\n+ * ice_acl_set_ip4_addr_seg - set flow segment IPv4 addresses masks\n+ * @seg: flow segment for programming\n+ */\n+static void ice_acl_set_ip4_addr_seg(struct ice_flow_seg_info *seg)\n+{\n+\tu16 val_loc, mask_loc;\n+\n+\t/* IP source address */\n+\tval_loc = offsetof(struct ice_ntuple_fltr, ip.v4.src_ip);\n+\tmask_loc = offsetof(struct ice_ntuple_fltr, mask.v4.src_ip);\n+\n+\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_SA, val_loc,\n+\t\t\t mask_loc, ICE_FLOW_FLD_OFF_INVAL, false);\n+\n+\t/* IP destination address */\n+\tval_loc = offsetof(struct ice_ntuple_fltr, ip.v4.dst_ip);\n+\tmask_loc = offsetof(struct ice_ntuple_fltr, mask.v4.dst_ip);\n+\n+\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_DA, val_loc,\n+\t\t\t mask_loc, ICE_FLOW_FLD_OFF_INVAL, false);\n+}\n+\n+/**\n+ * ice_acl_set_ip4_port_seg - set flow segment port masks based on L4 port\n+ * @seg: flow segment for programming\n+ * @l4_proto: Layer 4 protocol to program\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_acl_set_ip4_port_seg(struct ice_flow_seg_info *seg,\n+\t\t\t\t    enum ice_flow_seg_hdr l4_proto)\n+{\n+\tenum ice_flow_field src_port, dst_port;\n+\tu16 val_loc, mask_loc;\n+\tint err;\n+\n+\terr = ice_ntuple_l4_proto_to_port(l4_proto, &src_port, &dst_port);\n+\tif (err)\n+\t\treturn err;\n+\n+\t/* Layer 4 source port */\n+\tval_loc = offsetof(struct ice_ntuple_fltr, ip.v4.src_port);\n+\tmask_loc = offsetof(struct ice_ntuple_fltr, mask.v4.src_port);\n+\n+\tice_flow_set_fld(seg, src_port, val_loc, mask_loc,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n+\n+\t/* Layer 4 destination port */\n+\tval_loc = offsetof(struct ice_ntuple_fltr, ip.v4.dst_port);\n+\tmask_loc = offsetof(struct ice_ntuple_fltr, mask.v4.dst_port);\n+\n+\tice_flow_set_fld(seg, dst_port, val_loc, mask_loc,\n+\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_acl_set_ip4_seg - set flow segment IPv4 and L4 masks\n+ * @seg: flow segment for programming\n+ * @tcp_ip4_spec: mask data from ethtool\n+ * @l4_proto: Layer 4 protocol to program\n+ *\n+ * Set the mask data into the flow segment to be used to program HW\n+ * table based on provided L4 protocol for IPv4\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_acl_set_ip4_seg(struct ice_flow_seg_info *seg,\n+\t\t\t       struct ethtool_tcpip4_spec *tcp_ip4_spec,\n+\t\t\t       enum ice_flow_seg_hdr l4_proto)\n+{\n+\tint err;\n+\n+\terr = ice_ntuple_check_ip4_seg(tcp_ip4_spec);\n+\tif (err)\n+\t\treturn err;\n+\n+\tICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | l4_proto);\n+\tice_acl_set_ip4_addr_seg(seg);\n+\n+\treturn ice_acl_set_ip4_port_seg(seg, l4_proto);\n+}\n+\n+/**\n+ * ice_acl_set_ip4_usr_seg - set flow segment IPv4 masks\n+ * @seg: flow segment for programming\n+ * @usr_ip4_spec: ethtool userdef packet offset\n+ *\n+ * Set the offset data into the flow segment to be used to program HW\n+ * table for IPv4\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_acl_set_ip4_usr_seg(struct ice_flow_seg_info *seg,\n+\t\t\t\t   struct ethtool_usrip4_spec *usr_ip4_spec)\n+{\n+\tint err;\n+\n+\terr = ice_ntuple_check_ip4_usr_seg(usr_ip4_spec);\n+\tif (err)\n+\t\treturn err;\n+\n+\tICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4);\n+\tice_acl_set_ip4_addr_seg(seg);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_acl_prof_add_ethtool - Check ethtool input set and add ACL profile\n+ * @pf: ice PF structure\n+ * @fsp: pointer to ethtool Rx flow specification\n+ *\n+ * Return: 0 on success and negative values for failure\n+ */\n+static int ice_acl_prof_add_ethtool(struct ice_pf *pf,\n+\t\t\t\t    struct ethtool_rx_flow_spec *fsp)\n+{\n+\tstruct ice_flow_prof *prof = NULL;\n+\tstruct ice_flow_seg_info *old_seg;\n+\tstruct ice_fd_hw_prof *hw_prof;\n+\tstruct ice_flow_seg_info *seg;\n+\tenum ice_fltr_ptype fltr_type;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tint err;\n+\n+\tseg = kzalloc_obj(*seg);\n+\tif (!seg)\n+\t\treturn -ENOMEM;\n+\n+\tswitch (fsp->flow_type & ~FLOW_EXT) {\n+\tcase TCP_V4_FLOW:\n+\t\terr = ice_acl_set_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,\n+\t\t\t\t\t  ICE_FLOW_SEG_HDR_TCP);\n+\t\tbreak;\n+\tcase UDP_V4_FLOW:\n+\t\terr = ice_acl_set_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,\n+\t\t\t\t\t  ICE_FLOW_SEG_HDR_UDP);\n+\t\tbreak;\n+\tcase SCTP_V4_FLOW:\n+\t\terr = ice_acl_set_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,\n+\t\t\t\t\t  ICE_FLOW_SEG_HDR_SCTP);\n+\t\tbreak;\n+\tcase IPV4_USER_FLOW:\n+\t\terr = ice_acl_set_ip4_usr_seg(seg, &fsp->m_u.usr_ip4_spec);\n+\t\tbreak;\n+\tdefault:\n+\t\terr = -EOPNOTSUPP;\n+\t}\n+\tif (err)\n+\t\tgoto free_seg;\n+\n+\tfltr_type = ice_ethtool_flow_to_fltr(fsp->flow_type & ~FLOW_EXT);\n+\n+\thw_prof = hw->acl_prof[fltr_type];\n+\tif (!hw_prof) {\n+\t\thw_prof = kzalloc_obj(**hw->acl_prof);\n+\t\tif (!hw_prof) {\n+\t\t\terr = -ENOMEM;\n+\t\t\tgoto free_seg;\n+\t\t}\n+\t\thw_prof->cnt = 0;\n+\t}\n+\n+\told_seg = hw_prof->fdir_seg[0];\n+\tif (old_seg) {\n+\t\t/* This flow_type already has an input set.\n+\t\t * If it matches the requested input set then we are\n+\t\t * done. If it's different then it's an error.\n+\t\t */\n+\t\tif (!memcmp(old_seg, seg, sizeof(*seg))) {\n+\t\t\tkfree(seg);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\terr = -EINVAL;\n+\t\tgoto free_acl_prof;\n+\t}\n+\n+\t/* Adding a profile for the given flow specification with no\n+\t * actions (NULL) and zero actions 0.\n+\t */\n+\terr = ice_flow_add_prof(hw, ICE_BLK_ACL, ICE_FLOW_RX, seg, 1, false,\n+\t\t\t\t&prof);\n+\tif (err)\n+\t\tgoto free_acl_prof;\n+\n+\thw_prof->fdir_seg[0] = seg;\n+\thw->acl_prof[fltr_type] = hw_prof;\n+\treturn 0;\n+\n+free_acl_prof:\n+\tkfree(hw_prof);\n+free_seg:\n+\tkfree(seg);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * ice_acl_add_rule_ethtool - add an ACL rule\n+ * @vsi: pointer to target VSI\n+ * @cmd: command to add or delete ACL rule\n+ *\n+ * Return: 0 on success and negative values for failure\n+ */\n+int ice_acl_add_rule_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)\n+{\n+\tstruct ethtool_rx_flow_spec *fsp;\n+\tstruct ice_pf *pf;\n+\n+\tpf = vsi->back;\n+\n+\tfsp = (struct ethtool_rx_flow_spec *)&cmd->fs;\n+\n+\treturn ice_acl_prof_add_ethtool(pf, fsp);\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_ntuple.c b/drivers/net/ethernet/intel/ice/ice_ethtool_ntuple.c\nindex 053d6b7a66bd..eca15cb2665e 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ethtool_ntuple.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ethtool_ntuple.c\n@@ -7,6 +7,7 @@\n #include \"ice_lib.h\"\n #include \"ice_fdir.h\"\n #include \"ice_flow.h\"\n+#include \"ice_acl_main.h\"\n \n static struct in6_addr full_ipv6_addr_mask = {\n \t.in6_u = {\n@@ -26,6 +27,9 @@ static struct in6_addr zero_ipv6_addr_mask = {\n \t}\n };\n \n+#define ICE_FULL_IPV4_ADDR_MASK\t0xFFFFFFFF\n+#define ICE_FULL_PORT_MASK\t0xFFFF\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@@ -71,7 +75,7 @@ static int ice_fltr_to_ethtool_flow(enum ice_fltr_ptype flow)\n  *\n  * Returns flow enum\n  */\n-static enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth)\n+enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth)\n {\n \tswitch (eth) {\n \tcase ETHER_FLOW:\n@@ -932,23 +936,13 @@ ice_create_init_fdir_rule(struct ice_pf *pf, enum ice_fltr_ptype flow)\n }\n \n /**\n- * ice_set_fdir_ip4_seg\n- * @seg: flow segment for programming\n+ * ice_ntuple_check_ip4_seg - Check valid fields are provided for filter\n  * @tcp_ip4_spec: mask data from ethtool\n- * @l4_proto: Layer 4 protocol to program\n- * @perfect_fltr: only valid on success; returns true if perfect filter,\n- *\t\t  false if not\n  *\n- * Set the mask data into the flow segment to be used to program HW\n- * table based on provided L4 protocol for IPv4\n+ * Return: 0 if fields valid, negative otherwise\n  */\n-static int\n-ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,\n-\t\t     struct ethtool_tcpip4_spec *tcp_ip4_spec,\n-\t\t     enum ice_flow_seg_hdr l4_proto, bool *perfect_fltr)\n+int ice_ntuple_check_ip4_seg(struct ethtool_tcpip4_spec *tcp_ip4_spec)\n {\n-\tenum ice_flow_field src_port, dst_port;\n-\n \t/* make sure we don't have any empty rule */\n \tif (!tcp_ip4_spec->psrc && !tcp_ip4_spec->ip4src &&\n \t    !tcp_ip4_spec->pdst && !tcp_ip4_spec->ip4dst)\n@@ -958,24 +952,71 @@ ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,\n \tif (tcp_ip4_spec->tos)\n \t\treturn -EOPNOTSUPP;\n \n+\treturn 0;\n+}\n+\n+/**\n+ * ice_ntuple_l4_proto_to_port - set src and dst port for given L4 protocol\n+ * @l4_proto: Layer 4 protocol to program\n+ * @src_port: source flow field value for provided l4 protocol\n+ * @dst_port: destination flow field value for provided l4 protocol\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+int ice_ntuple_l4_proto_to_port(enum ice_flow_seg_hdr l4_proto,\n+\t\t\t\tenum ice_flow_field *src_port,\n+\t\t\t\tenum ice_flow_field *dst_port)\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\t*src_port = ICE_FLOW_FIELD_IDX_TCP_SRC_PORT;\n+\t\t*dst_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\t*src_port = ICE_FLOW_FIELD_IDX_UDP_SRC_PORT;\n+\t\t*dst_port = ICE_FLOW_FIELD_IDX_UDP_DST_PORT;\n \t} else if (l4_proto == ICE_FLOW_SEG_HDR_SCTP) {\n-\t\tsrc_port = ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT;\n-\t\tdst_port = ICE_FLOW_FIELD_IDX_SCTP_DST_PORT;\n+\t\t*src_port = ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT;\n+\t\t*dst_port = ICE_FLOW_FIELD_IDX_SCTP_DST_PORT;\n \t} else {\n \t\treturn -EOPNOTSUPP;\n \t}\n \n+\treturn 0;\n+}\n+\n+/**\n+ * ice_set_fdir_ip4_seg - setup flow segment based on IPv4 and L4 proto\n+ * @seg: flow segment for programming\n+ * @tcp_ip4_spec: mask data from ethtool\n+ * @l4_proto: Layer 4 protocol to program\n+ * @perfect_fltr: only valid on success; returns true if perfect filter,\n+ *\t\t  false if not\n+ *\n+ * Set the mask data into the flow segment to be used to program HW\n+ * table based on provided L4 protocol for IPv4\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,\n+\t\t\t\tstruct ethtool_tcpip4_spec *tcp_ip4_spec,\n+\t\t\t\tenum ice_flow_seg_hdr l4_proto,\n+\t\t\t\tbool *perfect_fltr)\n+{\n+\tenum ice_flow_field src_port, dst_port;\n+\tint err;\n+\n+\terr = ice_ntuple_check_ip4_seg(tcp_ip4_spec);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ice_ntuple_l4_proto_to_port(l4_proto, &src_port, &dst_port);\n+\tif (err)\n+\t\treturn err;\n+\n \t*perfect_fltr = true;\n \tICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | l4_proto);\n \n \t/* IP source address */\n-\tif (tcp_ip4_spec->ip4src == htonl(0xFFFFFFFF))\n+\tif (tcp_ip4_spec->ip4src == htonl(ICE_FULL_IPV4_ADDR_MASK))\n \t\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_SA,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n@@ -985,7 +1026,7 @@ ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,\n \t\treturn -EOPNOTSUPP;\n \n \t/* IP destination address */\n-\tif (tcp_ip4_spec->ip4dst == htonl(0xFFFFFFFF))\n+\tif (tcp_ip4_spec->ip4dst == htonl(ICE_FULL_IPV4_ADDR_MASK))\n \t\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_DA,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n@@ -995,7 +1036,7 @@ ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,\n \t\treturn -EOPNOTSUPP;\n \n \t/* Layer 4 source port */\n-\tif (tcp_ip4_spec->psrc == htons(0xFFFF))\n+\tif (tcp_ip4_spec->psrc == htons(ICE_FULL_PORT_MASK))\n \t\tice_flow_set_fld(seg, src_port, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t false);\n@@ -1005,7 +1046,7 @@ ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,\n \t\treturn -EOPNOTSUPP;\n \n \t/* Layer 4 destination port */\n-\tif (tcp_ip4_spec->pdst == htons(0xFFFF))\n+\tif (tcp_ip4_spec->pdst == htons(ICE_FULL_PORT_MASK))\n \t\tice_flow_set_fld(seg, dst_port, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t false);\n@@ -1018,19 +1059,12 @@ ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,\n }\n \n /**\n- * ice_set_fdir_ip4_usr_seg\n- * @seg: flow segment for programming\n+ * ice_ntuple_check_ip4_usr_seg - Check valid fields are provided for filter\n  * @usr_ip4_spec: ethtool userdef packet offset\n- * @perfect_fltr: only valid on success; returns true if perfect filter,\n- *\t\t  false if not\n  *\n- * Set the offset data into the flow segment to be used to program HW\n- * table for IPv4\n+ * Return: 0 if fields valid, negative otherwise\n  */\n-static int\n-ice_set_fdir_ip4_usr_seg(struct ice_flow_seg_info *seg,\n-\t\t\t struct ethtool_usrip4_spec *usr_ip4_spec,\n-\t\t\t bool *perfect_fltr)\n+int ice_ntuple_check_ip4_usr_seg(struct ethtool_usrip4_spec *usr_ip4_spec)\n {\n \t/* first 4 bytes of Layer 4 header */\n \tif (usr_ip4_spec->l4_4_bytes)\n@@ -1046,11 +1080,36 @@ ice_set_fdir_ip4_usr_seg(struct ice_flow_seg_info *seg,\n \tif (!usr_ip4_spec->ip4src && !usr_ip4_spec->ip4dst)\n \t\treturn -EINVAL;\n \n+\treturn 0;\n+}\n+\n+/**\n+ * ice_set_fdir_ip4_usr_seg - setup flow segment based on IPv4\n+ * @seg: flow segment for programming\n+ * @usr_ip4_spec: ethtool userdef packet offset\n+ * @perfect_fltr: only set on success; returns true if perfect filter, false if\n+ *\t\t  not\n+ *\n+ * Set the offset data into the flow segment to be used to program HW\n+ * table for IPv4\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_set_fdir_ip4_usr_seg(struct ice_flow_seg_info *seg,\n+\t\t\t\t    struct ethtool_usrip4_spec *usr_ip4_spec,\n+\t\t\t\t    bool *perfect_fltr)\n+{\n+\tint err;\n+\n+\terr = ice_ntuple_check_ip4_usr_seg(usr_ip4_spec);\n+\tif (err)\n+\t\treturn err;\n+\n \t*perfect_fltr = true;\n \tICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4);\n \n \t/* IP source address */\n-\tif (usr_ip4_spec->ip4src == htonl(0xFFFFFFFF))\n+\tif (usr_ip4_spec->ip4src == htonl(ICE_FULL_IPV4_ADDR_MASK))\n \t\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_SA,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n@@ -1060,7 +1119,7 @@ ice_set_fdir_ip4_usr_seg(struct ice_flow_seg_info *seg,\n \t\treturn -EOPNOTSUPP;\n \n \t/* IP destination address */\n-\tif (usr_ip4_spec->ip4dst == htonl(0xFFFFFFFF))\n+\tif (usr_ip4_spec->ip4dst == htonl(ICE_FULL_IPV4_ADDR_MASK))\n \t\tice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_DA,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, false);\n@@ -1073,23 +1132,13 @@ ice_set_fdir_ip4_usr_seg(struct ice_flow_seg_info *seg,\n }\n \n /**\n- * ice_set_fdir_ip6_seg\n- * @seg: flow segment for programming\n+ * ice_ntuple_check_ip6_seg - Check valid fields are provided for filter\n  * @tcp_ip6_spec: mask data from ethtool\n- * @l4_proto: Layer 4 protocol to program\n- * @perfect_fltr: only valid on success; returns true if perfect filter,\n- *\t\t  false if not\n  *\n- * Set the mask data into the flow segment to be used to program HW\n- * table based on provided L4 protocol for IPv6\n+ * Return: 0 if fields valid, negative otherwise\n  */\n-static int\n-ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg,\n-\t\t     struct ethtool_tcpip6_spec *tcp_ip6_spec,\n-\t\t     enum ice_flow_seg_hdr l4_proto, bool *perfect_fltr)\n+static int ice_ntuple_check_ip6_seg(struct ethtool_tcpip6_spec *tcp_ip6_spec)\n {\n-\tenum ice_flow_field src_port, dst_port;\n-\n \t/* make sure we don't have any empty rule */\n \tif (!memcmp(tcp_ip6_spec->ip6src, &zero_ipv6_addr_mask,\n \t\t    sizeof(struct in6_addr)) &&\n@@ -1102,18 +1151,37 @@ ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg,\n \tif (tcp_ip6_spec->tclass)\n \t\treturn -EOPNOTSUPP;\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 if (l4_proto == ICE_FLOW_SEG_HDR_SCTP) {\n-\t\tsrc_port = ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT;\n-\t\tdst_port = ICE_FLOW_FIELD_IDX_SCTP_DST_PORT;\n-\t} else {\n-\t\treturn -EINVAL;\n-\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_set_fdir_ip6_seg - setup flow segment based on IPv6 and L4 proto\n+ * @seg: flow segment for programming\n+ * @tcp_ip6_spec: mask data from ethtool\n+ * @l4_proto: Layer 4 protocol to program\n+ * @perfect_fltr: only valid on success; returns true if perfect filter,\n+ *\t\t  false if not\n+ *\n+ * Set the mask data into the flow segment to be used to program HW\n+ * table based on provided L4 protocol for IPv6\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg,\n+\t\t\t\tstruct ethtool_tcpip6_spec *tcp_ip6_spec,\n+\t\t\t\tenum ice_flow_seg_hdr l4_proto,\n+\t\t\t\tbool *perfect_fltr)\n+{\n+\tenum ice_flow_field src_port, dst_port;\n+\tint err;\n+\n+\terr = ice_ntuple_check_ip6_seg(tcp_ip6_spec);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ice_ntuple_l4_proto_to_port(l4_proto, &src_port, &dst_port);\n+\tif (err)\n+\t\treturn err;\n \n \t*perfect_fltr = true;\n \tICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 | l4_proto);\n@@ -1141,7 +1209,7 @@ ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg,\n \t\treturn -EOPNOTSUPP;\n \n \t/* Layer 4 source port */\n-\tif (tcp_ip6_spec->psrc == htons(0xFFFF))\n+\tif (tcp_ip6_spec->psrc == htons(ICE_FULL_PORT_MASK))\n \t\tice_flow_set_fld(seg, src_port, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t false);\n@@ -1151,7 +1219,7 @@ ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg,\n \t\treturn -EOPNOTSUPP;\n \n \t/* Layer 4 destination port */\n-\tif (tcp_ip6_spec->pdst == htons(0xFFFF))\n+\tif (tcp_ip6_spec->pdst == htons(ICE_FULL_PORT_MASK))\n \t\tice_flow_set_fld(seg, dst_port, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,\n \t\t\t\t false);\n@@ -1164,19 +1232,13 @@ ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg,\n }\n \n /**\n- * ice_set_fdir_ip6_usr_seg\n- * @seg: flow segment for programming\n+ * ice_ntuple_check_ip6_usr_seg - Check valid fields are provided for filter\n  * @usr_ip6_spec: ethtool userdef packet offset\n- * @perfect_fltr: only valid on success; returns true if perfect filter,\n- *\t\t  false if not\n  *\n- * Set the offset data into the flow segment to be used to program HW\n- * table for IPv6\n+ * Return: 0 if fields valid, negative otherwise\n  */\n static int\n-ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg,\n-\t\t\t struct ethtool_usrip6_spec *usr_ip6_spec,\n-\t\t\t bool *perfect_fltr)\n+ice_ntuple_check_ip6_usr_seg(struct ethtool_usrip6_spec *usr_ip6_spec)\n {\n \t/* filtering on Layer 4 bytes not supported */\n \tif (usr_ip6_spec->l4_4_bytes)\n@@ -1194,6 +1256,31 @@ ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg,\n \t\t    sizeof(struct in6_addr)))\n \t\treturn -EINVAL;\n \n+\treturn 0;\n+}\n+\n+/**\n+ * ice_set_fdir_ip6_usr_seg - setup flow segment based on IPv6\n+ * @seg: flow segment for programming\n+ * @usr_ip6_spec: ethtool userdef packet offset\n+ * @perfect_fltr: only set on success; returns true if perfect filter, false if\n+ *\t\t  not\n+ *\n+ * Set the offset data into the flow segment to be used to program HW\n+ * table for IPv6\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg,\n+\t\t\t\t    struct ethtool_usrip6_spec *usr_ip6_spec,\n+\t\t\t\t    bool *perfect_fltr)\n+{\n+\tint err;\n+\n+\terr = ice_ntuple_check_ip6_usr_seg(usr_ip6_spec);\n+\tif (err)\n+\t\treturn err;\n+\n \t*perfect_fltr = true;\n \tICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6);\n \n@@ -1813,6 +1900,60 @@ int ice_del_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)\n \treturn val;\n }\n \n+/**\n+ * ice_is_acl_filter - Check if it's a FD or ACL filter\n+ * @fsp: pointer to ethtool Rx flow specification\n+ *\n+ * If any field of the provided filter is using a partial mask then this is\n+ * an ACL filter.\n+ *\n+ * Return: true if ACL filter, false otherwise\n+ */\n+static bool ice_is_acl_filter(struct ethtool_rx_flow_spec *fsp)\n+{\n+\tstruct ethtool_tcpip4_spec *tcp_ip4_spec;\n+\tstruct ethtool_usrip4_spec *usr_ip4_spec;\n+\n+\tswitch (fsp->flow_type & ~FLOW_EXT) {\n+\tcase TCP_V4_FLOW:\n+\tcase UDP_V4_FLOW:\n+\tcase SCTP_V4_FLOW:\n+\t\ttcp_ip4_spec = &fsp->m_u.tcp_ip4_spec;\n+\n+\t\tif (tcp_ip4_spec->ip4src &&\n+\t\t    tcp_ip4_spec->ip4src != htonl(ICE_FULL_IPV4_ADDR_MASK))\n+\t\t\treturn true;\n+\n+\t\tif (tcp_ip4_spec->ip4dst &&\n+\t\t    tcp_ip4_spec->ip4dst != htonl(ICE_FULL_IPV4_ADDR_MASK))\n+\t\t\treturn true;\n+\n+\t\tif (tcp_ip4_spec->psrc &&\n+\t\t    tcp_ip4_spec->psrc != htons(ICE_FULL_PORT_MASK))\n+\t\t\treturn true;\n+\n+\t\tif (tcp_ip4_spec->pdst &&\n+\t\t    tcp_ip4_spec->pdst != htons(ICE_FULL_PORT_MASK))\n+\t\t\treturn true;\n+\n+\t\tbreak;\n+\tcase IPV4_USER_FLOW:\n+\t\tusr_ip4_spec = &fsp->m_u.usr_ip4_spec;\n+\n+\t\tif (usr_ip4_spec->ip4src &&\n+\t\t    usr_ip4_spec->ip4src != htonl(ICE_FULL_IPV4_ADDR_MASK))\n+\t\t\treturn true;\n+\n+\t\tif (usr_ip4_spec->ip4dst &&\n+\t\t    usr_ip4_spec->ip4dst != htonl(ICE_FULL_IPV4_ADDR_MASK))\n+\t\t\treturn true;\n+\n+\t\tbreak;\n+\t}\n+\n+\treturn false;\n+}\n+\n /**\n  * ice_update_ring_dest_vsi - update dest ring and dest VSI\n  * @vsi: pointer to target VSI\n@@ -2030,7 +2171,7 @@ int ice_add_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)\n \n \t/* Do not program filters during reset */\n \tif (ice_is_reset_in_progress(pf->state)) {\n-\t\tdev_err(dev, \"Device is resetting - adding Flow Director filters not supported during reset\\n\");\n+\t\tdev_err(dev, \"Device is resetting - adding ntuple filters not supported during reset\\n\");\n \t\treturn -EBUSY;\n \t}\n \n@@ -2042,10 +2183,6 @@ int ice_add_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)\n \tif (fsp->flow_type & FLOW_MAC_EXT)\n \t\treturn -EINVAL;\n \n-\tret = ice_cfg_fdir_xtrct_seq(pf, fsp, &userdata);\n-\tif (ret)\n-\t\treturn ret;\n-\n \tmax_location = ice_ntuple_get_max_fltr_cnt(hw);\n \tif (fsp->location >= max_location) {\n \t\tdev_err(dev, \"Failed to add filter. The number of ntuple filters or provided location exceed max %d.\\n\",\n@@ -2053,6 +2190,14 @@ int ice_add_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)\n \t\treturn -ENOSPC;\n \t}\n \n+\t/* ACL filter */\n+\tif (pf->hw.acl_tbl && ice_is_acl_filter(fsp))\n+\t\treturn ice_acl_add_rule_ethtool(vsi, cmd);\n+\n+\tret = ice_cfg_fdir_xtrct_seq(pf, fsp, &userdata);\n+\tif (ret)\n+\t\treturn ret;\n+\n \t/* return error if not an update and no available filters */\n \tfltrs_needed = ice_get_open_tunnel_port(hw, &tunnel_port, TNL_ALL) ? 2 : 1;\n \tif (!ice_fdir_find_fltr_by_idx(hw, fsp->location) &&\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\nindex bb1d12f952cf..d255ffcd5c86 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\n+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\n@@ -1259,6 +1259,9 @@ ice_find_prof_id_with_mask(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_ACL:\n+\t\t*rsrc_type = ICE_AQC_RES_TYPE_ACL_PROF_BLDR_PROFID;\n+\t\tbreak;\n \tcase ICE_BLK_FD:\n \t\t*rsrc_type = ICE_AQC_RES_TYPE_FD_PROF_BLDR_PROFID;\n \t\tbreak;\n@@ -1279,6 +1282,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_ACL:\n+\t\t*rsrc_type = ICE_AQC_RES_TYPE_ACL_PROF_BLDR_TCAM;\n+\t\tbreak;\n \tcase ICE_BLK_FD:\n \t\t*rsrc_type = ICE_AQC_RES_TYPE_FD_PROF_BLDR_TCAM;\n \t\tbreak;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flow.c b/drivers/net/ethernet/intel/ice/ice_flow.c\nindex 121552c644cd..864bbda7e880 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flow.c\n+++ b/drivers/net/ethernet/intel/ice/ice_flow.c\n@@ -3,6 +3,7 @@\n \n #include \"ice_common.h\"\n #include \"ice_flow.h\"\n+#include \"ice_acl.h\"\n #include <net/gre.h>\n \n /* Size of known protocol header fields */\n@@ -989,6 +990,43 @@ static int ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)\n \treturn 0;\n }\n \n+/**\n+ * ice_flow_xtract_pkt_flags - Create an extr sequence entry for packet flags\n+ * @hw: pointer to the HW struct\n+ * @params: information about the flow to be processed\n+ * @flags: The value of pkt_flags[x:x] in Rx/Tx MDID metadata.\n+ *\n+ * Allocate an extraction sequence entries for a DWORD size chunk of the packet\n+ * flags.\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_flow_xtract_pkt_flags(struct ice_hw *hw,\n+\t\t\t\t     struct ice_flow_prof_params *params,\n+\t\t\t\t     enum ice_flex_mdid_pkt_flags flags)\n+{\n+\tu8 fv_words = hw->blk[params->blk].es.fvw;\n+\tu8 idx;\n+\n+\t/* Make sure the number of extraction sequence entries required does not\n+\t * exceed the block's capacity.\n+\t */\n+\tif (params->es_cnt >= fv_words)\n+\t\treturn -ENOSPC;\n+\n+\t/* some blocks require a reversed field vector layout */\n+\tif (hw->blk[params->blk].es.reverse)\n+\t\tidx = fv_words - params->es_cnt - 1;\n+\telse\n+\t\tidx = params->es_cnt;\n+\n+\tparams->es[idx].prot_id = ICE_PROT_META_ID;\n+\tparams->es[idx].off = flags;\n+\tparams->es_cnt++;\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_flow_xtract_fld - Create an extraction sequence entry for the given field\n  * @hw: pointer to the HW struct\n@@ -1287,6 +1325,16 @@ ice_flow_create_xtrct_seq(struct ice_hw *hw,\n \tint status = 0;\n \tu8 i;\n \n+\t/* For ACL, we also need to extract the direction bit (Rx,Tx) data from\n+\t * packet flags\n+\t */\n+\tif (params->blk == ICE_BLK_ACL) {\n+\t\tstatus = ice_flow_xtract_pkt_flags(hw, params,\n+\t\t\t\t\t\t   ICE_RX_MDID_PKT_FLAGS_15_0);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n \tfor (i = 0; i < prof->segs_cnt; i++) {\n \t\tu64 match = params->prof->segs[i].match;\n \t\tenum ice_flow_field j;\n@@ -1308,6 +1356,123 @@ ice_flow_create_xtrct_seq(struct ice_hw *hw,\n \treturn status;\n }\n \n+/**\n+ * ice_flow_sel_acl_scen - return specific scenario\n+ * @hw: pointer to the hardware structure\n+ * @params: information about the flow to be processed\n+ *\n+ * Return (through @params) the specific scenario based on params.\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int ice_flow_sel_acl_scen(struct ice_hw *hw,\n+\t\t\t\t struct ice_flow_prof_params *params)\n+{\n+\t/* Find the best-fit scenario for the provided match width */\n+\tstruct ice_acl_scen *cand_scen = NULL, *scen;\n+\n+\tif (!hw->acl_tbl)\n+\t\treturn -ENOENT;\n+\n+\t/* Loop through each scenario and match against the scenario width\n+\t * to select the specific scenario\n+\t */\n+\tlist_for_each_entry(scen, &hw->acl_tbl->scens, list_entry)\n+\t\tif (scen->eff_width >= params->entry_length &&\n+\t\t    (!cand_scen || cand_scen->eff_width > scen->eff_width))\n+\t\t\tcand_scen = scen;\n+\tif (!cand_scen)\n+\t\treturn -ENOENT;\n+\n+\tparams->prof->cfg.scen = cand_scen;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_flow_acl_def_entry_frmt - Determine the layout of flow entries\n+ * @params: information about the flow to be processed\n+ *\n+ * Return: 0 on success, negative on error\n+ */\n+static int\n+ice_flow_acl_def_entry_frmt(struct ice_flow_prof_params *params)\n+{\n+\tu16 index, range_idx = 0;\n+\n+\tindex = ICE_AQC_ACL_PROF_BYTE_SEL_START_IDX;\n+\n+\tfor (int i = 0; i < params->prof->segs_cnt; i++) {\n+\t\tstruct ice_flow_seg_info *seg = &params->prof->segs[i];\n+\t\tint j;\n+\n+\t\tfor_each_set_bit(j, (unsigned long *)&seg->match,\n+\t\t\t\t ICE_FLOW_FIELD_IDX_MAX) {\n+\t\t\tstruct ice_flow_fld_info *fld = &seg->fields[j];\n+\n+\t\t\tfld->entry.mask = ICE_FLOW_FLD_OFF_INVAL;\n+\n+\t\t\tif (fld->type == ICE_FLOW_FLD_TYPE_RANGE) {\n+\t\t\t\tfld->entry.last = ICE_FLOW_FLD_OFF_INVAL;\n+\n+\t\t\t\t/* Range checking only supported for single\n+\t\t\t\t * words\n+\t\t\t\t */\n+\t\t\t\tif (DIV_ROUND_UP(ice_flds_info[j].size +\n+\t\t\t\t\t\t fld->xtrct.disp,\n+\t\t\t\t\t\t BITS_PER_BYTE * 2) > 1)\n+\t\t\t\t\treturn -EINVAL;\n+\n+\t\t\t\t/* Ranges must define low and high values */\n+\t\t\t\tif (fld->src.val == ICE_FLOW_FLD_OFF_INVAL ||\n+\t\t\t\t    fld->src.last == ICE_FLOW_FLD_OFF_INVAL)\n+\t\t\t\t\treturn -EINVAL;\n+\n+\t\t\t\tfld->entry.val = range_idx++;\n+\t\t\t} else {\n+\t\t\t\t/* Store adjusted byte-length of field for later\n+\t\t\t\t * use, taking into account potential\n+\t\t\t\t * non-byte-aligned displacement\n+\t\t\t\t */\n+\t\t\t\tfld->entry.last =\n+\t\t\t\t\tDIV_ROUND_UP(ice_flds_info[j].size +\n+\t\t\t\t\t\t     (fld->xtrct.disp %\n+\t\t\t\t\t\t      BITS_PER_BYTE),\n+\t\t\t\t\t\t     BITS_PER_BYTE);\n+\t\t\t\tfld->entry.val = index;\n+\t\t\t\tindex += fld->entry.last;\n+\t\t\t}\n+\t\t}\n+\n+\t\tfor (j = 0; j < seg->raws_cnt; j++) {\n+\t\t\tstruct ice_flow_seg_fld_raw *raw = &seg->raws[j];\n+\n+\t\t\traw->info.entry.mask = ICE_FLOW_FLD_OFF_INVAL;\n+\t\t\traw->info.entry.val = index;\n+\t\t\traw->info.entry.last = raw->info.src.last;\n+\t\t\tindex += raw->info.entry.last;\n+\t\t}\n+\t}\n+\n+\t/* Currently only support using the byte selection base, which only\n+\t * allows for an effective entry size of 30 bytes. Reject anything\n+\t * larger.\n+\t */\n+\tif (index > ICE_AQC_ACL_PROF_BYTE_SEL_ELEMS)\n+\t\treturn -EINVAL;\n+\n+\t/* Only 8 range checkers per profile, reject anything trying to use\n+\t * more\n+\t */\n+\tif (range_idx > ICE_AQC_ACL_PROF_RANGES_NUM_CFG)\n+\t\treturn -EINVAL;\n+\n+\t/* Store # bytes required for entry for later use */\n+\tparams->entry_length = index - ICE_AQC_ACL_PROF_BYTE_SEL_START_IDX;\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_flow_proc_segs - process all packet segments associated with a profile\n  * @hw: pointer to the HW struct\n@@ -1331,6 +1496,14 @@ ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)\n \tcase ICE_BLK_RSS:\n \t\tstatus = 0;\n \t\tbreak;\n+\tcase ICE_BLK_ACL:\n+\t\tstatus = ice_flow_acl_def_entry_frmt(params);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t\tstatus = ice_flow_sel_acl_scen(hw, params);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t\tbreak;\n \tdefault:\n \t\treturn -EOPNOTSUPP;\n \t}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex 23d6b8311ff9..59036a22ba91 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -4326,19 +4326,25 @@ static int ice_send_version(struct ice_pf *pf)\n }\n \n /**\n- * ice_init_acl - Initializes the ACL block\n+ * ice_init_acl - initialize the ACL block and allocate necessary structs\n  * @pf: ptr to PF device\n  *\n  * Return: 0 on success, negative on error\n  */\n static int ice_init_acl(struct ice_pf *pf)\n {\n+\tstruct device *dev = ice_pf_to_dev(pf);\n \tstruct ice_acl_tbl_params params = {};\n \tstruct ice_hw *hw = &pf->hw;\n \tint divider;\n \tu16 scen_id;\n \tint err;\n \n+\thw->acl_prof = devm_kcalloc(dev, ICE_FLTR_PTYPE_MAX,\n+\t\t\t\t    sizeof(*hw->acl_prof), GFP_KERNEL);\n+\tif (!hw->acl_prof)\n+\t\treturn -ENOMEM;\n+\n \t/* Creates a single ACL table that consist of src_ip(4 byte),\n \t * dest_ip(4 byte), src_port(2 byte) and dst_port(2 byte) for a total\n \t * of 12 bytes (96 bits), hence 120 bit wide keys, i.e. 3 TCAM slices.\n@@ -4358,7 +4364,7 @@ static int ice_init_acl(struct ice_pf *pf)\n \n \terr = ice_acl_create_tbl(hw, &params);\n \tif (err)\n-\t\treturn err;\n+\t\tgoto free_prof;\n \n \terr = ice_acl_create_scen(hw, params.width, params.depth, &scen_id);\n \tif (err)\n@@ -4368,17 +4374,36 @@ static int ice_init_acl(struct ice_pf *pf)\n \n destroy_table:\n \tice_acl_destroy_tbl(hw);\n+free_prof:\n+\tdevm_kfree(dev, hw->acl_prof);\n+\thw->acl_prof = NULL;\n \n \treturn err;\n }\n \n /**\n- * ice_deinit_acl - Unroll the initialization of the ACL block\n+ * ice_deinit_acl - unroll the initialization of the ACL block\n  * @pf: ptr to PF device\n  */\n static void ice_deinit_acl(struct ice_pf *pf)\n {\n-\tice_acl_destroy_tbl(&pf->hw);\n+\tstruct device *dev = ice_pf_to_dev(pf);\n+\tstruct ice_hw *hw = &pf->hw;\n+\n+\tice_acl_destroy_tbl(hw);\n+\n+\tfor (int i = 0; i < ICE_FLTR_PTYPE_MAX; i++) {\n+\t\tstruct ice_fd_hw_prof *hw_prof = hw->acl_prof[i];\n+\n+\t\tif (!hw_prof)\n+\t\t\tcontinue;\n+\n+\t\tkfree(hw_prof->fdir_seg[0]);\n+\t\tkfree(hw_prof);\n+\t}\n+\n+\tdevm_kfree(dev, hw->acl_prof);\n+\thw->acl_prof = NULL;\n }\n \n /**\n","prefixes":["iwl-next","v2","04/10"]}