Thomas Bogendoerfer e2e5bd
From: Dan Nowlin <dan.nowlin@intel.com>
Thomas Bogendoerfer e2e5bd
Date: Fri, 6 Aug 2021 10:49:00 +0200
Thomas Bogendoerfer e2e5bd
Subject: ice: create advanced switch recipe
Thomas Bogendoerfer e2e5bd
Patch-mainline: v5.16-rc1
Thomas Bogendoerfer e2e5bd
Git-commit: fd2a6b71e3008360c7b26a3d7002fe03dbdc61fd
Thomas Bogendoerfer e2e5bd
References: jsc#SLE-18375
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
These changes introduce code for creating advanced recipes for the
Thomas Bogendoerfer e2e5bd
switch in hardware.
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
There are a couple of recipes already defined in the HW. They apply to
Thomas Bogendoerfer e2e5bd
matching on basic protocol headers, like MAC, VLAN, MACVLAN,
Thomas Bogendoerfer e2e5bd
ethertype or direction (promiscuous), etc.. If the user wants to match on
Thomas Bogendoerfer e2e5bd
other protocol headers (eg. ip address, src/dst port etc.) or different
Thomas Bogendoerfer e2e5bd
variation of already supported protocols, there is a need to create
Thomas Bogendoerfer e2e5bd
new, more complex recipe. That new recipe is referred as
Thomas Bogendoerfer e2e5bd
'advanced recipe', and the filtering rule created on top of that recipe
Thomas Bogendoerfer e2e5bd
is called 'advanced rule'.
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
One recipe can have up to 5 words, but the first word is always reserved
Thomas Bogendoerfer e2e5bd
for match on switch id, so the driver can define up to 4 words for one
Thomas Bogendoerfer e2e5bd
recipe. To support recipes with more words up to 5 recipes can be
Thomas Bogendoerfer e2e5bd
chained, so 20 words can be programmed for look up.
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
Input for adding recipe function is a list of protocols to support. Based
Thomas Bogendoerfer e2e5bd
on this list correct profile is being chosen. Correct profile means
Thomas Bogendoerfer e2e5bd
that it contains all protocol types from a list. Each profile have up to
Thomas Bogendoerfer e2e5bd
48 field vector words and each of this word have protocol id and offset.
Thomas Bogendoerfer e2e5bd
These two fields need to match with input data for adding recipe
Thomas Bogendoerfer e2e5bd
function. If the correct profile can't be found the function returns an
Thomas Bogendoerfer e2e5bd
error.
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
The next step after finding the correct profile is grouping words into
Thomas Bogendoerfer e2e5bd
groups. One group can have up to 4 words. This is done to simplify
Thomas Bogendoerfer e2e5bd
sending recipes to HW (because recipe also can have up to 4 words).
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
In case of chaining (so when look up consists of more than 4 words) last
Thomas Bogendoerfer e2e5bd
recipe will always have results from the previous recipes used as words.
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
A recipe to profile map is used to store information about which profile
Thomas Bogendoerfer e2e5bd
is associate with this recipe. This map is an array of 64 elements (max
Thomas Bogendoerfer e2e5bd
number of recipes) and each element is a 256 bits bitmap (max number of
Thomas Bogendoerfer e2e5bd
profiles)
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
Profile to recipe map is used to store information about which recipe is
Thomas Bogendoerfer e2e5bd
associate with this profile. This map is an array of 256 elements (max
Thomas Bogendoerfer e2e5bd
number of profiles) and each element is a 64 bits bitmap (max number of
Thomas Bogendoerfer e2e5bd
recipes)
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
Signed-off-by: Dan Nowlin <dan.nowlin@intel.com>
Thomas Bogendoerfer e2e5bd
Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
Thomas Bogendoerfer e2e5bd
Tested-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
Thomas Bogendoerfer e2e5bd
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Thomas Bogendoerfer e2e5bd
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Thomas Bogendoerfer e2e5bd
---
Thomas Bogendoerfer e2e5bd
 drivers/net/ethernet/intel/ice/ice_flex_pipe.c     |   33 
Thomas Bogendoerfer e2e5bd
 drivers/net/ethernet/intel/ice/ice_flex_pipe.h     |    6 
Thomas Bogendoerfer e2e5bd
 drivers/net/ethernet/intel/ice/ice_protocol_type.h |  169 +++
Thomas Bogendoerfer e2e5bd
 drivers/net/ethernet/intel/ice/ice_switch.c        | 1116 ++++++++++++++++++++-
Thomas Bogendoerfer e2e5bd
 drivers/net/ethernet/intel/ice/ice_switch.h        |  110 +-
Thomas Bogendoerfer e2e5bd
 5 files changed, 1412 insertions(+), 22 deletions(-)
Thomas Bogendoerfer e2e5bd
Thomas Bogendoerfer e2e5bd
--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
Thomas Bogendoerfer e2e5bd
+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
Thomas Bogendoerfer e2e5bd
@@ -735,7 +735,7 @@ static void ice_release_global_cfg_lock(
Thomas Bogendoerfer e2e5bd
  *
Thomas Bogendoerfer e2e5bd
  * This function will request ownership of the change lock.
Thomas Bogendoerfer e2e5bd
  */
Thomas Bogendoerfer e2e5bd
-static enum ice_status
Thomas Bogendoerfer e2e5bd
+enum ice_status
Thomas Bogendoerfer e2e5bd
 ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)
Thomas Bogendoerfer e2e5bd
 {
Thomas Bogendoerfer e2e5bd
 	return ice_acquire_res(hw, ICE_CHANGE_LOCK_RES_ID, access,
Thomas Bogendoerfer e2e5bd
@@ -748,7 +748,7 @@ ice_acquire_change_lock(struct ice_hw *h
Thomas Bogendoerfer e2e5bd
  *
Thomas Bogendoerfer e2e5bd
  * This function will release the change lock using the proper Admin Command.
Thomas Bogendoerfer e2e5bd
  */
Thomas Bogendoerfer e2e5bd
-static void ice_release_change_lock(struct ice_hw *hw)
Thomas Bogendoerfer e2e5bd
+void ice_release_change_lock(struct ice_hw *hw)
Thomas Bogendoerfer e2e5bd
 {
Thomas Bogendoerfer e2e5bd
 	ice_release_res(hw, ICE_CHANGE_LOCK_RES_ID);
Thomas Bogendoerfer e2e5bd
 }
Thomas Bogendoerfer e2e5bd
@@ -2104,6 +2104,35 @@ int ice_udp_tunnel_unset_port(struct net
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
 	return 0;
Thomas Bogendoerfer e2e5bd
 }
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_find_prot_off - find prot ID and offset pair, based on prof and FV index
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to the hardware structure
Thomas Bogendoerfer e2e5bd
+ * @blk: hardware block
Thomas Bogendoerfer e2e5bd
+ * @prof: profile ID
Thomas Bogendoerfer e2e5bd
+ * @fv_idx: field vector word index
Thomas Bogendoerfer e2e5bd
+ * @prot: variable to receive the protocol ID
Thomas Bogendoerfer e2e5bd
+ * @off: variable to receive the protocol offset
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx,
Thomas Bogendoerfer e2e5bd
+		  u8 *prot, u16 *off)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	struct ice_fv_word *fv_ext;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (prof >= hw->blk[blk].es.count)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_PARAM;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (fv_idx >= hw->blk[blk].es.fvw)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_PARAM;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	fv_ext = hw->blk[blk].es.t + (prof * hw->blk[blk].es.fvw);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	*prot = fv_ext[fv_idx].prot_id;
Thomas Bogendoerfer e2e5bd
+	*off = fv_ext[fv_idx].off;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	return 0;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
 /* PTG Management */
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h
Thomas Bogendoerfer e2e5bd
+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h
Thomas Bogendoerfer e2e5bd
@@ -18,6 +18,12 @@
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
 #define ICE_PKG_CNT 4
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
+enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access);
Thomas Bogendoerfer e2e5bd
+void ice_release_change_lock(struct ice_hw *hw);
Thomas Bogendoerfer e2e5bd
+enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx,
Thomas Bogendoerfer e2e5bd
+		  u8 *prot, u16 *off);
Thomas Bogendoerfer e2e5bd
 void
Thomas Bogendoerfer e2e5bd
 ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type type,
Thomas Bogendoerfer e2e5bd
 		     unsigned long *bm);
Thomas Bogendoerfer e2e5bd
--- a/drivers/net/ethernet/intel/ice/ice_protocol_type.h
Thomas Bogendoerfer e2e5bd
+++ b/drivers/net/ethernet/intel/ice/ice_protocol_type.h
Thomas Bogendoerfer e2e5bd
@@ -3,6 +3,44 @@
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
 #ifndef _ICE_PROTOCOL_TYPE_H_
Thomas Bogendoerfer e2e5bd
 #define _ICE_PROTOCOL_TYPE_H_
Thomas Bogendoerfer e2e5bd
+#define ICE_IPV6_ADDR_LENGTH 16
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* Each recipe can match up to 5 different fields. Fields to match can be meta-
Thomas Bogendoerfer e2e5bd
+ * data, values extracted from packet headers, or results from other recipes.
Thomas Bogendoerfer e2e5bd
+ * One of the 5 fields is reserved for matching the switch ID. So, up to 4
Thomas Bogendoerfer e2e5bd
+ * recipes can provide intermediate results to another one through chaining,
Thomas Bogendoerfer e2e5bd
+ * e.g. recipes 0, 1, 2, and 3 can provide intermediate results to recipe 4.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+#define ICE_NUM_WORDS_RECIPE 4
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* Max recipes that can be chained */
Thomas Bogendoerfer e2e5bd
+#define ICE_MAX_CHAIN_RECIPE 5
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* 1 word reserved for switch ID from allowed 5 words.
Thomas Bogendoerfer e2e5bd
+ * So a recipe can have max 4 words. And you can chain 5 such recipes
Thomas Bogendoerfer e2e5bd
+ * together. So maximum words that can be programmed for look up is 5 * 4.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+#define ICE_MAX_CHAIN_WORDS (ICE_NUM_WORDS_RECIPE * ICE_MAX_CHAIN_RECIPE)
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* Field vector index corresponding to chaining */
Thomas Bogendoerfer e2e5bd
+#define ICE_CHAIN_FV_INDEX_START 47
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+enum ice_protocol_type {
Thomas Bogendoerfer e2e5bd
+	ICE_MAC_OFOS = 0,
Thomas Bogendoerfer e2e5bd
+	ICE_MAC_IL,
Thomas Bogendoerfer e2e5bd
+	ICE_ETYPE_OL,
Thomas Bogendoerfer e2e5bd
+	ICE_VLAN_OFOS,
Thomas Bogendoerfer e2e5bd
+	ICE_IPV4_OFOS,
Thomas Bogendoerfer e2e5bd
+	ICE_IPV4_IL,
Thomas Bogendoerfer e2e5bd
+	ICE_IPV6_OFOS,
Thomas Bogendoerfer e2e5bd
+	ICE_IPV6_IL,
Thomas Bogendoerfer e2e5bd
+	ICE_TCP_IL,
Thomas Bogendoerfer e2e5bd
+	ICE_UDP_OF,
Thomas Bogendoerfer e2e5bd
+	ICE_UDP_ILOS,
Thomas Bogendoerfer e2e5bd
+	ICE_SCTP_IL,
Thomas Bogendoerfer e2e5bd
+	ICE_PROTOCOL_LAST
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
 /* Decoders for ice_prot_id:
Thomas Bogendoerfer e2e5bd
  * - F: First
Thomas Bogendoerfer e2e5bd
  * - I: Inner
Thomas Bogendoerfer e2e5bd
@@ -35,4 +73,135 @@ enum ice_prot_id {
Thomas Bogendoerfer e2e5bd
 	ICE_PROT_META_ID	= 255, /* when offset == metadata */
Thomas Bogendoerfer e2e5bd
 	ICE_PROT_INVALID	= 255  /* when offset == ICE_FV_OFFSET_INVAL */
Thomas Bogendoerfer e2e5bd
 };
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+#define ICE_MAC_OFOS_HW		1
Thomas Bogendoerfer e2e5bd
+#define ICE_MAC_IL_HW		4
Thomas Bogendoerfer e2e5bd
+#define ICE_ETYPE_OL_HW		9
Thomas Bogendoerfer e2e5bd
+#define ICE_VLAN_OF_HW		16
Thomas Bogendoerfer e2e5bd
+#define ICE_VLAN_OL_HW		17
Thomas Bogendoerfer e2e5bd
+#define ICE_IPV4_OFOS_HW	32
Thomas Bogendoerfer e2e5bd
+#define ICE_IPV4_IL_HW		33
Thomas Bogendoerfer e2e5bd
+#define ICE_IPV6_OFOS_HW	40
Thomas Bogendoerfer e2e5bd
+#define ICE_IPV6_IL_HW		41
Thomas Bogendoerfer e2e5bd
+#define ICE_TCP_IL_HW		49
Thomas Bogendoerfer e2e5bd
+#define ICE_UDP_ILOS_HW		53
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+#define ICE_UDP_OF_HW	52 /* UDP Tunnels */
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+#define ICE_TUN_FLAG_FV_IND 2
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* Mapping of software defined protocol ID to hardware defined protocol ID */
Thomas Bogendoerfer e2e5bd
+struct ice_protocol_entry {
Thomas Bogendoerfer e2e5bd
+	enum ice_protocol_type type;
Thomas Bogendoerfer e2e5bd
+	u8 protocol_id;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_ether_hdr {
Thomas Bogendoerfer e2e5bd
+	u8 dst_addr[ETH_ALEN];
Thomas Bogendoerfer e2e5bd
+	u8 src_addr[ETH_ALEN];
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_ethtype_hdr {
Thomas Bogendoerfer e2e5bd
+	__be16 ethtype_id;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_ether_vlan_hdr {
Thomas Bogendoerfer e2e5bd
+	u8 dst_addr[ETH_ALEN];
Thomas Bogendoerfer e2e5bd
+	u8 src_addr[ETH_ALEN];
Thomas Bogendoerfer e2e5bd
+	__be32 vlan_id;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_vlan_hdr {
Thomas Bogendoerfer e2e5bd
+	__be16 type;
Thomas Bogendoerfer e2e5bd
+	__be16 vlan;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_ipv4_hdr {
Thomas Bogendoerfer e2e5bd
+	u8 version;
Thomas Bogendoerfer e2e5bd
+	u8 tos;
Thomas Bogendoerfer e2e5bd
+	__be16 total_length;
Thomas Bogendoerfer e2e5bd
+	__be16 id;
Thomas Bogendoerfer e2e5bd
+	__be16 frag_off;
Thomas Bogendoerfer e2e5bd
+	u8 time_to_live;
Thomas Bogendoerfer e2e5bd
+	u8 protocol;
Thomas Bogendoerfer e2e5bd
+	__be16 check;
Thomas Bogendoerfer e2e5bd
+	__be32 src_addr;
Thomas Bogendoerfer e2e5bd
+	__be32 dst_addr;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_ipv6_hdr {
Thomas Bogendoerfer e2e5bd
+	__be32 be_ver_tc_flow;
Thomas Bogendoerfer e2e5bd
+	__be16 payload_len;
Thomas Bogendoerfer e2e5bd
+	u8 next_hdr;
Thomas Bogendoerfer e2e5bd
+	u8 hop_limit;
Thomas Bogendoerfer e2e5bd
+	u8 src_addr[ICE_IPV6_ADDR_LENGTH];
Thomas Bogendoerfer e2e5bd
+	u8 dst_addr[ICE_IPV6_ADDR_LENGTH];
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_sctp_hdr {
Thomas Bogendoerfer e2e5bd
+	__be16 src_port;
Thomas Bogendoerfer e2e5bd
+	__be16 dst_port;
Thomas Bogendoerfer e2e5bd
+	__be32 verification_tag;
Thomas Bogendoerfer e2e5bd
+	__be32 check;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_l4_hdr {
Thomas Bogendoerfer e2e5bd
+	__be16 src_port;
Thomas Bogendoerfer e2e5bd
+	__be16 dst_port;
Thomas Bogendoerfer e2e5bd
+	__be16 len;
Thomas Bogendoerfer e2e5bd
+	__be16 check;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+union ice_prot_hdr {
Thomas Bogendoerfer e2e5bd
+	struct ice_ether_hdr eth_hdr;
Thomas Bogendoerfer e2e5bd
+	struct ice_ethtype_hdr ethertype;
Thomas Bogendoerfer e2e5bd
+	struct ice_vlan_hdr vlan_hdr;
Thomas Bogendoerfer e2e5bd
+	struct ice_ipv4_hdr ipv4_hdr;
Thomas Bogendoerfer e2e5bd
+	struct ice_ipv6_hdr ipv6_hdr;
Thomas Bogendoerfer e2e5bd
+	struct ice_l4_hdr l4_hdr;
Thomas Bogendoerfer e2e5bd
+	struct ice_sctp_hdr sctp_hdr;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* This is mapping table entry that maps every word within a given protocol
Thomas Bogendoerfer e2e5bd
+ * structure to the real byte offset as per the specification of that
Thomas Bogendoerfer e2e5bd
+ * protocol header.
Thomas Bogendoerfer e2e5bd
+ * for e.g. dst address is 3 words in ethertype header and corresponding bytes
Thomas Bogendoerfer e2e5bd
+ * are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+struct ice_prot_ext_tbl_entry {
Thomas Bogendoerfer e2e5bd
+	enum ice_protocol_type prot_type;
Thomas Bogendoerfer e2e5bd
+	/* Byte offset into header of given protocol type */
Thomas Bogendoerfer e2e5bd
+	u8 offs[sizeof(union ice_prot_hdr)];
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* Extractions to be looked up for a given recipe */
Thomas Bogendoerfer e2e5bd
+struct ice_prot_lkup_ext {
Thomas Bogendoerfer e2e5bd
+	u16 prot_type;
Thomas Bogendoerfer e2e5bd
+	u8 n_val_words;
Thomas Bogendoerfer e2e5bd
+	/* create a buffer to hold max words per recipe */
Thomas Bogendoerfer e2e5bd
+	u16 field_off[ICE_MAX_CHAIN_WORDS];
Thomas Bogendoerfer e2e5bd
+	u16 field_mask[ICE_MAX_CHAIN_WORDS];
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	struct ice_fv_word fv_words[ICE_MAX_CHAIN_WORDS];
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Indicate field offsets that have field vector indices assigned */
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(done, ICE_MAX_CHAIN_WORDS);
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_pref_recipe_group {
Thomas Bogendoerfer e2e5bd
+	u8 n_val_pairs;		/* Number of valid pairs */
Thomas Bogendoerfer e2e5bd
+	struct ice_fv_word pairs[ICE_NUM_WORDS_RECIPE];
Thomas Bogendoerfer e2e5bd
+	u16 mask[ICE_NUM_WORDS_RECIPE];
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_recp_grp_entry {
Thomas Bogendoerfer e2e5bd
+	struct list_head l_entry;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+#define ICE_INVAL_CHAIN_IND 0xFF
Thomas Bogendoerfer e2e5bd
+	u16 rid;
Thomas Bogendoerfer e2e5bd
+	u8 chain_idx;
Thomas Bogendoerfer e2e5bd
+	u16 fv_idx[ICE_NUM_WORDS_RECIPE];
Thomas Bogendoerfer e2e5bd
+	u16 fv_mask[ICE_NUM_WORDS_RECIPE];
Thomas Bogendoerfer e2e5bd
+	struct ice_pref_recipe_group r_group;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
 #endif /* _ICE_PROTOCOL_TYPE_H_ */
Thomas Bogendoerfer e2e5bd
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
Thomas Bogendoerfer e2e5bd
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
Thomas Bogendoerfer e2e5bd
@@ -42,6 +42,14 @@ static const u8 dummy_eth_header[DUMMY_E
Thomas Bogendoerfer e2e5bd
 	(offsetof(struct ice_aqc_sw_rules_elem, pdata.vsi_list.vsi) + \
Thomas Bogendoerfer e2e5bd
 	 ((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi[0])))
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
+/* this is a recipe to profile association bitmap */
Thomas Bogendoerfer e2e5bd
+static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES],
Thomas Bogendoerfer e2e5bd
+			  ICE_MAX_NUM_PROFILES);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* this is a profile to recipe association bitmap */
Thomas Bogendoerfer e2e5bd
+static DECLARE_BITMAP(profile_to_recipe[ICE_MAX_NUM_PROFILES],
Thomas Bogendoerfer e2e5bd
+			  ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
 /**
Thomas Bogendoerfer e2e5bd
  * ice_init_def_sw_recp - initialize the recipe book keeping tables
Thomas Bogendoerfer e2e5bd
  * @hw: pointer to the HW struct
Thomas Bogendoerfer e2e5bd
@@ -553,7 +561,7 @@ ice_aq_sw_rules(struct ice_hw *hw, void
Thomas Bogendoerfer e2e5bd
  *
Thomas Bogendoerfer e2e5bd
  * Add(0x0290)
Thomas Bogendoerfer e2e5bd
  */
Thomas Bogendoerfer e2e5bd
-static enum ice_status __maybe_unused
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
 ice_aq_add_recipe(struct ice_hw *hw,
Thomas Bogendoerfer e2e5bd
 		  struct ice_aqc_recipe_data_elem *s_recipe_list,
Thomas Bogendoerfer e2e5bd
 		  u16 num_recipes, struct ice_sq_cd *cd)
Thomas Bogendoerfer e2e5bd
@@ -590,7 +598,7 @@ ice_aq_add_recipe(struct ice_hw *hw,
Thomas Bogendoerfer e2e5bd
  * The caller must supply enough space in s_recipe_list to hold all possible
Thomas Bogendoerfer e2e5bd
  * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES.
Thomas Bogendoerfer e2e5bd
  */
Thomas Bogendoerfer e2e5bd
-static enum ice_status __maybe_unused
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
 ice_aq_get_recipe(struct ice_hw *hw,
Thomas Bogendoerfer e2e5bd
 		  struct ice_aqc_recipe_data_elem *s_recipe_list,
Thomas Bogendoerfer e2e5bd
 		  u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd)
Thomas Bogendoerfer e2e5bd
@@ -625,7 +633,7 @@ ice_aq_get_recipe(struct ice_hw *hw,
Thomas Bogendoerfer e2e5bd
  * @cd: pointer to command details structure or NULL
Thomas Bogendoerfer e2e5bd
  * Recipe to profile association (0x0291)
Thomas Bogendoerfer e2e5bd
  */
Thomas Bogendoerfer e2e5bd
-static enum ice_status __maybe_unused
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
 ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
Thomas Bogendoerfer e2e5bd
 			     struct ice_sq_cd *cd)
Thomas Bogendoerfer e2e5bd
 {
Thomas Bogendoerfer e2e5bd
@@ -651,7 +659,7 @@ ice_aq_map_recipe_to_profile(struct ice_
Thomas Bogendoerfer e2e5bd
  * @cd: pointer to command details structure or NULL
Thomas Bogendoerfer e2e5bd
  * Associate profile ID with given recipe (0x0293)
Thomas Bogendoerfer e2e5bd
  */
Thomas Bogendoerfer e2e5bd
-static enum ice_status __maybe_unused
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
 ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
Thomas Bogendoerfer e2e5bd
 			     struct ice_sq_cd *cd)
Thomas Bogendoerfer e2e5bd
 {
Thomas Bogendoerfer e2e5bd
@@ -675,7 +683,7 @@ ice_aq_get_recipe_to_profile(struct ice_
Thomas Bogendoerfer e2e5bd
  * @hw: pointer to the hardware structure
Thomas Bogendoerfer e2e5bd
  * @rid: recipe ID returned as response to AQ call
Thomas Bogendoerfer e2e5bd
  */
Thomas Bogendoerfer e2e5bd
-static enum ice_status __maybe_unused ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
Thomas Bogendoerfer e2e5bd
+static enum ice_status ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
Thomas Bogendoerfer e2e5bd
 {
Thomas Bogendoerfer e2e5bd
 	struct ice_aqc_alloc_free_res_elem *sw_buf;
Thomas Bogendoerfer e2e5bd
 	enum ice_status status;
Thomas Bogendoerfer e2e5bd
@@ -699,6 +707,203 @@ static enum ice_status __maybe_unused ic
Thomas Bogendoerfer e2e5bd
 	return status;
Thomas Bogendoerfer e2e5bd
 }
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_get_recp_to_prof_map - updates recipe to profile mapping
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * This function is used to populate recipe_to_profile matrix where index to
Thomas Bogendoerfer e2e5bd
+ * this array is the recipe ID and the element is the mapping of which profiles
Thomas Bogendoerfer e2e5bd
+ * is this recipe mapped to.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static void ice_get_recp_to_prof_map(struct ice_hw *hw)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+	u16 i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) {
Thomas Bogendoerfer e2e5bd
+		u16 j;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		bitmap_zero(profile_to_recipe[i], ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+		bitmap_zero(r_bitmap, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+		if (ice_aq_get_recipe_to_profile(hw, i, (u8 *)r_bitmap, NULL))
Thomas Bogendoerfer e2e5bd
+			continue;
Thomas Bogendoerfer e2e5bd
+		bitmap_copy(profile_to_recipe[i], r_bitmap,
Thomas Bogendoerfer e2e5bd
+			    ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+		for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES)
Thomas Bogendoerfer e2e5bd
+			set_bit(i, recipe_to_profile[j]);
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_collect_result_idx - copy result index values
Thomas Bogendoerfer e2e5bd
+ * @buf: buffer that contains the result index
Thomas Bogendoerfer e2e5bd
+ * @recp: the recipe struct to copy data into
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static void
Thomas Bogendoerfer e2e5bd
+ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
Thomas Bogendoerfer e2e5bd
+		       struct ice_sw_recipe *recp)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
Thomas Bogendoerfer e2e5bd
+		set_bit(buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
Thomas Bogendoerfer e2e5bd
+			recp->res_idxs);
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ * @recps: struct that we need to populate
Thomas Bogendoerfer e2e5bd
+ * @rid: recipe ID that we are populating
Thomas Bogendoerfer e2e5bd
+ * @refresh_required: true if we should get recipe to profile mapping from FW
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * This function is used to populate all the necessary entries into our
Thomas Bogendoerfer e2e5bd
+ * bookkeeping so that we have a current list of all the recipes that are
Thomas Bogendoerfer e2e5bd
+ * programmed in the firmware.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
Thomas Bogendoerfer e2e5bd
+		    bool *refresh_required)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	struct ice_aqc_recipe_data_elem *tmp;
Thomas Bogendoerfer e2e5bd
+	u16 num_recps = ICE_MAX_NUM_RECIPES;
Thomas Bogendoerfer e2e5bd
+	struct ice_prot_lkup_ext *lkup_exts;
Thomas Bogendoerfer e2e5bd
+	enum ice_status status;
Thomas Bogendoerfer e2e5bd
+	u8 fv_word_idx = 0;
Thomas Bogendoerfer e2e5bd
+	u16 sub_recps;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(result_bm, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* we need a buffer big enough to accommodate all the recipes */
Thomas Bogendoerfer e2e5bd
+	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+	if (!tmp)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	tmp[0].recipe_indx = rid;
Thomas Bogendoerfer e2e5bd
+	status = ice_aq_get_recipe(hw, tmp, &num_recps, rid, NULL);
Thomas Bogendoerfer e2e5bd
+	/* non-zero status meaning recipe doesn't exist */
Thomas Bogendoerfer e2e5bd
+	if (status)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Get recipe to profile map so that we can get the fv from lkups that
Thomas Bogendoerfer e2e5bd
+	 * we read for a recipe from FW. Since we want to minimize the number of
Thomas Bogendoerfer e2e5bd
+	 * times we make this FW call, just make one call and cache the copy
Thomas Bogendoerfer e2e5bd
+	 * until a new recipe is added. This operation is only required the
Thomas Bogendoerfer e2e5bd
+	 * first time to get the changes from FW. Then to search existing
Thomas Bogendoerfer e2e5bd
+	 * entries we don't need to update the cache again until another recipe
Thomas Bogendoerfer e2e5bd
+	 * gets added.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	if (*refresh_required) {
Thomas Bogendoerfer e2e5bd
+		ice_get_recp_to_prof_map(hw);
Thomas Bogendoerfer e2e5bd
+		*refresh_required = false;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Start populating all the entries for recps[rid] based on lkups from
Thomas Bogendoerfer e2e5bd
+	 * firmware. Note that we are only creating the root recipe in our
Thomas Bogendoerfer e2e5bd
+	 * database.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	lkup_exts = &recps[rid].lkup_exts;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	for (sub_recps = 0; sub_recps < num_recps; sub_recps++) {
Thomas Bogendoerfer e2e5bd
+		struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps];
Thomas Bogendoerfer e2e5bd
+		struct ice_recp_grp_entry *rg_entry;
Thomas Bogendoerfer e2e5bd
+		u8 i, prof, idx, prot = 0;
Thomas Bogendoerfer e2e5bd
+		bool is_root;
Thomas Bogendoerfer e2e5bd
+		u16 off = 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		rg_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rg_entry),
Thomas Bogendoerfer e2e5bd
+					GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+		if (!rg_entry) {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		idx = root_bufs.recipe_indx;
Thomas Bogendoerfer e2e5bd
+		is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Mark all result indices in this chain */
Thomas Bogendoerfer e2e5bd
+		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN)
Thomas Bogendoerfer e2e5bd
+			set_bit(root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN,
Thomas Bogendoerfer e2e5bd
+				result_bm);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* get the first profile that is associated with rid */
Thomas Bogendoerfer e2e5bd
+		prof = find_first_bit(recipe_to_profile[idx],
Thomas Bogendoerfer e2e5bd
+				      ICE_MAX_NUM_PROFILES);
Thomas Bogendoerfer e2e5bd
+		for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) {
Thomas Bogendoerfer e2e5bd
+			u8 lkup_indx = root_bufs.content.lkup_indx[i + 1];
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			rg_entry->fv_idx[i] = lkup_indx;
Thomas Bogendoerfer e2e5bd
+			rg_entry->fv_mask[i] =
Thomas Bogendoerfer e2e5bd
+				le16_to_cpu(root_bufs.content.mask[i + 1]);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			/* If the recipe is a chained recipe then all its
Thomas Bogendoerfer e2e5bd
+			 * child recipe's result will have a result index.
Thomas Bogendoerfer e2e5bd
+			 * To fill fv_words we should not use those result
Thomas Bogendoerfer e2e5bd
+			 * index, we only need the protocol ids and offsets.
Thomas Bogendoerfer e2e5bd
+			 * We will skip all the fv_idx which stores result
Thomas Bogendoerfer e2e5bd
+			 * index in them. We also need to skip any fv_idx which
Thomas Bogendoerfer e2e5bd
+			 * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a
Thomas Bogendoerfer e2e5bd
+			 * valid offset value.
Thomas Bogendoerfer e2e5bd
+			 */
Thomas Bogendoerfer e2e5bd
+			if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) ||
Thomas Bogendoerfer e2e5bd
+			    rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE ||
Thomas Bogendoerfer e2e5bd
+			    rg_entry->fv_idx[i] == 0)
Thomas Bogendoerfer e2e5bd
+				continue;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			ice_find_prot_off(hw, ICE_BLK_SW, prof,
Thomas Bogendoerfer e2e5bd
+					  rg_entry->fv_idx[i], &prot, &off;;
Thomas Bogendoerfer e2e5bd
+			lkup_exts->fv_words[fv_word_idx].prot_id = prot;
Thomas Bogendoerfer e2e5bd
+			lkup_exts->fv_words[fv_word_idx].off = off;
Thomas Bogendoerfer e2e5bd
+			lkup_exts->field_mask[fv_word_idx] =
Thomas Bogendoerfer e2e5bd
+				rg_entry->fv_mask[i];
Thomas Bogendoerfer e2e5bd
+			fv_word_idx++;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+		/* populate rg_list with the data from the child entry of this
Thomas Bogendoerfer e2e5bd
+		 * recipe
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		list_add(&rg_entry->l_entry, &recps[rid].rg_list);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Propagate some data to the recipe database */
Thomas Bogendoerfer e2e5bd
+		recps[idx].is_root = !!is_root;
Thomas Bogendoerfer e2e5bd
+		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
Thomas Bogendoerfer e2e5bd
+		bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+		if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) {
Thomas Bogendoerfer e2e5bd
+			recps[idx].chain_idx = root_bufs.content.result_indx &
Thomas Bogendoerfer e2e5bd
+				~ICE_AQ_RECIPE_RESULT_EN;
Thomas Bogendoerfer e2e5bd
+			set_bit(recps[idx].chain_idx, recps[idx].res_idxs);
Thomas Bogendoerfer e2e5bd
+		} else {
Thomas Bogendoerfer e2e5bd
+			recps[idx].chain_idx = ICE_INVAL_CHAIN_IND;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		if (!is_root)
Thomas Bogendoerfer e2e5bd
+			continue;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Only do the following for root recipes entries */
Thomas Bogendoerfer e2e5bd
+		memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap,
Thomas Bogendoerfer e2e5bd
+		       sizeof(recps[idx].r_bitmap));
Thomas Bogendoerfer e2e5bd
+		recps[idx].root_rid = root_bufs.content.rid &
Thomas Bogendoerfer e2e5bd
+			~ICE_AQ_RECIPE_ID_IS_ROOT;
Thomas Bogendoerfer e2e5bd
+		recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Complete initialization of the root recipe entry */
Thomas Bogendoerfer e2e5bd
+	lkup_exts->n_val_words = fv_word_idx;
Thomas Bogendoerfer e2e5bd
+	recps[rid].big_recp = (num_recps > 1);
Thomas Bogendoerfer e2e5bd
+	recps[rid].n_grp_count = (u8)num_recps;
Thomas Bogendoerfer e2e5bd
+	recps[rid].root_buf = devm_kmemdup(ice_hw_to_dev(hw), tmp,
Thomas Bogendoerfer e2e5bd
+					   recps[rid].n_grp_count * sizeof(*recps[rid].root_buf),
Thomas Bogendoerfer e2e5bd
+					   GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+	if (!recps[rid].root_buf)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Copy result indexes */
Thomas Bogendoerfer e2e5bd
+	bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	recps[rid].recp_created = true;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+err_unroll:
Thomas Bogendoerfer e2e5bd
+	kfree(tmp);
Thomas Bogendoerfer e2e5bd
+	return status;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
 /* ice_init_port_info - Initialize port_info with switch configuration data
Thomas Bogendoerfer e2e5bd
  * @pi: pointer to port_info
Thomas Bogendoerfer e2e5bd
  * @vsi_port_num: VSI number or port number
Thomas Bogendoerfer e2e5bd
@@ -2929,6 +3134,907 @@ ice_free_res_cntr(struct ice_hw *hw, u8
Thomas Bogendoerfer e2e5bd
 	return status;
Thomas Bogendoerfer e2e5bd
 }
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
+/* This is mapping table entry that maps every word within a given protocol
Thomas Bogendoerfer e2e5bd
+ * structure to the real byte offset as per the specification of that
Thomas Bogendoerfer e2e5bd
+ * protocol header.
Thomas Bogendoerfer e2e5bd
+ * for example dst address is 3 words in ethertype header and corresponding
Thomas Bogendoerfer e2e5bd
+ * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8
Thomas Bogendoerfer e2e5bd
+ * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a
Thomas Bogendoerfer e2e5bd
+ * matching entry describing its field. This needs to be updated if new
Thomas Bogendoerfer e2e5bd
+ * structure is added to that union.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
Thomas Bogendoerfer e2e5bd
+	{ ICE_MAC_OFOS,		{ 0, 2, 4, 6, 8, 10, 12 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_MAC_IL,		{ 0, 2, 4, 6, 8, 10, 12 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_ETYPE_OL,		{ 0 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_VLAN_OFOS,	{ 2, 0 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV4_OFOS,	{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV4_IL,		{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV6_OFOS,	{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
Thomas Bogendoerfer e2e5bd
+				 26, 28, 30, 32, 34, 36, 38 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV6_IL,		{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
Thomas Bogendoerfer e2e5bd
+				 26, 28, 30, 32, 34, 36, 38 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_TCP_IL,		{ 0, 2 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_UDP_OF,		{ 0, 2 } },
Thomas Bogendoerfer e2e5bd
+	{ ICE_UDP_ILOS,		{ 0, 2 } },
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
Thomas Bogendoerfer e2e5bd
+	{ ICE_MAC_OFOS,		ICE_MAC_OFOS_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_MAC_IL,		ICE_MAC_IL_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_ETYPE_OL,		ICE_ETYPE_OL_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_VLAN_OFOS,	ICE_VLAN_OL_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV4_OFOS,	ICE_IPV4_OFOS_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV4_IL,		ICE_IPV4_IL_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV6_OFOS,	ICE_IPV6_OFOS_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_IPV6_IL,		ICE_IPV6_IL_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_TCP_IL,		ICE_TCP_IL_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_UDP_OF,		ICE_UDP_OF_HW },
Thomas Bogendoerfer e2e5bd
+	{ ICE_UDP_ILOS,		ICE_UDP_ILOS_HW },
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_find_recp - find a recipe
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to the hardware structure
Thomas Bogendoerfer e2e5bd
+ * @lkup_exts: extension sequence to match
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	bool refresh_required = true;
Thomas Bogendoerfer e2e5bd
+	struct ice_sw_recipe *recp;
Thomas Bogendoerfer e2e5bd
+	u8 i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Walk through existing recipes to find a match */
Thomas Bogendoerfer e2e5bd
+	recp = hw->switch_info->recp_list;
Thomas Bogendoerfer e2e5bd
+	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
Thomas Bogendoerfer e2e5bd
+		/* If recipe was not created for this ID, in SW bookkeeping,
Thomas Bogendoerfer e2e5bd
+		 * check if FW has an entry for this recipe. If the FW has an
Thomas Bogendoerfer e2e5bd
+		 * entry update it in our SW bookkeeping and continue with the
Thomas Bogendoerfer e2e5bd
+		 * matching.
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		if (!recp[i].recp_created)
Thomas Bogendoerfer e2e5bd
+			if (ice_get_recp_frm_fw(hw,
Thomas Bogendoerfer e2e5bd
+						hw->switch_info->recp_list, i,
Thomas Bogendoerfer e2e5bd
+						&refresh_required))
Thomas Bogendoerfer e2e5bd
+				continue;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Skip inverse action recipes */
Thomas Bogendoerfer e2e5bd
+		if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl &
Thomas Bogendoerfer e2e5bd
+		    ICE_AQ_RECIPE_ACT_INV_ACT)
Thomas Bogendoerfer e2e5bd
+			continue;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* if number of words we are looking for match */
Thomas Bogendoerfer e2e5bd
+		if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) {
Thomas Bogendoerfer e2e5bd
+			struct ice_fv_word *ar = recp[i].lkup_exts.fv_words;
Thomas Bogendoerfer e2e5bd
+			struct ice_fv_word *be = lkup_exts->fv_words;
Thomas Bogendoerfer e2e5bd
+			u16 *cr = recp[i].lkup_exts.field_mask;
Thomas Bogendoerfer e2e5bd
+			u16 *de = lkup_exts->field_mask;
Thomas Bogendoerfer e2e5bd
+			bool found = true;
Thomas Bogendoerfer e2e5bd
+			u8 pe, qr;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			/* ar, cr, and qr are related to the recipe words, while
Thomas Bogendoerfer e2e5bd
+			 * be, de, and pe are related to the lookup words
Thomas Bogendoerfer e2e5bd
+			 */
Thomas Bogendoerfer e2e5bd
+			for (pe = 0; pe < lkup_exts->n_val_words; pe++) {
Thomas Bogendoerfer e2e5bd
+				for (qr = 0; qr < recp[i].lkup_exts.n_val_words;
Thomas Bogendoerfer e2e5bd
+				     qr++) {
Thomas Bogendoerfer e2e5bd
+					if (ar[qr].off == be[pe].off &&
Thomas Bogendoerfer e2e5bd
+					    ar[qr].prot_id == be[pe].prot_id &&
Thomas Bogendoerfer e2e5bd
+					    cr[qr] == de[pe])
Thomas Bogendoerfer e2e5bd
+						/* Found the "pe"th word in the
Thomas Bogendoerfer e2e5bd
+						 * given recipe
Thomas Bogendoerfer e2e5bd
+						 */
Thomas Bogendoerfer e2e5bd
+						break;
Thomas Bogendoerfer e2e5bd
+				}
Thomas Bogendoerfer e2e5bd
+				/* After walking through all the words in the
Thomas Bogendoerfer e2e5bd
+				 * "i"th recipe if "p"th word was not found then
Thomas Bogendoerfer e2e5bd
+				 * this recipe is not what we are looking for.
Thomas Bogendoerfer e2e5bd
+				 * So break out from this loop and try the next
Thomas Bogendoerfer e2e5bd
+				 * recipe
Thomas Bogendoerfer e2e5bd
+				 */
Thomas Bogendoerfer e2e5bd
+				if (qr >= recp[i].lkup_exts.n_val_words) {
Thomas Bogendoerfer e2e5bd
+					found = false;
Thomas Bogendoerfer e2e5bd
+					break;
Thomas Bogendoerfer e2e5bd
+				}
Thomas Bogendoerfer e2e5bd
+			}
Thomas Bogendoerfer e2e5bd
+			/* If for "i"th recipe the found was never set to false
Thomas Bogendoerfer e2e5bd
+			 * then it means we found our match
Thomas Bogendoerfer e2e5bd
+			 */
Thomas Bogendoerfer e2e5bd
+			if (found)
Thomas Bogendoerfer e2e5bd
+				return i; /* Return the recipe ID */
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+	return ICE_MAX_NUM_RECIPES;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_prot_type_to_id - get protocol ID from protocol type
Thomas Bogendoerfer e2e5bd
+ * @type: protocol type
Thomas Bogendoerfer e2e5bd
+ * @id: pointer to variable that will receive the ID
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * Returns true if found, false otherwise
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	u8 i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++)
Thomas Bogendoerfer e2e5bd
+		if (ice_prot_id_tbl[i].type == type) {
Thomas Bogendoerfer e2e5bd
+			*id = ice_prot_id_tbl[i].protocol_id;
Thomas Bogendoerfer e2e5bd
+			return true;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+	return false;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_fill_valid_words - count valid words
Thomas Bogendoerfer e2e5bd
+ * @rule: advanced rule with lookup information
Thomas Bogendoerfer e2e5bd
+ * @lkup_exts: byte offset extractions of the words that are valid
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * calculate valid words in a lookup rule using mask value
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static u8
Thomas Bogendoerfer e2e5bd
+ice_fill_valid_words(struct ice_adv_lkup_elem *rule,
Thomas Bogendoerfer e2e5bd
+		     struct ice_prot_lkup_ext *lkup_exts)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	u8 j, word, prot_id, ret_val;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (!ice_prot_type_to_id(rule->type, &prot_id))
Thomas Bogendoerfer e2e5bd
+		return 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	word = lkup_exts->n_val_words;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++)
Thomas Bogendoerfer e2e5bd
+		if (((u16 *)&rule->m_u)[j] &&
Thomas Bogendoerfer e2e5bd
+		    rule->type < ARRAY_SIZE(ice_prot_ext)) {
Thomas Bogendoerfer e2e5bd
+			/* No more space to accommodate */
Thomas Bogendoerfer e2e5bd
+			if (word >= ICE_MAX_CHAIN_WORDS)
Thomas Bogendoerfer e2e5bd
+				return 0;
Thomas Bogendoerfer e2e5bd
+			lkup_exts->fv_words[word].off =
Thomas Bogendoerfer e2e5bd
+				ice_prot_ext[rule->type].offs[j];
Thomas Bogendoerfer e2e5bd
+			lkup_exts->fv_words[word].prot_id =
Thomas Bogendoerfer e2e5bd
+				ice_prot_id_tbl[rule->type].protocol_id;
Thomas Bogendoerfer e2e5bd
+			lkup_exts->field_mask[word] =
Thomas Bogendoerfer e2e5bd
+				be16_to_cpu(((__force __be16 *)&rule->m_u)[j]);
Thomas Bogendoerfer e2e5bd
+			word++;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	ret_val = word - lkup_exts->n_val_words;
Thomas Bogendoerfer e2e5bd
+	lkup_exts->n_val_words = word;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	return ret_val;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_create_first_fit_recp_def - Create a recipe grouping
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to the hardware structure
Thomas Bogendoerfer e2e5bd
+ * @lkup_exts: an array of protocol header extractions
Thomas Bogendoerfer e2e5bd
+ * @rg_list: pointer to a list that stores new recipe groups
Thomas Bogendoerfer e2e5bd
+ * @recp_cnt: pointer to a variable that stores returned number of recipe groups
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * Using first fit algorithm, take all the words that are still not done
Thomas Bogendoerfer e2e5bd
+ * and start grouping them in 4-word groups. Each group makes up one
Thomas Bogendoerfer e2e5bd
+ * recipe.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_create_first_fit_recp_def(struct ice_hw *hw,
Thomas Bogendoerfer e2e5bd
+			      struct ice_prot_lkup_ext *lkup_exts,
Thomas Bogendoerfer e2e5bd
+			      struct list_head *rg_list,
Thomas Bogendoerfer e2e5bd
+			      u8 *recp_cnt)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	struct ice_pref_recipe_group *grp = NULL;
Thomas Bogendoerfer e2e5bd
+	u8 j;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	*recp_cnt = 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Walk through every word in the rule to check if it is not done. If so
Thomas Bogendoerfer e2e5bd
+	 * then this word needs to be part of a new recipe.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	for (j = 0; j < lkup_exts->n_val_words; j++)
Thomas Bogendoerfer e2e5bd
+		if (!test_bit(j, lkup_exts->done)) {
Thomas Bogendoerfer e2e5bd
+			if (!grp ||
Thomas Bogendoerfer e2e5bd
+			    grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) {
Thomas Bogendoerfer e2e5bd
+				struct ice_recp_grp_entry *entry;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+				entry = devm_kzalloc(ice_hw_to_dev(hw),
Thomas Bogendoerfer e2e5bd
+						     sizeof(*entry),
Thomas Bogendoerfer e2e5bd
+						     GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+				if (!entry)
Thomas Bogendoerfer e2e5bd
+					return ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+				list_add(&entry->l_entry, rg_list);
Thomas Bogendoerfer e2e5bd
+				grp = &entry->r_group;
Thomas Bogendoerfer e2e5bd
+				(*recp_cnt)++;
Thomas Bogendoerfer e2e5bd
+			}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			grp->pairs[grp->n_val_pairs].prot_id =
Thomas Bogendoerfer e2e5bd
+				lkup_exts->fv_words[j].prot_id;
Thomas Bogendoerfer e2e5bd
+			grp->pairs[grp->n_val_pairs].off =
Thomas Bogendoerfer e2e5bd
+				lkup_exts->fv_words[j].off;
Thomas Bogendoerfer e2e5bd
+			grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j];
Thomas Bogendoerfer e2e5bd
+			grp->n_val_pairs++;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	return 0;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_fill_fv_word_index - fill in the field vector indices for a recipe group
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to the hardware structure
Thomas Bogendoerfer e2e5bd
+ * @fv_list: field vector with the extraction sequence information
Thomas Bogendoerfer e2e5bd
+ * @rg_list: recipe groupings with protocol-offset pairs
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * Helper function to fill in the field vector indices for protocol-offset
Thomas Bogendoerfer e2e5bd
+ * pairs. These indexes are then ultimately programmed into a recipe.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list,
Thomas Bogendoerfer e2e5bd
+		       struct list_head *rg_list)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	struct ice_sw_fv_list_entry *fv;
Thomas Bogendoerfer e2e5bd
+	struct ice_recp_grp_entry *rg;
Thomas Bogendoerfer e2e5bd
+	struct ice_fv_word *fv_ext;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (list_empty(fv_list))
Thomas Bogendoerfer e2e5bd
+		return 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry,
Thomas Bogendoerfer e2e5bd
+			      list_entry);
Thomas Bogendoerfer e2e5bd
+	fv_ext = fv->fv_ptr->ew;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	list_for_each_entry(rg, rg_list, l_entry) {
Thomas Bogendoerfer e2e5bd
+		u8 i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		for (i = 0; i < rg->r_group.n_val_pairs; i++) {
Thomas Bogendoerfer e2e5bd
+			struct ice_fv_word *pr;
Thomas Bogendoerfer e2e5bd
+			bool found = false;
Thomas Bogendoerfer e2e5bd
+			u16 mask;
Thomas Bogendoerfer e2e5bd
+			u8 j;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			pr = &rg->r_group.pairs[i];
Thomas Bogendoerfer e2e5bd
+			mask = rg->r_group.mask[i];
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
Thomas Bogendoerfer e2e5bd
+				if (fv_ext[j].prot_id == pr->prot_id &&
Thomas Bogendoerfer e2e5bd
+				    fv_ext[j].off == pr->off) {
Thomas Bogendoerfer e2e5bd
+					found = true;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+					/* Store index of field vector */
Thomas Bogendoerfer e2e5bd
+					rg->fv_idx[i] = j;
Thomas Bogendoerfer e2e5bd
+					rg->fv_mask[i] = mask;
Thomas Bogendoerfer e2e5bd
+					break;
Thomas Bogendoerfer e2e5bd
+				}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			/* Protocol/offset could not be found, caller gave an
Thomas Bogendoerfer e2e5bd
+			 * invalid pair
Thomas Bogendoerfer e2e5bd
+			 */
Thomas Bogendoerfer e2e5bd
+			if (!found)
Thomas Bogendoerfer e2e5bd
+				return ICE_ERR_PARAM;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	return 0;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_find_free_recp_res_idx - find free result indexes for recipe
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ * @profiles: bitmap of profiles that will be associated with the new recipe
Thomas Bogendoerfer e2e5bd
+ * @free_idx: pointer to variable to receive the free index bitmap
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ * The algorithm used here is:
Thomas Bogendoerfer e2e5bd
+ *	1. When creating a new recipe, create a set P which contains all
Thomas Bogendoerfer e2e5bd
+ *	   Profiles that will be associated with our new recipe
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ *	2. For each Profile p in set P:
Thomas Bogendoerfer e2e5bd
+ *	    a. Add all recipes associated with Profile p into set R
Thomas Bogendoerfer e2e5bd
+ *	    b. Optional : PossibleIndexes &= profile[p].possibleIndexes
Thomas Bogendoerfer e2e5bd
+ *		[initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF]
Thomas Bogendoerfer e2e5bd
+ *		i. Or just assume they all have the same possible indexes:
Thomas Bogendoerfer e2e5bd
+ *			44, 45, 46, 47
Thomas Bogendoerfer e2e5bd
+ *			i.e., PossibleIndexes = 0x0000F00000000000
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ *	3. For each Recipe r in set R:
Thomas Bogendoerfer e2e5bd
+ *	    a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes
Thomas Bogendoerfer e2e5bd
+ *	    b. FreeIndexes = UsedIndexes ^ PossibleIndexes
Thomas Bogendoerfer e2e5bd
+ *
Thomas Bogendoerfer e2e5bd
+ *	FreeIndexes will contain the bits indicating the indexes free for use,
Thomas Bogendoerfer e2e5bd
+ *      then the code needs to update the recipe[r].used_result_idx_bits to
Thomas Bogendoerfer e2e5bd
+ *      indicate which indexes were selected for use by this recipe.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static u16
Thomas Bogendoerfer e2e5bd
+ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles,
Thomas Bogendoerfer e2e5bd
+			   unsigned long *free_idx)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	u16 bit;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(possible_idx, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(recipes, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(used_idx, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(free_idx, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	bitmap_set(possible_idx, 0, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* For each profile we are going to associate the recipe with, add the
Thomas Bogendoerfer e2e5bd
+	 * recipes that are associated with that profile. This will give us
Thomas Bogendoerfer e2e5bd
+	 * the set of recipes that our recipe may collide with. Also, determine
Thomas Bogendoerfer e2e5bd
+	 * what possible result indexes are usable given this set of profiles.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) {
Thomas Bogendoerfer e2e5bd
+		bitmap_or(recipes, recipes, profile_to_recipe[bit],
Thomas Bogendoerfer e2e5bd
+			  ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+		bitmap_and(possible_idx, possible_idx,
Thomas Bogendoerfer e2e5bd
+			   hw->switch_info->prof_res_bm[bit],
Thomas Bogendoerfer e2e5bd
+			   ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* For each recipe that our new recipe may collide with, determine
Thomas Bogendoerfer e2e5bd
+	 * which indexes have been used.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES)
Thomas Bogendoerfer e2e5bd
+		bitmap_or(used_idx, used_idx,
Thomas Bogendoerfer e2e5bd
+			  hw->switch_info->recp_list[bit].res_idxs,
Thomas Bogendoerfer e2e5bd
+			  ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* return number of free indexes */
Thomas Bogendoerfer e2e5bd
+	return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_add_sw_recipe - function to call AQ calls to create switch recipe
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ * @rm: recipe management list entry
Thomas Bogendoerfer e2e5bd
+ * @match_tun_mask: tunnel mask that needs to be programmed
Thomas Bogendoerfer e2e5bd
+ * @profiles: bitmap of profiles that will be associated.
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
Thomas Bogendoerfer e2e5bd
+		  u16 match_tun_mask, unsigned long *profiles)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	struct ice_aqc_recipe_data_elem *tmp;
Thomas Bogendoerfer e2e5bd
+	struct ice_aqc_recipe_data_elem *buf;
Thomas Bogendoerfer e2e5bd
+	struct ice_recp_grp_entry *entry;
Thomas Bogendoerfer e2e5bd
+	enum ice_status status;
Thomas Bogendoerfer e2e5bd
+	u16 free_res_idx;
Thomas Bogendoerfer e2e5bd
+	u16 recipe_count;
Thomas Bogendoerfer e2e5bd
+	u8 chain_idx;
Thomas Bogendoerfer e2e5bd
+	u8 recps = 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* When more than one recipe are required, another recipe is needed to
Thomas Bogendoerfer e2e5bd
+	 * chain them together. Matching a tunnel metadata ID takes up one of
Thomas Bogendoerfer e2e5bd
+	 * the match fields in the chaining recipe reducing the number of
Thomas Bogendoerfer e2e5bd
+	 * chained recipes by one.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	 /* check number of free result indices */
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(result_idx_bm, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	free_res_idx = ice_find_free_recp_res_idx(hw, profiles, result_idx_bm);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n",
Thomas Bogendoerfer e2e5bd
+		  free_res_idx, rm->n_grp_count);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (rm->n_grp_count > 1) {
Thomas Bogendoerfer e2e5bd
+		if (rm->n_grp_count > free_res_idx)
Thomas Bogendoerfer e2e5bd
+			return ICE_ERR_MAX_LIMIT;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		rm->n_grp_count++;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_MAX_LIMIT;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+	if (!tmp)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	buf = devm_kcalloc(ice_hw_to_dev(hw), rm->n_grp_count, sizeof(*buf),
Thomas Bogendoerfer e2e5bd
+			   GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+	if (!buf) {
Thomas Bogendoerfer e2e5bd
+		status = ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+		goto err_mem;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(rm->r_bitmap, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+	recipe_count = ICE_MAX_NUM_RECIPES;
Thomas Bogendoerfer e2e5bd
+	status = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC,
Thomas Bogendoerfer e2e5bd
+				   NULL);
Thomas Bogendoerfer e2e5bd
+	if (status || recipe_count == 0)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Allocate the recipe resources, and configure them according to the
Thomas Bogendoerfer e2e5bd
+	 * match fields from protocol headers and extracted field vectors.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	chain_idx = find_first_bit(result_idx_bm, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+	list_for_each_entry(entry, &rm->rg_list, l_entry) {
Thomas Bogendoerfer e2e5bd
+		u8 i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		status = ice_alloc_recipe(hw, &entry->rid);
Thomas Bogendoerfer e2e5bd
+		if (status)
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Clear the result index of the located recipe, as this will be
Thomas Bogendoerfer e2e5bd
+		 * updated, if needed, later in the recipe creation process.
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		tmp[0].content.result_indx = 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		buf[recps] = tmp[0];
Thomas Bogendoerfer e2e5bd
+		buf[recps].recipe_indx = (u8)entry->rid;
Thomas Bogendoerfer e2e5bd
+		/* if the recipe is a non-root recipe RID should be programmed
Thomas Bogendoerfer e2e5bd
+		 * as 0 for the rules to be applied correctly.
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.rid = 0;
Thomas Bogendoerfer e2e5bd
+		memset(&buf[recps].content.lkup_indx, 0,
Thomas Bogendoerfer e2e5bd
+		       sizeof(buf[recps].content.lkup_indx));
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* All recipes use look-up index 0 to match switch ID. */
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.mask[0] =
Thomas Bogendoerfer e2e5bd
+			cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
Thomas Bogendoerfer e2e5bd
+		/* Setup lkup_indx 1..4 to INVALID/ignore and set the mask
Thomas Bogendoerfer e2e5bd
+		 * to be 0
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.lkup_indx[i] = 0x80;
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.mask[i] = 0;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		for (i = 0; i < entry->r_group.n_val_pairs; i++) {
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i];
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.mask[i + 1] =
Thomas Bogendoerfer e2e5bd
+				cpu_to_le16(entry->fv_mask[i]);
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		if (rm->n_grp_count > 1) {
Thomas Bogendoerfer e2e5bd
+			/* Checks to see if there really is a valid result index
Thomas Bogendoerfer e2e5bd
+			 * that can be used.
Thomas Bogendoerfer e2e5bd
+			 */
Thomas Bogendoerfer e2e5bd
+			if (chain_idx >= ICE_MAX_FV_WORDS) {
Thomas Bogendoerfer e2e5bd
+				ice_debug(hw, ICE_DBG_SW, "No chain index available\n");
Thomas Bogendoerfer e2e5bd
+				status = ICE_ERR_MAX_LIMIT;
Thomas Bogendoerfer e2e5bd
+				goto err_unroll;
Thomas Bogendoerfer e2e5bd
+			}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+			entry->chain_idx = chain_idx;
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.result_indx =
Thomas Bogendoerfer e2e5bd
+				ICE_AQ_RECIPE_RESULT_EN |
Thomas Bogendoerfer e2e5bd
+				((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
Thomas Bogendoerfer e2e5bd
+				 ICE_AQ_RECIPE_RESULT_DATA_M);
Thomas Bogendoerfer e2e5bd
+			clear_bit(chain_idx, result_idx_bm);
Thomas Bogendoerfer e2e5bd
+			chain_idx = find_first_bit(result_idx_bm,
Thomas Bogendoerfer e2e5bd
+						   ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* fill recipe dependencies */
Thomas Bogendoerfer e2e5bd
+		bitmap_zero((unsigned long *)buf[recps].recipe_bitmap,
Thomas Bogendoerfer e2e5bd
+			    ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+		set_bit(buf[recps].recipe_indx,
Thomas Bogendoerfer e2e5bd
+			(unsigned long *)buf[recps].recipe_bitmap);
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.act_ctrl_fwd_priority = rm->priority;
Thomas Bogendoerfer e2e5bd
+		recps++;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (rm->n_grp_count == 1) {
Thomas Bogendoerfer e2e5bd
+		rm->root_rid = buf[0].recipe_indx;
Thomas Bogendoerfer e2e5bd
+		set_bit(buf[0].recipe_indx, rm->r_bitmap);
Thomas Bogendoerfer e2e5bd
+		buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT;
Thomas Bogendoerfer e2e5bd
+		if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) {
Thomas Bogendoerfer e2e5bd
+			memcpy(buf[0].recipe_bitmap, rm->r_bitmap,
Thomas Bogendoerfer e2e5bd
+			       sizeof(buf[0].recipe_bitmap));
Thomas Bogendoerfer e2e5bd
+		} else {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_BAD_PTR;
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+		/* Applicable only for ROOT_RECIPE, set the fwd_priority for
Thomas Bogendoerfer e2e5bd
+		 * the recipe which is getting created if specified
Thomas Bogendoerfer e2e5bd
+		 * by user. Usually any advanced switch filter, which results
Thomas Bogendoerfer e2e5bd
+		 * into new extraction sequence, ended up creating a new recipe
Thomas Bogendoerfer e2e5bd
+		 * of type ROOT and usually recipes are associated with profiles
Thomas Bogendoerfer e2e5bd
+		 * Switch rule referreing newly created recipe, needs to have
Thomas Bogendoerfer e2e5bd
+		 * either/or 'fwd' or 'join' priority, otherwise switch rule
Thomas Bogendoerfer e2e5bd
+		 * evaluation will not happen correctly. In other words, if
Thomas Bogendoerfer e2e5bd
+		 * switch rule to be evaluated on priority basis, then recipe
Thomas Bogendoerfer e2e5bd
+		 * needs to have priority, otherwise it will be evaluated last.
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		buf[0].content.act_ctrl_fwd_priority = rm->priority;
Thomas Bogendoerfer e2e5bd
+	} else {
Thomas Bogendoerfer e2e5bd
+		struct ice_recp_grp_entry *last_chain_entry;
Thomas Bogendoerfer e2e5bd
+		u16 rid, i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Allocate the last recipe that will chain the outcomes of the
Thomas Bogendoerfer e2e5bd
+		 * other recipes together
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		status = ice_alloc_recipe(hw, &rid;;
Thomas Bogendoerfer e2e5bd
+		if (status)
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		buf[recps].recipe_indx = (u8)rid;
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.rid = (u8)rid;
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
Thomas Bogendoerfer e2e5bd
+		/* the new entry created should also be part of rg_list to
Thomas Bogendoerfer e2e5bd
+		 * make sure we have complete recipe
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		last_chain_entry = devm_kzalloc(ice_hw_to_dev(hw),
Thomas Bogendoerfer e2e5bd
+						sizeof(*last_chain_entry),
Thomas Bogendoerfer e2e5bd
+						GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+		if (!last_chain_entry) {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+		last_chain_entry->rid = rid;
Thomas Bogendoerfer e2e5bd
+		memset(&buf[recps].content.lkup_indx, 0,
Thomas Bogendoerfer e2e5bd
+		       sizeof(buf[recps].content.lkup_indx));
Thomas Bogendoerfer e2e5bd
+		/* All recipes use look-up index 0 to match switch ID. */
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.mask[0] =
Thomas Bogendoerfer e2e5bd
+			cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
Thomas Bogendoerfer e2e5bd
+		for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.lkup_indx[i] =
Thomas Bogendoerfer e2e5bd
+				ICE_AQ_RECIPE_LKUP_IGNORE;
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.mask[i] = 0;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		i = 1;
Thomas Bogendoerfer e2e5bd
+		/* update r_bitmap with the recp that is used for chaining */
Thomas Bogendoerfer e2e5bd
+		set_bit(rid, rm->r_bitmap);
Thomas Bogendoerfer e2e5bd
+		/* this is the recipe that chains all the other recipes so it
Thomas Bogendoerfer e2e5bd
+		 * should not have a chaining ID to indicate the same
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;
Thomas Bogendoerfer e2e5bd
+		list_for_each_entry(entry, &rm->rg_list, l_entry) {
Thomas Bogendoerfer e2e5bd
+			last_chain_entry->fv_idx[i] = entry->chain_idx;
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.lkup_indx[i] = entry->chain_idx;
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF);
Thomas Bogendoerfer e2e5bd
+			set_bit(entry->rid, rm->r_bitmap);
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+		list_add(&last_chain_entry->l_entry, &rm->rg_list);
Thomas Bogendoerfer e2e5bd
+		if (sizeof(buf[recps].recipe_bitmap) >=
Thomas Bogendoerfer e2e5bd
+		    sizeof(rm->r_bitmap)) {
Thomas Bogendoerfer e2e5bd
+			memcpy(buf[recps].recipe_bitmap, rm->r_bitmap,
Thomas Bogendoerfer e2e5bd
+			       sizeof(buf[recps].recipe_bitmap));
Thomas Bogendoerfer e2e5bd
+		} else {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_BAD_PTR;
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+		buf[recps].content.act_ctrl_fwd_priority = rm->priority;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* To differentiate among different UDP tunnels, a meta data ID
Thomas Bogendoerfer e2e5bd
+		 * flag is used.
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		if (match_tun_mask) {
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.lkup_indx[i] = ICE_TUN_FLAG_FV_IND;
Thomas Bogendoerfer e2e5bd
+			buf[recps].content.mask[i] =
Thomas Bogendoerfer e2e5bd
+				cpu_to_le16(match_tun_mask);
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		recps++;
Thomas Bogendoerfer e2e5bd
+		rm->root_rid = (u8)rid;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+	status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
Thomas Bogendoerfer e2e5bd
+	if (status)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	status = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL);
Thomas Bogendoerfer e2e5bd
+	ice_release_change_lock(hw);
Thomas Bogendoerfer e2e5bd
+	if (status)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Every recipe that just got created add it to the recipe
Thomas Bogendoerfer e2e5bd
+	 * book keeping list
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	list_for_each_entry(entry, &rm->rg_list, l_entry) {
Thomas Bogendoerfer e2e5bd
+		struct ice_switch_info *sw = hw->switch_info;
Thomas Bogendoerfer e2e5bd
+		bool is_root, idx_found = false;
Thomas Bogendoerfer e2e5bd
+		struct ice_sw_recipe *recp;
Thomas Bogendoerfer e2e5bd
+		u16 idx, buf_idx = 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* find buffer index for copying some data */
Thomas Bogendoerfer e2e5bd
+		for (idx = 0; idx < rm->n_grp_count; idx++)
Thomas Bogendoerfer e2e5bd
+			if (buf[idx].recipe_indx == entry->rid) {
Thomas Bogendoerfer e2e5bd
+				buf_idx = idx;
Thomas Bogendoerfer e2e5bd
+				idx_found = true;
Thomas Bogendoerfer e2e5bd
+			}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		if (!idx_found) {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_OUT_OF_RANGE;
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		recp = &sw->recp_list[entry->rid];
Thomas Bogendoerfer e2e5bd
+		is_root = (rm->root_rid == entry->rid);
Thomas Bogendoerfer e2e5bd
+		recp->is_root = is_root;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		recp->root_rid = entry->rid;
Thomas Bogendoerfer e2e5bd
+		recp->big_recp = (is_root && rm->n_grp_count > 1);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		memcpy(&recp->ext_words, entry->r_group.pairs,
Thomas Bogendoerfer e2e5bd
+		       entry->r_group.n_val_pairs * sizeof(struct ice_fv_word));
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap,
Thomas Bogendoerfer e2e5bd
+		       sizeof(recp->r_bitmap));
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Copy non-result fv index values and masks to recipe. This
Thomas Bogendoerfer e2e5bd
+		 * call will also update the result recipe bitmask.
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		ice_collect_result_idx(&buf[buf_idx], recp);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* for non-root recipes, also copy to the root, this allows
Thomas Bogendoerfer e2e5bd
+		 * easier matching of a complete chained recipe
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		if (!is_root)
Thomas Bogendoerfer e2e5bd
+			ice_collect_result_idx(&buf[buf_idx],
Thomas Bogendoerfer e2e5bd
+					       &sw->recp_list[rm->root_rid]);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		recp->n_ext_words = entry->r_group.n_val_pairs;
Thomas Bogendoerfer e2e5bd
+		recp->chain_idx = entry->chain_idx;
Thomas Bogendoerfer e2e5bd
+		recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
Thomas Bogendoerfer e2e5bd
+		recp->n_grp_count = rm->n_grp_count;
Thomas Bogendoerfer e2e5bd
+		recp->recp_created = true;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+	rm->root_buf = buf;
Thomas Bogendoerfer e2e5bd
+	kfree(tmp);
Thomas Bogendoerfer e2e5bd
+	return status;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+err_unroll:
Thomas Bogendoerfer e2e5bd
+err_mem:
Thomas Bogendoerfer e2e5bd
+	kfree(tmp);
Thomas Bogendoerfer e2e5bd
+	devm_kfree(ice_hw_to_dev(hw), buf);
Thomas Bogendoerfer e2e5bd
+	return status;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_create_recipe_group - creates recipe group
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ * @rm: recipe management list entry
Thomas Bogendoerfer e2e5bd
+ * @lkup_exts: lookup elements
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm,
Thomas Bogendoerfer e2e5bd
+			struct ice_prot_lkup_ext *lkup_exts)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	enum ice_status status;
Thomas Bogendoerfer e2e5bd
+	u8 recp_count = 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	rm->n_grp_count = 0;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Create recipes for words that are marked not done by packing them
Thomas Bogendoerfer e2e5bd
+	 * as best fit.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	status = ice_create_first_fit_recp_def(hw, lkup_exts,
Thomas Bogendoerfer e2e5bd
+					       &rm->rg_list, &recp_count);
Thomas Bogendoerfer e2e5bd
+	if (!status) {
Thomas Bogendoerfer e2e5bd
+		rm->n_grp_count += recp_count;
Thomas Bogendoerfer e2e5bd
+		rm->n_ext_words = lkup_exts->n_val_words;
Thomas Bogendoerfer e2e5bd
+		memcpy(&rm->ext_words, lkup_exts->fv_words,
Thomas Bogendoerfer e2e5bd
+		       sizeof(rm->ext_words));
Thomas Bogendoerfer e2e5bd
+		memcpy(rm->word_masks, lkup_exts->field_mask,
Thomas Bogendoerfer e2e5bd
+		       sizeof(rm->word_masks));
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	return status;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_get_fv - get field vectors/extraction sequences for spec. lookup types
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ * @lkups: lookup elements or match criteria for the advanced recipe, one
Thomas Bogendoerfer e2e5bd
+ *	   structure per protocol header
Thomas Bogendoerfer e2e5bd
+ * @lkups_cnt: number of protocols
Thomas Bogendoerfer e2e5bd
+ * @bm: bitmap of field vectors to consider
Thomas Bogendoerfer e2e5bd
+ * @fv_list: pointer to a list that holds the returned field vectors
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static enum ice_status
Thomas Bogendoerfer e2e5bd
+ice_get_fv(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
Thomas Bogendoerfer e2e5bd
+	   unsigned long *bm, struct list_head *fv_list)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	enum ice_status status;
Thomas Bogendoerfer e2e5bd
+	u8 *prot_ids;
Thomas Bogendoerfer e2e5bd
+	u16 i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	prot_ids = kcalloc(lkups_cnt, sizeof(*prot_ids), GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+	if (!prot_ids)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	for (i = 0; i < lkups_cnt; i++)
Thomas Bogendoerfer e2e5bd
+		if (!ice_prot_type_to_id(lkups[i].type, &prot_ids[i])) {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_CFG;
Thomas Bogendoerfer e2e5bd
+			goto free_mem;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Find field vectors that include all specified protocol types */
Thomas Bogendoerfer e2e5bd
+	status = ice_get_sw_fv_list(hw, prot_ids, lkups_cnt, bm, fv_list);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+free_mem:
Thomas Bogendoerfer e2e5bd
+	kfree(prot_ids);
Thomas Bogendoerfer e2e5bd
+	return status;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ * @rinfo: other information regarding the rule e.g. priority and action info
Thomas Bogendoerfer e2e5bd
+ * @bm: pointer to memory for returning the bitmap of field vectors
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static void
Thomas Bogendoerfer e2e5bd
+ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
Thomas Bogendoerfer e2e5bd
+			 unsigned long *bm)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	ice_get_sw_fv_bitmap(hw, ICE_PROF_NON_TUN, bm);
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/**
Thomas Bogendoerfer e2e5bd
+ * ice_add_adv_recipe - Add an advanced recipe that is not part of the default
Thomas Bogendoerfer e2e5bd
+ * @hw: pointer to hardware structure
Thomas Bogendoerfer e2e5bd
+ * @lkups: lookup elements or match criteria for the advanced recipe, one
Thomas Bogendoerfer e2e5bd
+ *  structure per protocol header
Thomas Bogendoerfer e2e5bd
+ * @lkups_cnt: number of protocols
Thomas Bogendoerfer e2e5bd
+ * @rinfo: other information regarding the rule e.g. priority and action info
Thomas Bogendoerfer e2e5bd
+ * @rid: return the recipe ID of the recipe created
Thomas Bogendoerfer e2e5bd
+ */
Thomas Bogendoerfer e2e5bd
+static enum ice_status __maybe_unused
Thomas Bogendoerfer e2e5bd
+ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
Thomas Bogendoerfer e2e5bd
+		   u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid)
Thomas Bogendoerfer e2e5bd
+{
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES);
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES);
Thomas Bogendoerfer e2e5bd
+	struct ice_prot_lkup_ext *lkup_exts;
Thomas Bogendoerfer e2e5bd
+	struct ice_recp_grp_entry *r_entry;
Thomas Bogendoerfer e2e5bd
+	struct ice_sw_fv_list_entry *fvit;
Thomas Bogendoerfer e2e5bd
+	struct ice_recp_grp_entry *r_tmp;
Thomas Bogendoerfer e2e5bd
+	struct ice_sw_fv_list_entry *tmp;
Thomas Bogendoerfer e2e5bd
+	enum ice_status status = 0;
Thomas Bogendoerfer e2e5bd
+	struct ice_sw_recipe *rm;
Thomas Bogendoerfer e2e5bd
+	u16 match_tun_mask = 0;
Thomas Bogendoerfer e2e5bd
+	u8 i;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (!lkups_cnt)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_PARAM;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+	if (!lkup_exts)
Thomas Bogendoerfer e2e5bd
+		return ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Determine the number of words to be matched and if it exceeds a
Thomas Bogendoerfer e2e5bd
+	 * recipe's restrictions
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	for (i = 0; i < lkups_cnt; i++) {
Thomas Bogendoerfer e2e5bd
+		u16 count;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		if (lkups[i].type >= ICE_PROTOCOL_LAST) {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_CFG;
Thomas Bogendoerfer e2e5bd
+			goto err_free_lkup_exts;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		count = ice_fill_valid_words(&lkups[i], lkup_exts);
Thomas Bogendoerfer e2e5bd
+		if (!count) {
Thomas Bogendoerfer e2e5bd
+			status = ICE_ERR_CFG;
Thomas Bogendoerfer e2e5bd
+			goto err_free_lkup_exts;
Thomas Bogendoerfer e2e5bd
+		}
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	rm = kzalloc(sizeof(*rm), GFP_KERNEL);
Thomas Bogendoerfer e2e5bd
+	if (!rm) {
Thomas Bogendoerfer e2e5bd
+		status = ICE_ERR_NO_MEMORY;
Thomas Bogendoerfer e2e5bd
+		goto err_free_lkup_exts;
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Get field vectors that contain fields extracted from all the protocol
Thomas Bogendoerfer e2e5bd
+	 * headers being programmed.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	INIT_LIST_HEAD(&rm->fv_list);
Thomas Bogendoerfer e2e5bd
+	INIT_LIST_HEAD(&rm->rg_list);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Get bitmap of field vectors (profiles) that are compatible with the
Thomas Bogendoerfer e2e5bd
+	 * rule request; only these will be searched in the subsequent call to
Thomas Bogendoerfer e2e5bd
+	 * ice_get_fv.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	ice_get_compat_fv_bitmap(hw, rinfo, fv_bitmap);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	status = ice_get_fv(hw, lkups, lkups_cnt, fv_bitmap, &rm->fv_list);
Thomas Bogendoerfer e2e5bd
+	if (status)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Group match words into recipes using preferred recipe grouping
Thomas Bogendoerfer e2e5bd
+	 * criteria.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	status = ice_create_recipe_group(hw, rm, lkup_exts);
Thomas Bogendoerfer e2e5bd
+	if (status)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* set the recipe priority if specified */
Thomas Bogendoerfer e2e5bd
+	rm->priority = (u8)rinfo->priority;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Find offsets from the field vector. Pick the first one for all the
Thomas Bogendoerfer e2e5bd
+	 * recipes.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	status = ice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list);
Thomas Bogendoerfer e2e5bd
+	if (status)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* get bitmap of all profiles the recipe will be associated with */
Thomas Bogendoerfer e2e5bd
+	bitmap_zero(profiles, ICE_MAX_NUM_PROFILES);
Thomas Bogendoerfer e2e5bd
+	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
Thomas Bogendoerfer e2e5bd
+		ice_debug(hw, ICE_DBG_SW, "profile: %d\n", fvit->profile_id);
Thomas Bogendoerfer e2e5bd
+		set_bit((u16)fvit->profile_id, profiles);
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Look for a recipe which matches our requested fv / mask list */
Thomas Bogendoerfer e2e5bd
+	*rid = ice_find_recp(hw, lkup_exts);
Thomas Bogendoerfer e2e5bd
+	if (*rid < ICE_MAX_NUM_RECIPES)
Thomas Bogendoerfer e2e5bd
+		/* Success if found a recipe that match the existing criteria */
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Recipe we need does not exist, add a recipe */
Thomas Bogendoerfer e2e5bd
+	status = ice_add_sw_recipe(hw, rm, match_tun_mask, profiles);
Thomas Bogendoerfer e2e5bd
+	if (status)
Thomas Bogendoerfer e2e5bd
+		goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Associate all the recipes created with all the profiles in the
Thomas Bogendoerfer e2e5bd
+	 * common field vector.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	list_for_each_entry(fvit, &rm->fv_list, list_entry) {
Thomas Bogendoerfer e2e5bd
+		DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+		u16 j;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id,
Thomas Bogendoerfer e2e5bd
+						      (u8 *)r_bitmap, NULL);
Thomas Bogendoerfer e2e5bd
+		if (status)
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap,
Thomas Bogendoerfer e2e5bd
+			  ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+		status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
Thomas Bogendoerfer e2e5bd
+		if (status)
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id,
Thomas Bogendoerfer e2e5bd
+						      (u8 *)r_bitmap,
Thomas Bogendoerfer e2e5bd
+						      NULL);
Thomas Bogendoerfer e2e5bd
+		ice_release_change_lock(hw);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		if (status)
Thomas Bogendoerfer e2e5bd
+			goto err_unroll;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Update profile to recipe bitmap array */
Thomas Bogendoerfer e2e5bd
+		bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap,
Thomas Bogendoerfer e2e5bd
+			    ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+		/* Update recipe to profile bitmap array */
Thomas Bogendoerfer e2e5bd
+		for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES)
Thomas Bogendoerfer e2e5bd
+			set_bit((u16)fvit->profile_id, recipe_to_profile[j]);
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	*rid = rm->root_rid;
Thomas Bogendoerfer e2e5bd
+	memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts,
Thomas Bogendoerfer e2e5bd
+	       sizeof(*lkup_exts));
Thomas Bogendoerfer e2e5bd
+err_unroll:
Thomas Bogendoerfer e2e5bd
+	list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) {
Thomas Bogendoerfer e2e5bd
+		list_del(&r_entry->l_entry);
Thomas Bogendoerfer e2e5bd
+		devm_kfree(ice_hw_to_dev(hw), r_entry);
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) {
Thomas Bogendoerfer e2e5bd
+		list_del(&fvit->list_entry);
Thomas Bogendoerfer e2e5bd
+		devm_kfree(ice_hw_to_dev(hw), fvit);
Thomas Bogendoerfer e2e5bd
+	}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	if (rm->root_buf)
Thomas Bogendoerfer e2e5bd
+		devm_kfree(ice_hw_to_dev(hw), rm->root_buf);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	kfree(rm);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+err_free_lkup_exts:
Thomas Bogendoerfer e2e5bd
+	kfree(lkup_exts);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	return status;
Thomas Bogendoerfer e2e5bd
+}
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
 /**
Thomas Bogendoerfer e2e5bd
  * ice_replay_vsi_fltr - Replay filters for requested VSI
Thomas Bogendoerfer e2e5bd
  * @hw: pointer to the hardware structure
Thomas Bogendoerfer e2e5bd
--- a/drivers/net/ethernet/intel/ice/ice_switch.h
Thomas Bogendoerfer e2e5bd
+++ b/drivers/net/ethernet/intel/ice/ice_switch.h
Thomas Bogendoerfer e2e5bd
@@ -125,30 +125,110 @@ struct ice_fltr_info {
Thomas Bogendoerfer e2e5bd
 	u8 lan_en;	/* Indicate if packet can be forwarded to the uplink */
Thomas Bogendoerfer e2e5bd
 };
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
+struct ice_adv_lkup_elem {
Thomas Bogendoerfer e2e5bd
+	enum ice_protocol_type type;
Thomas Bogendoerfer e2e5bd
+	union ice_prot_hdr h_u;	/* Header values */
Thomas Bogendoerfer e2e5bd
+	union ice_prot_hdr m_u;	/* Mask of header values to match */
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_sw_act_ctrl {
Thomas Bogendoerfer e2e5bd
+	/* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */
Thomas Bogendoerfer e2e5bd
+	u16 src;
Thomas Bogendoerfer e2e5bd
+	u16 flag;
Thomas Bogendoerfer e2e5bd
+	enum ice_sw_fwd_act_type fltr_act;
Thomas Bogendoerfer e2e5bd
+	/* Depending on filter action */
Thomas Bogendoerfer e2e5bd
+	union {
Thomas Bogendoerfer e2e5bd
+		/* This is a queue ID in case of ICE_FWD_TO_Q and starting
Thomas Bogendoerfer e2e5bd
+		 * queue ID in case of ICE_FWD_TO_QGRP.
Thomas Bogendoerfer e2e5bd
+		 */
Thomas Bogendoerfer e2e5bd
+		u16 q_id:11;
Thomas Bogendoerfer e2e5bd
+		u16 vsi_id:10;
Thomas Bogendoerfer e2e5bd
+		u16 hw_vsi_id:10;
Thomas Bogendoerfer e2e5bd
+		u16 vsi_list_id:10;
Thomas Bogendoerfer e2e5bd
+	} fwd_id;
Thomas Bogendoerfer e2e5bd
+	/* software VSI handle */
Thomas Bogendoerfer e2e5bd
+	u16 vsi_handle;
Thomas Bogendoerfer e2e5bd
+	u8 qgrp_size;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_rule_query_data {
Thomas Bogendoerfer e2e5bd
+	/* Recipe ID for which the requested rule was added */
Thomas Bogendoerfer e2e5bd
+	u16 rid;
Thomas Bogendoerfer e2e5bd
+	/* Rule ID that was added or is supposed to be removed */
Thomas Bogendoerfer e2e5bd
+	u16 rule_id;
Thomas Bogendoerfer e2e5bd
+	/* vsi_handle for which Rule was added or is supposed to be removed */
Thomas Bogendoerfer e2e5bd
+	u16 vsi_handle;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+struct ice_adv_rule_info {
Thomas Bogendoerfer e2e5bd
+	struct ice_sw_act_ctrl sw_act;
Thomas Bogendoerfer e2e5bd
+	u32 priority;
Thomas Bogendoerfer e2e5bd
+	u8 rx; /* true means LOOKUP_RX otherwise LOOKUP_TX */
Thomas Bogendoerfer e2e5bd
+	u16 fltr_rule_id;
Thomas Bogendoerfer e2e5bd
+};
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+/* A collection of one or more four word recipe */
Thomas Bogendoerfer e2e5bd
 struct ice_sw_recipe {
Thomas Bogendoerfer e2e5bd
-	struct list_head l_entry;
Thomas Bogendoerfer e2e5bd
+	/* For a chained recipe the root recipe is what should be used for
Thomas Bogendoerfer e2e5bd
+	 * programming rules
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	u8 is_root;
Thomas Bogendoerfer e2e5bd
+	u8 root_rid;
Thomas Bogendoerfer e2e5bd
+	u8 recp_created;
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
-	/* To protect modification of filt_rule list
Thomas Bogendoerfer e2e5bd
-	 * defined below
Thomas Bogendoerfer e2e5bd
+	/* Number of extraction words */
Thomas Bogendoerfer e2e5bd
+	u8 n_ext_words;
Thomas Bogendoerfer e2e5bd
+	/* Protocol ID and Offset pair (extraction word) to describe the
Thomas Bogendoerfer e2e5bd
+	 * recipe
Thomas Bogendoerfer e2e5bd
 	 */
Thomas Bogendoerfer e2e5bd
-	struct mutex filt_rule_lock;
Thomas Bogendoerfer e2e5bd
+	struct ice_fv_word ext_words[ICE_MAX_CHAIN_WORDS];
Thomas Bogendoerfer e2e5bd
+	u16 word_masks[ICE_MAX_CHAIN_WORDS];
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* if this recipe is a collection of other recipe */
Thomas Bogendoerfer e2e5bd
+	u8 big_recp;
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
-	/* List of type ice_fltr_mgmt_list_entry */
Thomas Bogendoerfer e2e5bd
+	/* if this recipe is part of another bigger recipe then chain index
Thomas Bogendoerfer e2e5bd
+	 * corresponding to this recipe
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	u8 chain_idx;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* if this recipe is a collection of other recipe then count of other
Thomas Bogendoerfer e2e5bd
+	 * recipes and recipe IDs of those recipes
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	u8 n_grp_count;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Bit map specifying the IDs associated with this group of recipe */
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* List of type ice_fltr_mgmt_list_entry or adv_rule */
Thomas Bogendoerfer e2e5bd
+	u8 adv_rule;
Thomas Bogendoerfer e2e5bd
 	struct list_head filt_rules;
Thomas Bogendoerfer e2e5bd
 	struct list_head filt_replay_rules;
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
-	/* linked list of type recipe_list_entry */
Thomas Bogendoerfer e2e5bd
-	struct list_head rg_list;
Thomas Bogendoerfer e2e5bd
-	/* linked list of type ice_sw_fv_list_entry*/
Thomas Bogendoerfer e2e5bd
+	struct mutex filt_rule_lock;	/* protect filter rule structure */
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Profiles this recipe should be associated with */
Thomas Bogendoerfer e2e5bd
 	struct list_head fv_list;
Thomas Bogendoerfer e2e5bd
-	struct ice_aqc_recipe_data_elem *r_buf;
Thomas Bogendoerfer e2e5bd
-	u8 recp_count;
Thomas Bogendoerfer e2e5bd
-	u8 root_rid;
Thomas Bogendoerfer e2e5bd
-	u8 num_profs;
Thomas Bogendoerfer e2e5bd
-	u8 *prof_ids;
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
-	/* recipe bitmap: what all recipes makes this recipe */
Thomas Bogendoerfer e2e5bd
-	DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
Thomas Bogendoerfer e2e5bd
+	/* Profiles this recipe is associated with */
Thomas Bogendoerfer e2e5bd
+	u8 num_profs, *prof_ids;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* Bit map for possible result indexes */
Thomas Bogendoerfer e2e5bd
+	DECLARE_BITMAP(res_idxs, ICE_MAX_FV_WORDS);
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* This allows user to specify the recipe priority.
Thomas Bogendoerfer e2e5bd
+	 * For now, this becomes 'fwd_priority' when recipe
Thomas Bogendoerfer e2e5bd
+	 * is created, usually recipes can have 'fwd' and 'join'
Thomas Bogendoerfer e2e5bd
+	 * priority.
Thomas Bogendoerfer e2e5bd
+	 */
Thomas Bogendoerfer e2e5bd
+	u8 priority;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	struct list_head rg_list;
Thomas Bogendoerfer e2e5bd
+
Thomas Bogendoerfer e2e5bd
+	/* AQ buffer associated with this recipe */
Thomas Bogendoerfer e2e5bd
+	struct ice_aqc_recipe_data_elem *root_buf;
Thomas Bogendoerfer e2e5bd
+	/* This struct saves the fv_words for a given lookup */
Thomas Bogendoerfer e2e5bd
+	struct ice_prot_lkup_ext lkup_exts;
Thomas Bogendoerfer e2e5bd
 };
Thomas Bogendoerfer e2e5bd
 
Thomas Bogendoerfer e2e5bd
 /* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list ID */