xref: /freebsd-src/sys/dev/ice/ice_switch.c (revision f377a0c7dfa97035844e58c2aec810001bebce17)
171d10453SEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2015f8cc5SEric Joyner /*  Copyright (c) 2024, Intel Corporation
371d10453SEric Joyner  *  All rights reserved.
471d10453SEric Joyner  *
571d10453SEric Joyner  *  Redistribution and use in source and binary forms, with or without
671d10453SEric Joyner  *  modification, are permitted provided that the following conditions are met:
771d10453SEric Joyner  *
871d10453SEric Joyner  *   1. Redistributions of source code must retain the above copyright notice,
971d10453SEric Joyner  *      this list of conditions and the following disclaimer.
1071d10453SEric Joyner  *
1171d10453SEric Joyner  *   2. Redistributions in binary form must reproduce the above copyright
1271d10453SEric Joyner  *      notice, this list of conditions and the following disclaimer in the
1371d10453SEric Joyner  *      documentation and/or other materials provided with the distribution.
1471d10453SEric Joyner  *
1571d10453SEric Joyner  *   3. Neither the name of the Intel Corporation nor the names of its
1671d10453SEric Joyner  *      contributors may be used to endorse or promote products derived from
1771d10453SEric Joyner  *      this software without specific prior written permission.
1871d10453SEric Joyner  *
1971d10453SEric Joyner  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2071d10453SEric Joyner  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2171d10453SEric Joyner  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2271d10453SEric Joyner  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2371d10453SEric Joyner  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2471d10453SEric Joyner  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2571d10453SEric Joyner  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2671d10453SEric Joyner  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2771d10453SEric Joyner  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2871d10453SEric Joyner  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2971d10453SEric Joyner  *  POSSIBILITY OF SUCH DAMAGE.
3071d10453SEric Joyner  */
3171d10453SEric Joyner 
328923de59SPiotr Kubaj #include "ice_common.h"
3371d10453SEric Joyner #include "ice_switch.h"
3471d10453SEric Joyner #include "ice_flex_type.h"
3571d10453SEric Joyner #include "ice_flow.h"
3671d10453SEric Joyner 
3771d10453SEric Joyner #define ICE_ETH_DA_OFFSET		0
3871d10453SEric Joyner #define ICE_ETH_ETHTYPE_OFFSET		12
3971d10453SEric Joyner #define ICE_ETH_VLAN_TCI_OFFSET		14
4071d10453SEric Joyner #define ICE_MAX_VLAN_ID			0xFFF
4156429daeSEric Joyner #define ICE_IPV6_ETHER_ID		0x86DD
428923de59SPiotr Kubaj #define ICE_PPP_IPV6_PROTO_ID		0x0057
439cf1841cSEric Joyner #define ICE_ETH_P_8021Q			0x8100
4471d10453SEric Joyner 
459c30461dSEric Joyner /* Dummy ethernet header needed in the ice_sw_rule_*
4671d10453SEric Joyner  * struct to configure any switch filter rules.
4771d10453SEric Joyner  * {DA (6 bytes), SA(6 bytes),
4871d10453SEric Joyner  * Ether type (2 bytes for header without VLAN tag) OR
4971d10453SEric Joyner  * VLAN tag (4 bytes for header with VLAN tag) }
5071d10453SEric Joyner  *
5171d10453SEric Joyner  * Word on Hardcoded values
5271d10453SEric Joyner  * byte 0 = 0x2: to identify it as locally administered DA MAC
5371d10453SEric Joyner  * byte 6 = 0x2: to identify it as locally administered SA MAC
5471d10453SEric Joyner  * byte 12 = 0x81 & byte 13 = 0x00:
5571d10453SEric Joyner  *	In case of VLAN filter first two bytes defines ether type (0x8100)
5671d10453SEric Joyner  *	and remaining two bytes are placeholder for programming a given VLAN ID
5771d10453SEric Joyner  *	In case of Ether type filter it is treated as header without VLAN tag
5871d10453SEric Joyner  *	and byte 12 and 13 is used to program a given Ether type instead
5971d10453SEric Joyner  */
6071d10453SEric Joyner static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
6171d10453SEric Joyner 							0x2, 0, 0, 0, 0, 0,
6271d10453SEric Joyner 							0x81, 0, 0, 0};
6371d10453SEric Joyner 
648923de59SPiotr Kubaj static bool
658923de59SPiotr Kubaj ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle);
668923de59SPiotr Kubaj 
6771d10453SEric Joyner /**
6871d10453SEric Joyner  * ice_init_def_sw_recp - initialize the recipe book keeping tables
6971d10453SEric Joyner  * @hw: pointer to the HW struct
7071d10453SEric Joyner  * @recp_list: pointer to sw recipe list
7171d10453SEric Joyner  *
7271d10453SEric Joyner  * Allocate memory for the entire recipe table and initialize the structures/
7371d10453SEric Joyner  * entries corresponding to basic recipes.
7471d10453SEric Joyner  */
75*f2635e84SEric Joyner int
7671d10453SEric Joyner ice_init_def_sw_recp(struct ice_hw *hw, struct ice_sw_recipe **recp_list)
7771d10453SEric Joyner {
7871d10453SEric Joyner 	struct ice_sw_recipe *recps;
7971d10453SEric Joyner 	u8 i;
8071d10453SEric Joyner 
8171d10453SEric Joyner 	recps = (struct ice_sw_recipe *)
8271d10453SEric Joyner 		ice_calloc(hw, ICE_MAX_NUM_RECIPES, sizeof(*recps));
8371d10453SEric Joyner 	if (!recps)
8471d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
8571d10453SEric Joyner 
8671d10453SEric Joyner 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
8771d10453SEric Joyner 		recps[i].root_rid = i;
8871d10453SEric Joyner 		INIT_LIST_HEAD(&recps[i].filt_rules);
8971d10453SEric Joyner 		INIT_LIST_HEAD(&recps[i].filt_replay_rules);
9071d10453SEric Joyner 		INIT_LIST_HEAD(&recps[i].rg_list);
9171d10453SEric Joyner 		ice_init_lock(&recps[i].filt_rule_lock);
9271d10453SEric Joyner 	}
9371d10453SEric Joyner 
9471d10453SEric Joyner 	*recp_list = recps;
9571d10453SEric Joyner 
96*f2635e84SEric Joyner 	return 0;
9771d10453SEric Joyner }
9871d10453SEric Joyner 
9971d10453SEric Joyner /**
10071d10453SEric Joyner  * ice_aq_get_sw_cfg - get switch configuration
10171d10453SEric Joyner  * @hw: pointer to the hardware structure
10271d10453SEric Joyner  * @buf: pointer to the result buffer
10371d10453SEric Joyner  * @buf_size: length of the buffer available for response
10471d10453SEric Joyner  * @req_desc: pointer to requested descriptor
10571d10453SEric Joyner  * @num_elems: pointer to number of elements
10671d10453SEric Joyner  * @cd: pointer to command details structure or NULL
10771d10453SEric Joyner  *
1087d7af7f8SEric Joyner  * Get switch configuration (0x0200) to be placed in buf.
10971d10453SEric Joyner  * This admin command returns information such as initial VSI/port number
11071d10453SEric Joyner  * and switch ID it belongs to.
11171d10453SEric Joyner  *
11271d10453SEric Joyner  * NOTE: *req_desc is both an input/output parameter.
11371d10453SEric Joyner  * The caller of this function first calls this function with *request_desc set
11471d10453SEric Joyner  * to 0. If the response from f/w has *req_desc set to 0, all the switch
11571d10453SEric Joyner  * configuration information has been returned; if non-zero (meaning not all
11671d10453SEric Joyner  * the information was returned), the caller should call this function again
11771d10453SEric Joyner  * with *req_desc set to the previous value returned by f/w to get the
11871d10453SEric Joyner  * next block of switch configuration information.
11971d10453SEric Joyner  *
12071d10453SEric Joyner  * *num_elems is output only parameter. This reflects the number of elements
12171d10453SEric Joyner  * in response buffer. The caller of this function to use *num_elems while
12271d10453SEric Joyner  * parsing the response buffer.
12371d10453SEric Joyner  */
124*f2635e84SEric Joyner static int
1257d7af7f8SEric Joyner ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf,
12671d10453SEric Joyner 		  u16 buf_size, u16 *req_desc, u16 *num_elems,
12771d10453SEric Joyner 		  struct ice_sq_cd *cd)
12871d10453SEric Joyner {
12971d10453SEric Joyner 	struct ice_aqc_get_sw_cfg *cmd;
13071d10453SEric Joyner 	struct ice_aq_desc desc;
131*f2635e84SEric Joyner 	int status;
13271d10453SEric Joyner 
13371d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg);
13471d10453SEric Joyner 	cmd = &desc.params.get_sw_conf;
13571d10453SEric Joyner 	cmd->element = CPU_TO_LE16(*req_desc);
13671d10453SEric Joyner 
13771d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
13871d10453SEric Joyner 	if (!status) {
13971d10453SEric Joyner 		*req_desc = LE16_TO_CPU(cmd->element);
14071d10453SEric Joyner 		*num_elems = LE16_TO_CPU(cmd->num_elems);
14171d10453SEric Joyner 	}
14271d10453SEric Joyner 
14371d10453SEric Joyner 	return status;
14471d10453SEric Joyner }
14571d10453SEric Joyner 
14671d10453SEric Joyner /**
147d08b8680SEric Joyner  * ice_alloc_rss_global_lut - allocate a RSS global LUT
148d08b8680SEric Joyner  * @hw: pointer to the HW struct
149d08b8680SEric Joyner  * @shared_res: true to allocate as a shared resource and false to allocate as a dedicated resource
150d08b8680SEric Joyner  * @global_lut_id: output parameter for the RSS global LUT's ID
151d08b8680SEric Joyner  */
152*f2635e84SEric Joyner int ice_alloc_rss_global_lut(struct ice_hw *hw, bool shared_res, u16 *global_lut_id)
153d08b8680SEric Joyner {
154d08b8680SEric Joyner 	struct ice_aqc_alloc_free_res_elem *sw_buf;
155*f2635e84SEric Joyner 	int status;
156d08b8680SEric Joyner 	u16 buf_len;
157d08b8680SEric Joyner 
158d08b8680SEric Joyner 	buf_len = ice_struct_size(sw_buf, elem, 1);
159d08b8680SEric Joyner 	sw_buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
160d08b8680SEric Joyner 	if (!sw_buf)
161d08b8680SEric Joyner 		return ICE_ERR_NO_MEMORY;
162d08b8680SEric Joyner 
163d08b8680SEric Joyner 	sw_buf->num_elems = CPU_TO_LE16(1);
164d08b8680SEric Joyner 	sw_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH |
165d08b8680SEric Joyner 				       (shared_res ? ICE_AQC_RES_TYPE_FLAG_SHARED :
166d08b8680SEric Joyner 				       ICE_AQC_RES_TYPE_FLAG_DEDICATED));
167d08b8680SEric Joyner 
168d08b8680SEric Joyner 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, ice_aqc_opc_alloc_res, NULL);
169d08b8680SEric Joyner 	if (status) {
170d08b8680SEric Joyner 		ice_debug(hw, ICE_DBG_RES, "Failed to allocate %s RSS global LUT, status %d\n",
171d08b8680SEric Joyner 			  shared_res ? "shared" : "dedicated", status);
172d08b8680SEric Joyner 		goto ice_alloc_global_lut_exit;
173d08b8680SEric Joyner 	}
174d08b8680SEric Joyner 
175d08b8680SEric Joyner 	*global_lut_id = LE16_TO_CPU(sw_buf->elem[0].e.sw_resp);
176d08b8680SEric Joyner 
177d08b8680SEric Joyner ice_alloc_global_lut_exit:
178d08b8680SEric Joyner 	ice_free(hw, sw_buf);
179d08b8680SEric Joyner 	return status;
180d08b8680SEric Joyner }
181d08b8680SEric Joyner 
182d08b8680SEric Joyner /**
18356429daeSEric Joyner  * ice_free_rss_global_lut - free a RSS global LUT
184d08b8680SEric Joyner  * @hw: pointer to the HW struct
185d08b8680SEric Joyner  * @global_lut_id: ID of the RSS global LUT to free
186d08b8680SEric Joyner  */
187*f2635e84SEric Joyner int ice_free_rss_global_lut(struct ice_hw *hw, u16 global_lut_id)
188d08b8680SEric Joyner {
189d08b8680SEric Joyner 	struct ice_aqc_alloc_free_res_elem *sw_buf;
190d08b8680SEric Joyner 	u16 buf_len, num_elems = 1;
191*f2635e84SEric Joyner 	int status;
192d08b8680SEric Joyner 
193d08b8680SEric Joyner 	buf_len = ice_struct_size(sw_buf, elem, num_elems);
194d08b8680SEric Joyner 	sw_buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
195d08b8680SEric Joyner 	if (!sw_buf)
196d08b8680SEric Joyner 		return ICE_ERR_NO_MEMORY;
197d08b8680SEric Joyner 
198d08b8680SEric Joyner 	sw_buf->num_elems = CPU_TO_LE16(num_elems);
199d08b8680SEric Joyner 	sw_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_GLOBAL_RSS_HASH);
200d08b8680SEric Joyner 	sw_buf->elem[0].e.sw_resp = CPU_TO_LE16(global_lut_id);
201d08b8680SEric Joyner 
202d08b8680SEric Joyner 	status = ice_aq_alloc_free_res(hw, num_elems, sw_buf, buf_len, ice_aqc_opc_free_res, NULL);
203d08b8680SEric Joyner 	if (status)
204d08b8680SEric Joyner 		ice_debug(hw, ICE_DBG_RES, "Failed to free RSS global LUT %d, status %d\n",
205d08b8680SEric Joyner 			  global_lut_id, status);
206d08b8680SEric Joyner 
207d08b8680SEric Joyner 	ice_free(hw, sw_buf);
208d08b8680SEric Joyner 	return status;
209d08b8680SEric Joyner }
210d08b8680SEric Joyner 
211d08b8680SEric Joyner /**
21271d10453SEric Joyner  * ice_alloc_sw - allocate resources specific to switch
21371d10453SEric Joyner  * @hw: pointer to the HW struct
21471d10453SEric Joyner  * @ena_stats: true to turn on VEB stats
21571d10453SEric Joyner  * @shared_res: true for shared resource, false for dedicated resource
21671d10453SEric Joyner  * @sw_id: switch ID returned
21771d10453SEric Joyner  * @counter_id: VEB counter ID returned
21871d10453SEric Joyner  *
21971d10453SEric Joyner  * allocates switch resources (SWID and VEB counter) (0x0208)
22071d10453SEric Joyner  */
221*f2635e84SEric Joyner int
22271d10453SEric Joyner ice_alloc_sw(struct ice_hw *hw, bool ena_stats, bool shared_res, u16 *sw_id,
22371d10453SEric Joyner 	     u16 *counter_id)
22471d10453SEric Joyner {
22571d10453SEric Joyner 	struct ice_aqc_alloc_free_res_elem *sw_buf;
22671d10453SEric Joyner 	struct ice_aqc_res_elem *sw_ele;
22771d10453SEric Joyner 	u16 buf_len;
228*f2635e84SEric Joyner 	int status;
22971d10453SEric Joyner 
2307d7af7f8SEric Joyner 	buf_len = ice_struct_size(sw_buf, elem, 1);
2317d7af7f8SEric Joyner 	sw_buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
23271d10453SEric Joyner 	if (!sw_buf)
23371d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
23471d10453SEric Joyner 
23571d10453SEric Joyner 	/* Prepare buffer for switch ID.
23671d10453SEric Joyner 	 * The number of resource entries in buffer is passed as 1 since only a
23771d10453SEric Joyner 	 * single switch/VEB instance is allocated, and hence a single sw_id
23871d10453SEric Joyner 	 * is requested.
23971d10453SEric Joyner 	 */
24071d10453SEric Joyner 	sw_buf->num_elems = CPU_TO_LE16(1);
24171d10453SEric Joyner 	sw_buf->res_type =
24271d10453SEric Joyner 		CPU_TO_LE16(ICE_AQC_RES_TYPE_SWID |
24371d10453SEric Joyner 			    (shared_res ? ICE_AQC_RES_TYPE_FLAG_SHARED :
24471d10453SEric Joyner 			    ICE_AQC_RES_TYPE_FLAG_DEDICATED));
24571d10453SEric Joyner 
24671d10453SEric Joyner 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len,
24771d10453SEric Joyner 				       ice_aqc_opc_alloc_res, NULL);
24871d10453SEric Joyner 
24971d10453SEric Joyner 	if (status)
25071d10453SEric Joyner 		goto ice_alloc_sw_exit;
25171d10453SEric Joyner 
25271d10453SEric Joyner 	sw_ele = &sw_buf->elem[0];
25371d10453SEric Joyner 	*sw_id = LE16_TO_CPU(sw_ele->e.sw_resp);
25471d10453SEric Joyner 
25571d10453SEric Joyner 	if (ena_stats) {
25671d10453SEric Joyner 		/* Prepare buffer for VEB Counter */
25771d10453SEric Joyner 		enum ice_adminq_opc opc = ice_aqc_opc_alloc_res;
25871d10453SEric Joyner 		struct ice_aqc_alloc_free_res_elem *counter_buf;
25971d10453SEric Joyner 		struct ice_aqc_res_elem *counter_ele;
26071d10453SEric Joyner 
26171d10453SEric Joyner 		counter_buf = (struct ice_aqc_alloc_free_res_elem *)
26271d10453SEric Joyner 				ice_malloc(hw, buf_len);
26371d10453SEric Joyner 		if (!counter_buf) {
26471d10453SEric Joyner 			status = ICE_ERR_NO_MEMORY;
26571d10453SEric Joyner 			goto ice_alloc_sw_exit;
26671d10453SEric Joyner 		}
26771d10453SEric Joyner 
26871d10453SEric Joyner 		/* The number of resource entries in buffer is passed as 1 since
26971d10453SEric Joyner 		 * only a single switch/VEB instance is allocated, and hence a
27071d10453SEric Joyner 		 * single VEB counter is requested.
27171d10453SEric Joyner 		 */
27271d10453SEric Joyner 		counter_buf->num_elems = CPU_TO_LE16(1);
27371d10453SEric Joyner 		counter_buf->res_type =
27471d10453SEric Joyner 			CPU_TO_LE16(ICE_AQC_RES_TYPE_VEB_COUNTER |
27571d10453SEric Joyner 				    ICE_AQC_RES_TYPE_FLAG_DEDICATED);
27671d10453SEric Joyner 		status = ice_aq_alloc_free_res(hw, 1, counter_buf, buf_len,
27771d10453SEric Joyner 					       opc, NULL);
27871d10453SEric Joyner 
27971d10453SEric Joyner 		if (status) {
28071d10453SEric Joyner 			ice_free(hw, counter_buf);
28171d10453SEric Joyner 			goto ice_alloc_sw_exit;
28271d10453SEric Joyner 		}
28371d10453SEric Joyner 		counter_ele = &counter_buf->elem[0];
28471d10453SEric Joyner 		*counter_id = LE16_TO_CPU(counter_ele->e.sw_resp);
28571d10453SEric Joyner 		ice_free(hw, counter_buf);
28671d10453SEric Joyner 	}
28771d10453SEric Joyner 
28871d10453SEric Joyner ice_alloc_sw_exit:
28971d10453SEric Joyner 	ice_free(hw, sw_buf);
29071d10453SEric Joyner 	return status;
29171d10453SEric Joyner }
29271d10453SEric Joyner 
29371d10453SEric Joyner /**
29471d10453SEric Joyner  * ice_free_sw - free resources specific to switch
29571d10453SEric Joyner  * @hw: pointer to the HW struct
29671d10453SEric Joyner  * @sw_id: switch ID returned
29771d10453SEric Joyner  * @counter_id: VEB counter ID returned
29871d10453SEric Joyner  *
29971d10453SEric Joyner  * free switch resources (SWID and VEB counter) (0x0209)
30071d10453SEric Joyner  *
30171d10453SEric Joyner  * NOTE: This function frees multiple resources. It continues
30271d10453SEric Joyner  * releasing other resources even after it encounters error.
30371d10453SEric Joyner  * The error code returned is the last error it encountered.
30471d10453SEric Joyner  */
305*f2635e84SEric Joyner int ice_free_sw(struct ice_hw *hw, u16 sw_id, u16 counter_id)
30671d10453SEric Joyner {
30771d10453SEric Joyner 	struct ice_aqc_alloc_free_res_elem *sw_buf, *counter_buf;
308*f2635e84SEric Joyner 	int status, ret_status;
30971d10453SEric Joyner 	u16 buf_len;
31071d10453SEric Joyner 
3117d7af7f8SEric Joyner 	buf_len = ice_struct_size(sw_buf, elem, 1);
3127d7af7f8SEric Joyner 	sw_buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
31371d10453SEric Joyner 	if (!sw_buf)
31471d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
31571d10453SEric Joyner 
31671d10453SEric Joyner 	/* Prepare buffer to free for switch ID res.
31771d10453SEric Joyner 	 * The number of resource entries in buffer is passed as 1 since only a
31871d10453SEric Joyner 	 * single switch/VEB instance is freed, and hence a single sw_id
31971d10453SEric Joyner 	 * is released.
32071d10453SEric Joyner 	 */
32171d10453SEric Joyner 	sw_buf->num_elems = CPU_TO_LE16(1);
32271d10453SEric Joyner 	sw_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_SWID);
32371d10453SEric Joyner 	sw_buf->elem[0].e.sw_resp = CPU_TO_LE16(sw_id);
32471d10453SEric Joyner 
32571d10453SEric Joyner 	ret_status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len,
32671d10453SEric Joyner 					   ice_aqc_opc_free_res, NULL);
32771d10453SEric Joyner 
32871d10453SEric Joyner 	if (ret_status)
32971d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SW, "CQ CMD Buffer:\n");
33071d10453SEric Joyner 
33171d10453SEric Joyner 	/* Prepare buffer to free for VEB Counter resource */
33271d10453SEric Joyner 	counter_buf = (struct ice_aqc_alloc_free_res_elem *)
33371d10453SEric Joyner 			ice_malloc(hw, buf_len);
33471d10453SEric Joyner 	if (!counter_buf) {
33571d10453SEric Joyner 		ice_free(hw, sw_buf);
33671d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
33771d10453SEric Joyner 	}
33871d10453SEric Joyner 
33971d10453SEric Joyner 	/* The number of resource entries in buffer is passed as 1 since only a
34071d10453SEric Joyner 	 * single switch/VEB instance is freed, and hence a single VEB counter
34171d10453SEric Joyner 	 * is released
34271d10453SEric Joyner 	 */
34371d10453SEric Joyner 	counter_buf->num_elems = CPU_TO_LE16(1);
34471d10453SEric Joyner 	counter_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_VEB_COUNTER);
34571d10453SEric Joyner 	counter_buf->elem[0].e.sw_resp = CPU_TO_LE16(counter_id);
34671d10453SEric Joyner 
34771d10453SEric Joyner 	status = ice_aq_alloc_free_res(hw, 1, counter_buf, buf_len,
34871d10453SEric Joyner 				       ice_aqc_opc_free_res, NULL);
34971d10453SEric Joyner 	if (status) {
3507d7af7f8SEric Joyner 		ice_debug(hw, ICE_DBG_SW, "VEB counter resource could not be freed\n");
35171d10453SEric Joyner 		ret_status = status;
35271d10453SEric Joyner 	}
35371d10453SEric Joyner 
35471d10453SEric Joyner 	ice_free(hw, counter_buf);
35571d10453SEric Joyner 	ice_free(hw, sw_buf);
35671d10453SEric Joyner 	return ret_status;
35771d10453SEric Joyner }
35871d10453SEric Joyner 
35971d10453SEric Joyner /**
36071d10453SEric Joyner  * ice_aq_add_vsi
36171d10453SEric Joyner  * @hw: pointer to the HW struct
36271d10453SEric Joyner  * @vsi_ctx: pointer to a VSI context struct
36371d10453SEric Joyner  * @cd: pointer to command details structure or NULL
36471d10453SEric Joyner  *
36571d10453SEric Joyner  * Add a VSI context to the hardware (0x0210)
36671d10453SEric Joyner  */
367*f2635e84SEric Joyner int
36871d10453SEric Joyner ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
36971d10453SEric Joyner 	       struct ice_sq_cd *cd)
37071d10453SEric Joyner {
37171d10453SEric Joyner 	struct ice_aqc_add_update_free_vsi_resp *res;
37271d10453SEric Joyner 	struct ice_aqc_add_get_update_free_vsi *cmd;
37371d10453SEric Joyner 	struct ice_aq_desc desc;
374*f2635e84SEric Joyner 	int status;
37571d10453SEric Joyner 
37671d10453SEric Joyner 	cmd = &desc.params.vsi_cmd;
37771d10453SEric Joyner 	res = &desc.params.add_update_free_vsi_res;
37871d10453SEric Joyner 
37971d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);
38071d10453SEric Joyner 
38171d10453SEric Joyner 	if (!vsi_ctx->alloc_from_pool)
38271d10453SEric Joyner 		cmd->vsi_num = CPU_TO_LE16(vsi_ctx->vsi_num |
38371d10453SEric Joyner 					   ICE_AQ_VSI_IS_VALID);
38471d10453SEric Joyner 	cmd->vf_id = vsi_ctx->vf_num;
38571d10453SEric Joyner 
38671d10453SEric Joyner 	cmd->vsi_flags = CPU_TO_LE16(vsi_ctx->flags);
38771d10453SEric Joyner 
38871d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
38971d10453SEric Joyner 
39071d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
39171d10453SEric Joyner 				 sizeof(vsi_ctx->info), cd);
39271d10453SEric Joyner 
39371d10453SEric Joyner 	if (!status) {
39471d10453SEric Joyner 		vsi_ctx->vsi_num = LE16_TO_CPU(res->vsi_num) & ICE_AQ_VSI_NUM_M;
39571d10453SEric Joyner 		vsi_ctx->vsis_allocd = LE16_TO_CPU(res->vsi_used);
39671d10453SEric Joyner 		vsi_ctx->vsis_unallocated = LE16_TO_CPU(res->vsi_free);
39771d10453SEric Joyner 	}
39871d10453SEric Joyner 
39971d10453SEric Joyner 	return status;
40071d10453SEric Joyner }
40171d10453SEric Joyner 
40271d10453SEric Joyner /**
40371d10453SEric Joyner  * ice_aq_free_vsi
40471d10453SEric Joyner  * @hw: pointer to the HW struct
40571d10453SEric Joyner  * @vsi_ctx: pointer to a VSI context struct
40671d10453SEric Joyner  * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
40771d10453SEric Joyner  * @cd: pointer to command details structure or NULL
40871d10453SEric Joyner  *
40971d10453SEric Joyner  * Free VSI context info from hardware (0x0213)
41071d10453SEric Joyner  */
411*f2635e84SEric Joyner int
41271d10453SEric Joyner ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
41371d10453SEric Joyner 		bool keep_vsi_alloc, struct ice_sq_cd *cd)
41471d10453SEric Joyner {
41571d10453SEric Joyner 	struct ice_aqc_add_update_free_vsi_resp *resp;
41671d10453SEric Joyner 	struct ice_aqc_add_get_update_free_vsi *cmd;
41771d10453SEric Joyner 	struct ice_aq_desc desc;
418*f2635e84SEric Joyner 	int status;
41971d10453SEric Joyner 
42071d10453SEric Joyner 	cmd = &desc.params.vsi_cmd;
42171d10453SEric Joyner 	resp = &desc.params.add_update_free_vsi_res;
42271d10453SEric Joyner 
42371d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);
42471d10453SEric Joyner 
42571d10453SEric Joyner 	cmd->vsi_num = CPU_TO_LE16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
42671d10453SEric Joyner 	if (keep_vsi_alloc)
42771d10453SEric Joyner 		cmd->cmd_flags = CPU_TO_LE16(ICE_AQ_VSI_KEEP_ALLOC);
42871d10453SEric Joyner 
42971d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
43071d10453SEric Joyner 	if (!status) {
43171d10453SEric Joyner 		vsi_ctx->vsis_allocd = LE16_TO_CPU(resp->vsi_used);
43271d10453SEric Joyner 		vsi_ctx->vsis_unallocated = LE16_TO_CPU(resp->vsi_free);
43371d10453SEric Joyner 	}
43471d10453SEric Joyner 
43571d10453SEric Joyner 	return status;
43671d10453SEric Joyner }
43771d10453SEric Joyner 
43871d10453SEric Joyner /**
43971d10453SEric Joyner  * ice_aq_update_vsi
44071d10453SEric Joyner  * @hw: pointer to the HW struct
44171d10453SEric Joyner  * @vsi_ctx: pointer to a VSI context struct
44271d10453SEric Joyner  * @cd: pointer to command details structure or NULL
44371d10453SEric Joyner  *
44471d10453SEric Joyner  * Update VSI context in the hardware (0x0211)
44571d10453SEric Joyner  */
446*f2635e84SEric Joyner int
44771d10453SEric Joyner ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
44871d10453SEric Joyner 		  struct ice_sq_cd *cd)
44971d10453SEric Joyner {
45071d10453SEric Joyner 	struct ice_aqc_add_update_free_vsi_resp *resp;
45171d10453SEric Joyner 	struct ice_aqc_add_get_update_free_vsi *cmd;
45271d10453SEric Joyner 	struct ice_aq_desc desc;
453*f2635e84SEric Joyner 	int status;
45471d10453SEric Joyner 
45571d10453SEric Joyner 	cmd = &desc.params.vsi_cmd;
45671d10453SEric Joyner 	resp = &desc.params.add_update_free_vsi_res;
45771d10453SEric Joyner 
45871d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);
45971d10453SEric Joyner 
46071d10453SEric Joyner 	cmd->vsi_num = CPU_TO_LE16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
46171d10453SEric Joyner 
46271d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
46371d10453SEric Joyner 
46471d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
46571d10453SEric Joyner 				 sizeof(vsi_ctx->info), cd);
46671d10453SEric Joyner 
46771d10453SEric Joyner 	if (!status) {
46871d10453SEric Joyner 		vsi_ctx->vsis_allocd = LE16_TO_CPU(resp->vsi_used);
46971d10453SEric Joyner 		vsi_ctx->vsis_unallocated = LE16_TO_CPU(resp->vsi_free);
47071d10453SEric Joyner 	}
47171d10453SEric Joyner 
47271d10453SEric Joyner 	return status;
47371d10453SEric Joyner }
47471d10453SEric Joyner 
47571d10453SEric Joyner /**
47671d10453SEric Joyner  * ice_is_vsi_valid - check whether the VSI is valid or not
47771d10453SEric Joyner  * @hw: pointer to the HW struct
47871d10453SEric Joyner  * @vsi_handle: VSI handle
47971d10453SEric Joyner  *
48071d10453SEric Joyner  * check whether the VSI is valid or not
48171d10453SEric Joyner  */
48271d10453SEric Joyner bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)
48371d10453SEric Joyner {
48471d10453SEric Joyner 	return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];
48571d10453SEric Joyner }
48671d10453SEric Joyner 
48771d10453SEric Joyner /**
48871d10453SEric Joyner  * ice_get_hw_vsi_num - return the HW VSI number
48971d10453SEric Joyner  * @hw: pointer to the HW struct
49071d10453SEric Joyner  * @vsi_handle: VSI handle
49171d10453SEric Joyner  *
49271d10453SEric Joyner  * return the HW VSI number
49371d10453SEric Joyner  * Caution: call this function only if VSI is valid (ice_is_vsi_valid)
49471d10453SEric Joyner  */
49571d10453SEric Joyner u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)
49671d10453SEric Joyner {
49771d10453SEric Joyner 	return hw->vsi_ctx[vsi_handle]->vsi_num;
49871d10453SEric Joyner }
49971d10453SEric Joyner 
50071d10453SEric Joyner /**
50171d10453SEric Joyner  * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle
50271d10453SEric Joyner  * @hw: pointer to the HW struct
50371d10453SEric Joyner  * @vsi_handle: VSI handle
50471d10453SEric Joyner  *
50571d10453SEric Joyner  * return the VSI context entry for a given VSI handle
50671d10453SEric Joyner  */
50771d10453SEric Joyner struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
50871d10453SEric Joyner {
50971d10453SEric Joyner 	return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];
51071d10453SEric Joyner }
51171d10453SEric Joyner 
51271d10453SEric Joyner /**
51371d10453SEric Joyner  * ice_save_vsi_ctx - save the VSI context for a given VSI handle
51471d10453SEric Joyner  * @hw: pointer to the HW struct
51571d10453SEric Joyner  * @vsi_handle: VSI handle
51671d10453SEric Joyner  * @vsi: VSI context pointer
51771d10453SEric Joyner  *
51871d10453SEric Joyner  * save the VSI context entry for a given VSI handle
51971d10453SEric Joyner  */
52071d10453SEric Joyner static void
52171d10453SEric Joyner ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi)
52271d10453SEric Joyner {
52371d10453SEric Joyner 	hw->vsi_ctx[vsi_handle] = vsi;
52471d10453SEric Joyner }
52571d10453SEric Joyner 
52671d10453SEric Joyner /**
52771d10453SEric Joyner  * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs
52871d10453SEric Joyner  * @hw: pointer to the HW struct
52971d10453SEric Joyner  * @vsi_handle: VSI handle
53071d10453SEric Joyner  */
531*f2635e84SEric Joyner void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle)
53271d10453SEric Joyner {
53371d10453SEric Joyner 	struct ice_vsi_ctx *vsi;
53471d10453SEric Joyner 	u8 i;
53571d10453SEric Joyner 
53671d10453SEric Joyner 	vsi = ice_get_vsi_ctx(hw, vsi_handle);
53771d10453SEric Joyner 	if (!vsi)
53871d10453SEric Joyner 		return;
53971d10453SEric Joyner 	ice_for_each_traffic_class(i) {
54071d10453SEric Joyner 		if (vsi->lan_q_ctx[i]) {
54171d10453SEric Joyner 			ice_free(hw, vsi->lan_q_ctx[i]);
54271d10453SEric Joyner 			vsi->lan_q_ctx[i] = NULL;
54371d10453SEric Joyner 		}
5448a13362dSEric Joyner 		if (vsi->rdma_q_ctx[i]) {
5458a13362dSEric Joyner 			ice_free(hw, vsi->rdma_q_ctx[i]);
5468a13362dSEric Joyner 			vsi->rdma_q_ctx[i] = NULL;
5478a13362dSEric Joyner 		}
54871d10453SEric Joyner 	}
54971d10453SEric Joyner }
55071d10453SEric Joyner 
55171d10453SEric Joyner /**
55271d10453SEric Joyner  * ice_clear_vsi_ctx - clear the VSI context entry
55371d10453SEric Joyner  * @hw: pointer to the HW struct
55471d10453SEric Joyner  * @vsi_handle: VSI handle
55571d10453SEric Joyner  *
55671d10453SEric Joyner  * clear the VSI context entry
55771d10453SEric Joyner  */
55871d10453SEric Joyner static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
55971d10453SEric Joyner {
56071d10453SEric Joyner 	struct ice_vsi_ctx *vsi;
56171d10453SEric Joyner 
56271d10453SEric Joyner 	vsi = ice_get_vsi_ctx(hw, vsi_handle);
56371d10453SEric Joyner 	if (vsi) {
56471d10453SEric Joyner 		ice_clear_vsi_q_ctx(hw, vsi_handle);
56571d10453SEric Joyner 		ice_free(hw, vsi);
56671d10453SEric Joyner 		hw->vsi_ctx[vsi_handle] = NULL;
56771d10453SEric Joyner 	}
56871d10453SEric Joyner }
56971d10453SEric Joyner 
57071d10453SEric Joyner /**
57171d10453SEric Joyner  * ice_clear_all_vsi_ctx - clear all the VSI context entries
57271d10453SEric Joyner  * @hw: pointer to the HW struct
57371d10453SEric Joyner  */
57471d10453SEric Joyner void ice_clear_all_vsi_ctx(struct ice_hw *hw)
57571d10453SEric Joyner {
57671d10453SEric Joyner 	u16 i;
57771d10453SEric Joyner 
57871d10453SEric Joyner 	for (i = 0; i < ICE_MAX_VSI; i++)
57971d10453SEric Joyner 		ice_clear_vsi_ctx(hw, i);
58071d10453SEric Joyner }
58171d10453SEric Joyner 
58271d10453SEric Joyner /**
58371d10453SEric Joyner  * ice_add_vsi - add VSI context to the hardware and VSI handle list
58471d10453SEric Joyner  * @hw: pointer to the HW struct
58571d10453SEric Joyner  * @vsi_handle: unique VSI handle provided by drivers
58671d10453SEric Joyner  * @vsi_ctx: pointer to a VSI context struct
58771d10453SEric Joyner  * @cd: pointer to command details structure or NULL
58871d10453SEric Joyner  *
58971d10453SEric Joyner  * Add a VSI context to the hardware also add it into the VSI handle list.
59071d10453SEric Joyner  * If this function gets called after reset for existing VSIs then update
59171d10453SEric Joyner  * with the new HW VSI number in the corresponding VSI handle list entry.
59271d10453SEric Joyner  */
593*f2635e84SEric Joyner int
59471d10453SEric Joyner ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
59571d10453SEric Joyner 	    struct ice_sq_cd *cd)
59671d10453SEric Joyner {
59771d10453SEric Joyner 	struct ice_vsi_ctx *tmp_vsi_ctx;
598*f2635e84SEric Joyner 	int status;
59971d10453SEric Joyner 
60071d10453SEric Joyner 	if (vsi_handle >= ICE_MAX_VSI)
60171d10453SEric Joyner 		return ICE_ERR_PARAM;
60271d10453SEric Joyner 	status = ice_aq_add_vsi(hw, vsi_ctx, cd);
60371d10453SEric Joyner 	if (status)
60471d10453SEric Joyner 		return status;
60571d10453SEric Joyner 	tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
60671d10453SEric Joyner 	if (!tmp_vsi_ctx) {
60771d10453SEric Joyner 		/* Create a new VSI context */
60871d10453SEric Joyner 		tmp_vsi_ctx = (struct ice_vsi_ctx *)
60971d10453SEric Joyner 			ice_malloc(hw, sizeof(*tmp_vsi_ctx));
61071d10453SEric Joyner 		if (!tmp_vsi_ctx) {
61171d10453SEric Joyner 			ice_aq_free_vsi(hw, vsi_ctx, false, cd);
61271d10453SEric Joyner 			return ICE_ERR_NO_MEMORY;
61371d10453SEric Joyner 		}
61471d10453SEric Joyner 		*tmp_vsi_ctx = *vsi_ctx;
61571d10453SEric Joyner 
61671d10453SEric Joyner 		ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);
61771d10453SEric Joyner 	} else {
61871d10453SEric Joyner 		/* update with new HW VSI num */
61971d10453SEric Joyner 		tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;
62071d10453SEric Joyner 	}
62171d10453SEric Joyner 
622*f2635e84SEric Joyner 	return 0;
62371d10453SEric Joyner }
62471d10453SEric Joyner 
62571d10453SEric Joyner /**
62671d10453SEric Joyner  * ice_free_vsi- free VSI context from hardware and VSI handle list
62771d10453SEric Joyner  * @hw: pointer to the HW struct
62871d10453SEric Joyner  * @vsi_handle: unique VSI handle
62971d10453SEric Joyner  * @vsi_ctx: pointer to a VSI context struct
63071d10453SEric Joyner  * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
63171d10453SEric Joyner  * @cd: pointer to command details structure or NULL
63271d10453SEric Joyner  *
63371d10453SEric Joyner  * Free VSI context info from hardware as well as from VSI handle list
63471d10453SEric Joyner  */
635*f2635e84SEric Joyner int
63671d10453SEric Joyner ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
63771d10453SEric Joyner 	     bool keep_vsi_alloc, struct ice_sq_cd *cd)
63871d10453SEric Joyner {
639*f2635e84SEric Joyner 	int status;
64071d10453SEric Joyner 
64171d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle))
64271d10453SEric Joyner 		return ICE_ERR_PARAM;
64371d10453SEric Joyner 	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
64471d10453SEric Joyner 	status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);
64571d10453SEric Joyner 	if (!status)
64671d10453SEric Joyner 		ice_clear_vsi_ctx(hw, vsi_handle);
64771d10453SEric Joyner 	return status;
64871d10453SEric Joyner }
64971d10453SEric Joyner 
65071d10453SEric Joyner /**
65171d10453SEric Joyner  * ice_update_vsi
65271d10453SEric Joyner  * @hw: pointer to the HW struct
65371d10453SEric Joyner  * @vsi_handle: unique VSI handle
65471d10453SEric Joyner  * @vsi_ctx: pointer to a VSI context struct
65571d10453SEric Joyner  * @cd: pointer to command details structure or NULL
65671d10453SEric Joyner  *
65771d10453SEric Joyner  * Update VSI context in the hardware
65871d10453SEric Joyner  */
659*f2635e84SEric Joyner int
66071d10453SEric Joyner ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
66171d10453SEric Joyner 	       struct ice_sq_cd *cd)
66271d10453SEric Joyner {
66371d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle))
66471d10453SEric Joyner 		return ICE_ERR_PARAM;
66571d10453SEric Joyner 	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
66671d10453SEric Joyner 	return ice_aq_update_vsi(hw, vsi_ctx, cd);
66771d10453SEric Joyner }
66871d10453SEric Joyner 
66971d10453SEric Joyner /**
6708a13362dSEric Joyner  * ice_cfg_iwarp_fltr - enable/disable iWARP filtering on VSI
6718a13362dSEric Joyner  * @hw: pointer to HW struct
6728a13362dSEric Joyner  * @vsi_handle: VSI SW index
6738a13362dSEric Joyner  * @enable: boolean for enable/disable
6748a13362dSEric Joyner  */
675*f2635e84SEric Joyner int
6768a13362dSEric Joyner ice_cfg_iwarp_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
6778a13362dSEric Joyner {
6788a13362dSEric Joyner 	struct ice_vsi_ctx *ctx, *cached_ctx;
679*f2635e84SEric Joyner 	int status;
6808a13362dSEric Joyner 
6818a13362dSEric Joyner 	cached_ctx = ice_get_vsi_ctx(hw, vsi_handle);
6828a13362dSEric Joyner 	if (!cached_ctx)
6838a13362dSEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
6848a13362dSEric Joyner 
6858a13362dSEric Joyner 	ctx = (struct ice_vsi_ctx *)ice_calloc(hw, 1, sizeof(*ctx));
6868a13362dSEric Joyner 	if (!ctx)
6878a13362dSEric Joyner 		return ICE_ERR_NO_MEMORY;
6888a13362dSEric Joyner 
6898a13362dSEric Joyner 	ctx->info.q_opt_rss = cached_ctx->info.q_opt_rss;
6908a13362dSEric Joyner 	ctx->info.q_opt_tc = cached_ctx->info.q_opt_tc;
6918a13362dSEric Joyner 	ctx->info.q_opt_flags = cached_ctx->info.q_opt_flags;
6928a13362dSEric Joyner 
6938a13362dSEric Joyner 	ctx->info.valid_sections = CPU_TO_LE16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
6948a13362dSEric Joyner 
6958a13362dSEric Joyner 	if (enable)
6968a13362dSEric Joyner 		ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
6978a13362dSEric Joyner 	else
6988a13362dSEric Joyner 		ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
6998a13362dSEric Joyner 
7008a13362dSEric Joyner 	status = ice_update_vsi(hw, vsi_handle, ctx, NULL);
7018a13362dSEric Joyner 	if (!status) {
7028a13362dSEric Joyner 		cached_ctx->info.q_opt_flags = ctx->info.q_opt_flags;
7038a13362dSEric Joyner 		cached_ctx->info.valid_sections |= ctx->info.valid_sections;
7048a13362dSEric Joyner 	}
7058a13362dSEric Joyner 
7068a13362dSEric Joyner 	ice_free(hw, ctx);
7078a13362dSEric Joyner 	return status;
7088a13362dSEric Joyner }
7098a13362dSEric Joyner 
7108a13362dSEric Joyner /**
71171d10453SEric Joyner  * ice_aq_get_vsi_params
71271d10453SEric Joyner  * @hw: pointer to the HW struct
71371d10453SEric Joyner  * @vsi_ctx: pointer to a VSI context struct
71471d10453SEric Joyner  * @cd: pointer to command details structure or NULL
71571d10453SEric Joyner  *
71671d10453SEric Joyner  * Get VSI context info from hardware (0x0212)
71771d10453SEric Joyner  */
718*f2635e84SEric Joyner int
71971d10453SEric Joyner ice_aq_get_vsi_params(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
72071d10453SEric Joyner 		      struct ice_sq_cd *cd)
72171d10453SEric Joyner {
72271d10453SEric Joyner 	struct ice_aqc_add_get_update_free_vsi *cmd;
72371d10453SEric Joyner 	struct ice_aqc_get_vsi_resp *resp;
72471d10453SEric Joyner 	struct ice_aq_desc desc;
725*f2635e84SEric Joyner 	int status;
72671d10453SEric Joyner 
72771d10453SEric Joyner 	cmd = &desc.params.vsi_cmd;
72871d10453SEric Joyner 	resp = &desc.params.get_vsi_resp;
72971d10453SEric Joyner 
73071d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_vsi_params);
73171d10453SEric Joyner 
73271d10453SEric Joyner 	cmd->vsi_num = CPU_TO_LE16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
73371d10453SEric Joyner 
73471d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
73571d10453SEric Joyner 				 sizeof(vsi_ctx->info), cd);
73671d10453SEric Joyner 	if (!status) {
73771d10453SEric Joyner 		vsi_ctx->vsi_num = LE16_TO_CPU(resp->vsi_num) &
73871d10453SEric Joyner 					ICE_AQ_VSI_NUM_M;
73971d10453SEric Joyner 		vsi_ctx->vf_num = resp->vf_id;
74071d10453SEric Joyner 		vsi_ctx->vsis_allocd = LE16_TO_CPU(resp->vsi_used);
74171d10453SEric Joyner 		vsi_ctx->vsis_unallocated = LE16_TO_CPU(resp->vsi_free);
74271d10453SEric Joyner 	}
74371d10453SEric Joyner 
74471d10453SEric Joyner 	return status;
74571d10453SEric Joyner }
74671d10453SEric Joyner 
74771d10453SEric Joyner /**
74871d10453SEric Joyner  * ice_aq_add_update_mir_rule - add/update a mirror rule
74971d10453SEric Joyner  * @hw: pointer to the HW struct
75071d10453SEric Joyner  * @rule_type: Rule Type
75171d10453SEric Joyner  * @dest_vsi: VSI number to which packets will be mirrored
75271d10453SEric Joyner  * @count: length of the list
75371d10453SEric Joyner  * @mr_buf: buffer for list of mirrored VSI numbers
75471d10453SEric Joyner  * @cd: pointer to command details structure or NULL
75571d10453SEric Joyner  * @rule_id: Rule ID
75671d10453SEric Joyner  *
75771d10453SEric Joyner  * Add/Update Mirror Rule (0x260).
75871d10453SEric Joyner  */
759*f2635e84SEric Joyner int
76071d10453SEric Joyner ice_aq_add_update_mir_rule(struct ice_hw *hw, u16 rule_type, u16 dest_vsi,
76171d10453SEric Joyner 			   u16 count, struct ice_mir_rule_buf *mr_buf,
76271d10453SEric Joyner 			   struct ice_sq_cd *cd, u16 *rule_id)
76371d10453SEric Joyner {
76471d10453SEric Joyner 	struct ice_aqc_add_update_mir_rule *cmd;
76571d10453SEric Joyner 	struct ice_aq_desc desc;
76671d10453SEric Joyner 	__le16 *mr_list = NULL;
76771d10453SEric Joyner 	u16 buf_size = 0;
768*f2635e84SEric Joyner 	int status;
76971d10453SEric Joyner 
77071d10453SEric Joyner 	switch (rule_type) {
77171d10453SEric Joyner 	case ICE_AQC_RULE_TYPE_VPORT_INGRESS:
77271d10453SEric Joyner 	case ICE_AQC_RULE_TYPE_VPORT_EGRESS:
77371d10453SEric Joyner 		/* Make sure count and mr_buf are set for these rule_types */
77471d10453SEric Joyner 		if (!(count && mr_buf))
77571d10453SEric Joyner 			return ICE_ERR_PARAM;
77671d10453SEric Joyner 
77771d10453SEric Joyner 		buf_size = count * sizeof(__le16);
77871d10453SEric Joyner 		mr_list = (_FORCE_ __le16 *)ice_malloc(hw, buf_size);
77971d10453SEric Joyner 		if (!mr_list)
78071d10453SEric Joyner 			return ICE_ERR_NO_MEMORY;
78171d10453SEric Joyner 		break;
78271d10453SEric Joyner 	case ICE_AQC_RULE_TYPE_PPORT_INGRESS:
78371d10453SEric Joyner 	case ICE_AQC_RULE_TYPE_PPORT_EGRESS:
78471d10453SEric Joyner 		/* Make sure count and mr_buf are not set for these
78571d10453SEric Joyner 		 * rule_types
78671d10453SEric Joyner 		 */
78771d10453SEric Joyner 		if (count || mr_buf)
78871d10453SEric Joyner 			return ICE_ERR_PARAM;
78971d10453SEric Joyner 		break;
79071d10453SEric Joyner 	default:
7917d7af7f8SEric Joyner 		ice_debug(hw, ICE_DBG_SW, "Error due to unsupported rule_type %u\n", rule_type);
79271d10453SEric Joyner 		return ICE_ERR_OUT_OF_RANGE;
79371d10453SEric Joyner 	}
79471d10453SEric Joyner 
79571d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_update_mir_rule);
79671d10453SEric Joyner 
79771d10453SEric Joyner 	/* Pre-process 'mr_buf' items for add/update of virtual port
79871d10453SEric Joyner 	 * ingress/egress mirroring (but not physical port ingress/egress
79971d10453SEric Joyner 	 * mirroring)
80071d10453SEric Joyner 	 */
80171d10453SEric Joyner 	if (mr_buf) {
80271d10453SEric Joyner 		int i;
80371d10453SEric Joyner 
80471d10453SEric Joyner 		for (i = 0; i < count; i++) {
80571d10453SEric Joyner 			u16 id;
80671d10453SEric Joyner 
80771d10453SEric Joyner 			id = mr_buf[i].vsi_idx & ICE_AQC_RULE_MIRRORED_VSI_M;
80871d10453SEric Joyner 
80971d10453SEric Joyner 			/* Validate specified VSI number, make sure it is less
81071d10453SEric Joyner 			 * than ICE_MAX_VSI, if not return with error.
81171d10453SEric Joyner 			 */
81271d10453SEric Joyner 			if (id >= ICE_MAX_VSI) {
8137d7af7f8SEric Joyner 				ice_debug(hw, ICE_DBG_SW, "Error VSI index (%u) out-of-range\n",
81471d10453SEric Joyner 					  id);
81571d10453SEric Joyner 				ice_free(hw, mr_list);
81671d10453SEric Joyner 				return ICE_ERR_OUT_OF_RANGE;
81771d10453SEric Joyner 			}
81871d10453SEric Joyner 
81971d10453SEric Joyner 			/* add VSI to mirror rule */
82071d10453SEric Joyner 			if (mr_buf[i].add)
82171d10453SEric Joyner 				mr_list[i] =
82271d10453SEric Joyner 					CPU_TO_LE16(id | ICE_AQC_RULE_ACT_M);
82371d10453SEric Joyner 			else /* remove VSI from mirror rule */
82471d10453SEric Joyner 				mr_list[i] = CPU_TO_LE16(id);
82571d10453SEric Joyner 		}
8268923de59SPiotr Kubaj 
8278923de59SPiotr Kubaj 		desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
82871d10453SEric Joyner 	}
82971d10453SEric Joyner 
83071d10453SEric Joyner 	cmd = &desc.params.add_update_rule;
83171d10453SEric Joyner 	if ((*rule_id) != ICE_INVAL_MIRROR_RULE_ID)
83271d10453SEric Joyner 		cmd->rule_id = CPU_TO_LE16(((*rule_id) & ICE_AQC_RULE_ID_M) |
83371d10453SEric Joyner 					   ICE_AQC_RULE_ID_VALID_M);
83471d10453SEric Joyner 	cmd->rule_type = CPU_TO_LE16(rule_type & ICE_AQC_RULE_TYPE_M);
83571d10453SEric Joyner 	cmd->num_entries = CPU_TO_LE16(count);
83671d10453SEric Joyner 	cmd->dest = CPU_TO_LE16(dest_vsi);
83771d10453SEric Joyner 
83871d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, mr_list, buf_size, cd);
83971d10453SEric Joyner 	if (!status)
84071d10453SEric Joyner 		*rule_id = LE16_TO_CPU(cmd->rule_id) & ICE_AQC_RULE_ID_M;
84171d10453SEric Joyner 
84271d10453SEric Joyner 	ice_free(hw, mr_list);
84371d10453SEric Joyner 
84471d10453SEric Joyner 	return status;
84571d10453SEric Joyner }
84671d10453SEric Joyner 
84771d10453SEric Joyner /**
84871d10453SEric Joyner  * ice_aq_delete_mir_rule - delete a mirror rule
84971d10453SEric Joyner  * @hw: pointer to the HW struct
85071d10453SEric Joyner  * @rule_id: Mirror rule ID (to be deleted)
85171d10453SEric Joyner  * @keep_allocd: if set, the VSI stays part of the PF allocated res,
85271d10453SEric Joyner  *		 otherwise it is returned to the shared pool
85371d10453SEric Joyner  * @cd: pointer to command details structure or NULL
85471d10453SEric Joyner  *
85571d10453SEric Joyner  * Delete Mirror Rule (0x261).
85671d10453SEric Joyner  */
857*f2635e84SEric Joyner int
85871d10453SEric Joyner ice_aq_delete_mir_rule(struct ice_hw *hw, u16 rule_id, bool keep_allocd,
85971d10453SEric Joyner 		       struct ice_sq_cd *cd)
86071d10453SEric Joyner {
86171d10453SEric Joyner 	struct ice_aqc_delete_mir_rule *cmd;
86271d10453SEric Joyner 	struct ice_aq_desc desc;
86371d10453SEric Joyner 
86471d10453SEric Joyner 	/* rule_id should be in the range 0...63 */
86571d10453SEric Joyner 	if (rule_id >= ICE_MAX_NUM_MIRROR_RULES)
86671d10453SEric Joyner 		return ICE_ERR_OUT_OF_RANGE;
86771d10453SEric Joyner 
86871d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_del_mir_rule);
86971d10453SEric Joyner 
87071d10453SEric Joyner 	cmd = &desc.params.del_rule;
87171d10453SEric Joyner 	rule_id |= ICE_AQC_RULE_ID_VALID_M;
87271d10453SEric Joyner 	cmd->rule_id = CPU_TO_LE16(rule_id);
87371d10453SEric Joyner 
87471d10453SEric Joyner 	if (keep_allocd)
87571d10453SEric Joyner 		cmd->flags = CPU_TO_LE16(ICE_AQC_FLAG_KEEP_ALLOCD_M);
87671d10453SEric Joyner 
87771d10453SEric Joyner 	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
87871d10453SEric Joyner }
87971d10453SEric Joyner 
88071d10453SEric Joyner /**
88171d10453SEric Joyner  * ice_aq_alloc_free_vsi_list
88271d10453SEric Joyner  * @hw: pointer to the HW struct
88371d10453SEric Joyner  * @vsi_list_id: VSI list ID returned or used for lookup
88471d10453SEric Joyner  * @lkup_type: switch rule filter lookup type
88571d10453SEric Joyner  * @opc: switch rules population command type - pass in the command opcode
88671d10453SEric Joyner  *
88771d10453SEric Joyner  * allocates or free a VSI list resource
88871d10453SEric Joyner  */
889*f2635e84SEric Joyner static int
89071d10453SEric Joyner ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
89171d10453SEric Joyner 			   enum ice_sw_lkup_type lkup_type,
89271d10453SEric Joyner 			   enum ice_adminq_opc opc)
89371d10453SEric Joyner {
89471d10453SEric Joyner 	struct ice_aqc_alloc_free_res_elem *sw_buf;
89571d10453SEric Joyner 	struct ice_aqc_res_elem *vsi_ele;
89671d10453SEric Joyner 	u16 buf_len;
897*f2635e84SEric Joyner 	int status;
89871d10453SEric Joyner 
8997d7af7f8SEric Joyner 	buf_len = ice_struct_size(sw_buf, elem, 1);
9007d7af7f8SEric Joyner 	sw_buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
90171d10453SEric Joyner 	if (!sw_buf)
90271d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
90371d10453SEric Joyner 	sw_buf->num_elems = CPU_TO_LE16(1);
90471d10453SEric Joyner 
90571d10453SEric Joyner 	if (lkup_type == ICE_SW_LKUP_MAC ||
90671d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
90771d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
90871d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
90971d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_PROMISC ||
91071d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
9118923de59SPiotr Kubaj 	    lkup_type == ICE_SW_LKUP_DFLT ||
91271d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_LAST) {
91371d10453SEric Joyner 		sw_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_VSI_LIST_REP);
91471d10453SEric Joyner 	} else if (lkup_type == ICE_SW_LKUP_VLAN) {
91571d10453SEric Joyner 		sw_buf->res_type =
91671d10453SEric Joyner 			CPU_TO_LE16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
91771d10453SEric Joyner 	} else {
91871d10453SEric Joyner 		status = ICE_ERR_PARAM;
91971d10453SEric Joyner 		goto ice_aq_alloc_free_vsi_list_exit;
92071d10453SEric Joyner 	}
92171d10453SEric Joyner 
92271d10453SEric Joyner 	if (opc == ice_aqc_opc_free_res)
92371d10453SEric Joyner 		sw_buf->elem[0].e.sw_resp = CPU_TO_LE16(*vsi_list_id);
92471d10453SEric Joyner 
92571d10453SEric Joyner 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL);
92671d10453SEric Joyner 	if (status)
92771d10453SEric Joyner 		goto ice_aq_alloc_free_vsi_list_exit;
92871d10453SEric Joyner 
92971d10453SEric Joyner 	if (opc == ice_aqc_opc_alloc_res) {
93071d10453SEric Joyner 		vsi_ele = &sw_buf->elem[0];
93171d10453SEric Joyner 		*vsi_list_id = LE16_TO_CPU(vsi_ele->e.sw_resp);
93271d10453SEric Joyner 	}
93371d10453SEric Joyner 
93471d10453SEric Joyner ice_aq_alloc_free_vsi_list_exit:
93571d10453SEric Joyner 	ice_free(hw, sw_buf);
93671d10453SEric Joyner 	return status;
93771d10453SEric Joyner }
93871d10453SEric Joyner 
93971d10453SEric Joyner /**
94071d10453SEric Joyner  * ice_aq_set_storm_ctrl - Sets storm control configuration
94171d10453SEric Joyner  * @hw: pointer to the HW struct
94271d10453SEric Joyner  * @bcast_thresh: represents the upper threshold for broadcast storm control
94371d10453SEric Joyner  * @mcast_thresh: represents the upper threshold for multicast storm control
9447d7af7f8SEric Joyner  * @ctl_bitmask: storm control knobs
94571d10453SEric Joyner  *
94671d10453SEric Joyner  * Sets the storm control configuration (0x0280)
94771d10453SEric Joyner  */
948*f2635e84SEric Joyner int
94971d10453SEric Joyner ice_aq_set_storm_ctrl(struct ice_hw *hw, u32 bcast_thresh, u32 mcast_thresh,
95071d10453SEric Joyner 		      u32 ctl_bitmask)
95171d10453SEric Joyner {
95271d10453SEric Joyner 	struct ice_aqc_storm_cfg *cmd;
95371d10453SEric Joyner 	struct ice_aq_desc desc;
95471d10453SEric Joyner 
95571d10453SEric Joyner 	cmd = &desc.params.storm_conf;
95671d10453SEric Joyner 
95771d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_storm_cfg);
95871d10453SEric Joyner 
95971d10453SEric Joyner 	cmd->bcast_thresh_size = CPU_TO_LE32(bcast_thresh & ICE_AQ_THRESHOLD_M);
96071d10453SEric Joyner 	cmd->mcast_thresh_size = CPU_TO_LE32(mcast_thresh & ICE_AQ_THRESHOLD_M);
96171d10453SEric Joyner 	cmd->storm_ctrl_ctrl = CPU_TO_LE32(ctl_bitmask);
96271d10453SEric Joyner 
96371d10453SEric Joyner 	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
96471d10453SEric Joyner }
96571d10453SEric Joyner 
96671d10453SEric Joyner /**
96771d10453SEric Joyner  * ice_aq_get_storm_ctrl - gets storm control configuration
96871d10453SEric Joyner  * @hw: pointer to the HW struct
96971d10453SEric Joyner  * @bcast_thresh: represents the upper threshold for broadcast storm control
97071d10453SEric Joyner  * @mcast_thresh: represents the upper threshold for multicast storm control
9717d7af7f8SEric Joyner  * @ctl_bitmask: storm control knobs
97271d10453SEric Joyner  *
97371d10453SEric Joyner  * Gets the storm control configuration (0x0281)
97471d10453SEric Joyner  */
975*f2635e84SEric Joyner int
97671d10453SEric Joyner ice_aq_get_storm_ctrl(struct ice_hw *hw, u32 *bcast_thresh, u32 *mcast_thresh,
97771d10453SEric Joyner 		      u32 *ctl_bitmask)
97871d10453SEric Joyner {
97971d10453SEric Joyner 	struct ice_aq_desc desc;
980*f2635e84SEric Joyner 	int status;
98171d10453SEric Joyner 
98271d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_storm_cfg);
98371d10453SEric Joyner 
98471d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
98571d10453SEric Joyner 	if (!status) {
98671d10453SEric Joyner 		struct ice_aqc_storm_cfg *resp = &desc.params.storm_conf;
98771d10453SEric Joyner 
98871d10453SEric Joyner 		if (bcast_thresh)
98971d10453SEric Joyner 			*bcast_thresh = LE32_TO_CPU(resp->bcast_thresh_size) &
99071d10453SEric Joyner 				ICE_AQ_THRESHOLD_M;
99171d10453SEric Joyner 		if (mcast_thresh)
99271d10453SEric Joyner 			*mcast_thresh = LE32_TO_CPU(resp->mcast_thresh_size) &
99371d10453SEric Joyner 				ICE_AQ_THRESHOLD_M;
99471d10453SEric Joyner 		if (ctl_bitmask)
99571d10453SEric Joyner 			*ctl_bitmask = LE32_TO_CPU(resp->storm_ctrl_ctrl);
99671d10453SEric Joyner 	}
99771d10453SEric Joyner 
99871d10453SEric Joyner 	return status;
99971d10453SEric Joyner }
100071d10453SEric Joyner 
100171d10453SEric Joyner /**
100271d10453SEric Joyner  * ice_aq_sw_rules - add/update/remove switch rules
100371d10453SEric Joyner  * @hw: pointer to the HW struct
100471d10453SEric Joyner  * @rule_list: pointer to switch rule population list
100571d10453SEric Joyner  * @rule_list_sz: total size of the rule list in bytes
100671d10453SEric Joyner  * @num_rules: number of switch rules in the rule_list
100771d10453SEric Joyner  * @opc: switch rules population command type - pass in the command opcode
100871d10453SEric Joyner  * @cd: pointer to command details structure or NULL
100971d10453SEric Joyner  *
101071d10453SEric Joyner  * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware
101171d10453SEric Joyner  */
1012*f2635e84SEric Joyner int
101371d10453SEric Joyner ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
101471d10453SEric Joyner 		u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd)
101571d10453SEric Joyner {
101671d10453SEric Joyner 	struct ice_aq_desc desc;
1017*f2635e84SEric Joyner 	int status;
101871d10453SEric Joyner 
101971d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
102071d10453SEric Joyner 
102171d10453SEric Joyner 	if (opc != ice_aqc_opc_add_sw_rules &&
102271d10453SEric Joyner 	    opc != ice_aqc_opc_update_sw_rules &&
102371d10453SEric Joyner 	    opc != ice_aqc_opc_remove_sw_rules)
102471d10453SEric Joyner 		return ICE_ERR_PARAM;
102571d10453SEric Joyner 
102671d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, opc);
102771d10453SEric Joyner 
102871d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
102971d10453SEric Joyner 	desc.params.sw_rules.num_rules_fltr_entry_index =
103071d10453SEric Joyner 		CPU_TO_LE16(num_rules);
10317d7af7f8SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd);
10327d7af7f8SEric Joyner 	if (opc != ice_aqc_opc_add_sw_rules &&
10337d7af7f8SEric Joyner 	    hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
10347d7af7f8SEric Joyner 		status = ICE_ERR_DOES_NOT_EXIST;
10357d7af7f8SEric Joyner 
10367d7af7f8SEric Joyner 	return status;
103771d10453SEric Joyner }
103871d10453SEric Joyner 
103971d10453SEric Joyner /* ice_init_port_info - Initialize port_info with switch configuration data
104071d10453SEric Joyner  * @pi: pointer to port_info
104171d10453SEric Joyner  * @vsi_port_num: VSI number or port number
104271d10453SEric Joyner  * @type: Type of switch element (port or VSI)
104371d10453SEric Joyner  * @swid: switch ID of the switch the element is attached to
104471d10453SEric Joyner  * @pf_vf_num: PF or VF number
104571d10453SEric Joyner  * @is_vf: true if the element is a VF, false otherwise
104671d10453SEric Joyner  */
104771d10453SEric Joyner static void
104871d10453SEric Joyner ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type,
104971d10453SEric Joyner 		   u16 swid, u16 pf_vf_num, bool is_vf)
105071d10453SEric Joyner {
105171d10453SEric Joyner 	switch (type) {
105271d10453SEric Joyner 	case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:
105371d10453SEric Joyner 		pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK);
105471d10453SEric Joyner 		pi->sw_id = swid;
105571d10453SEric Joyner 		pi->pf_vf_num = pf_vf_num;
105671d10453SEric Joyner 		pi->is_vf = is_vf;
105771d10453SEric Joyner 		break;
105871d10453SEric Joyner 	default:
10597d7af7f8SEric Joyner 		ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n");
106071d10453SEric Joyner 		break;
106171d10453SEric Joyner 	}
106271d10453SEric Joyner }
106371d10453SEric Joyner 
106471d10453SEric Joyner /* ice_get_initial_sw_cfg - Get initial port and default VSI data
106571d10453SEric Joyner  * @hw: pointer to the hardware structure
106671d10453SEric Joyner  */
1067*f2635e84SEric Joyner int ice_get_initial_sw_cfg(struct ice_hw *hw)
106871d10453SEric Joyner {
10697d7af7f8SEric Joyner 	struct ice_aqc_get_sw_cfg_resp_elem *rbuf;
107071d10453SEric Joyner 	u8 num_total_ports;
107171d10453SEric Joyner 	u16 req_desc = 0;
107271d10453SEric Joyner 	u16 num_elems;
1073*f2635e84SEric Joyner 	int status;
107471d10453SEric Joyner 	u8 j = 0;
107571d10453SEric Joyner 	u16 i;
107671d10453SEric Joyner 
107771d10453SEric Joyner 	num_total_ports = 1;
107871d10453SEric Joyner 
10797d7af7f8SEric Joyner 	rbuf = (struct ice_aqc_get_sw_cfg_resp_elem *)
108071d10453SEric Joyner 		ice_malloc(hw, ICE_SW_CFG_MAX_BUF_LEN);
108171d10453SEric Joyner 
108271d10453SEric Joyner 	if (!rbuf)
108371d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
108471d10453SEric Joyner 
108571d10453SEric Joyner 	/* Multiple calls to ice_aq_get_sw_cfg may be required
108671d10453SEric Joyner 	 * to get all the switch configuration information. The need
108771d10453SEric Joyner 	 * for additional calls is indicated by ice_aq_get_sw_cfg
108871d10453SEric Joyner 	 * writing a non-zero value in req_desc
108971d10453SEric Joyner 	 */
109071d10453SEric Joyner 	do {
10917d7af7f8SEric Joyner 		struct ice_aqc_get_sw_cfg_resp_elem *ele;
10927d7af7f8SEric Joyner 
109371d10453SEric Joyner 		status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN,
109471d10453SEric Joyner 					   &req_desc, &num_elems, NULL);
109571d10453SEric Joyner 
109671d10453SEric Joyner 		if (status)
109771d10453SEric Joyner 			break;
109871d10453SEric Joyner 
10997d7af7f8SEric Joyner 		for (i = 0, ele = rbuf; i < num_elems; i++, ele++) {
110071d10453SEric Joyner 			u16 pf_vf_num, swid, vsi_port_num;
110171d10453SEric Joyner 			bool is_vf = false;
110271d10453SEric Joyner 			u8 res_type;
110371d10453SEric Joyner 
110471d10453SEric Joyner 			vsi_port_num = LE16_TO_CPU(ele->vsi_port_num) &
110571d10453SEric Joyner 				ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M;
110671d10453SEric Joyner 
110771d10453SEric Joyner 			pf_vf_num = LE16_TO_CPU(ele->pf_vf_num) &
110871d10453SEric Joyner 				ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M;
110971d10453SEric Joyner 
111071d10453SEric Joyner 			swid = LE16_TO_CPU(ele->swid);
111171d10453SEric Joyner 
111271d10453SEric Joyner 			if (LE16_TO_CPU(ele->pf_vf_num) &
111371d10453SEric Joyner 			    ICE_AQC_GET_SW_CONF_RESP_IS_VF)
111471d10453SEric Joyner 				is_vf = true;
111571d10453SEric Joyner 
111671d10453SEric Joyner 			res_type = (u8)(LE16_TO_CPU(ele->vsi_port_num) >>
111771d10453SEric Joyner 					ICE_AQC_GET_SW_CONF_RESP_TYPE_S);
111871d10453SEric Joyner 
111971d10453SEric Joyner 			switch (res_type) {
1120*f2635e84SEric Joyner 			case ICE_AQC_GET_SW_CONF_RESP_VSI:
1121*f2635e84SEric Joyner 				if (hw->fw_vsi_num != ICE_DFLT_VSI_INVAL)
1122*f2635e84SEric Joyner 					ice_debug(hw, ICE_DBG_SW, "fw_vsi_num %d -> %d\n",
1123*f2635e84SEric Joyner 						  hw->fw_vsi_num, vsi_port_num);
1124*f2635e84SEric Joyner 				hw->fw_vsi_num = vsi_port_num;
1125*f2635e84SEric Joyner 				break;
112671d10453SEric Joyner 			case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:
112771d10453SEric Joyner 			case ICE_AQC_GET_SW_CONF_RESP_VIRT_PORT:
112871d10453SEric Joyner 				if (j == num_total_ports) {
11297d7af7f8SEric Joyner 					ice_debug(hw, ICE_DBG_SW, "more ports than expected\n");
113071d10453SEric Joyner 					status = ICE_ERR_CFG;
113171d10453SEric Joyner 					goto out;
113271d10453SEric Joyner 				}
113371d10453SEric Joyner 				ice_init_port_info(hw->port_info,
113471d10453SEric Joyner 						   vsi_port_num, res_type, swid,
113571d10453SEric Joyner 						   pf_vf_num, is_vf);
113671d10453SEric Joyner 				j++;
113771d10453SEric Joyner 				break;
113871d10453SEric Joyner 			default:
113971d10453SEric Joyner 				break;
114071d10453SEric Joyner 			}
114171d10453SEric Joyner 		}
114271d10453SEric Joyner 	} while (req_desc && !status);
114371d10453SEric Joyner 
114471d10453SEric Joyner out:
11457d7af7f8SEric Joyner 	ice_free(hw, rbuf);
114671d10453SEric Joyner 	return status;
114771d10453SEric Joyner }
114871d10453SEric Joyner 
114971d10453SEric Joyner /**
115071d10453SEric Joyner  * ice_fill_sw_info - Helper function to populate lb_en and lan_en
115171d10453SEric Joyner  * @hw: pointer to the hardware structure
115271d10453SEric Joyner  * @fi: filter info structure to fill/update
115371d10453SEric Joyner  *
115471d10453SEric Joyner  * This helper function populates the lb_en and lan_en elements of the provided
115571d10453SEric Joyner  * ice_fltr_info struct using the switch's type and characteristics of the
115671d10453SEric Joyner  * switch rule being configured.
115771d10453SEric Joyner  */
115871d10453SEric Joyner static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
115971d10453SEric Joyner {
116071d10453SEric Joyner 	fi->lb_en = false;
116171d10453SEric Joyner 	fi->lan_en = false;
116271d10453SEric Joyner 	if ((fi->flag & ICE_FLTR_TX) &&
116371d10453SEric Joyner 	    (fi->fltr_act == ICE_FWD_TO_VSI ||
116471d10453SEric Joyner 	     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
116571d10453SEric Joyner 	     fi->fltr_act == ICE_FWD_TO_Q ||
116671d10453SEric Joyner 	     fi->fltr_act == ICE_FWD_TO_QGRP)) {
116771d10453SEric Joyner 		/* Setting LB for prune actions will result in replicated
116871d10453SEric Joyner 		 * packets to the internal switch that will be dropped.
116971d10453SEric Joyner 		 */
117071d10453SEric Joyner 		if (fi->lkup_type != ICE_SW_LKUP_VLAN)
117171d10453SEric Joyner 			fi->lb_en = true;
117271d10453SEric Joyner 
117371d10453SEric Joyner 		/* Set lan_en to TRUE if
117471d10453SEric Joyner 		 * 1. The switch is a VEB AND
117571d10453SEric Joyner 		 * 2
117671d10453SEric Joyner 		 * 2.1 The lookup is a directional lookup like ethertype,
117771d10453SEric Joyner 		 * promiscuous, ethertype-MAC, promiscuous-VLAN
117871d10453SEric Joyner 		 * and default-port OR
117971d10453SEric Joyner 		 * 2.2 The lookup is VLAN, OR
118071d10453SEric Joyner 		 * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR
118171d10453SEric Joyner 		 * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC.
118271d10453SEric Joyner 		 *
118371d10453SEric Joyner 		 * OR
118471d10453SEric Joyner 		 *
118571d10453SEric Joyner 		 * The switch is a VEPA.
118671d10453SEric Joyner 		 *
118771d10453SEric Joyner 		 * In all other cases, the LAN enable has to be set to false.
118871d10453SEric Joyner 		 */
11899e54973fSEric Joyner 
119071d10453SEric Joyner 		if (hw->evb_veb) {
119171d10453SEric Joyner 			if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE ||
119271d10453SEric Joyner 			    fi->lkup_type == ICE_SW_LKUP_PROMISC ||
119371d10453SEric Joyner 			    fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
119471d10453SEric Joyner 			    fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
119571d10453SEric Joyner 			    fi->lkup_type == ICE_SW_LKUP_DFLT ||
119671d10453SEric Joyner 			    fi->lkup_type == ICE_SW_LKUP_VLAN ||
119771d10453SEric Joyner 			    (fi->lkup_type == ICE_SW_LKUP_MAC &&
119871d10453SEric Joyner 			     !IS_UNICAST_ETHER_ADDR(fi->l_data.mac.mac_addr)) ||
119971d10453SEric Joyner 			    (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN &&
1200*f2635e84SEric Joyner 			     !IS_UNICAST_ETHER_ADDR(fi->l_data.mac.mac_addr))) {
1201*f2635e84SEric Joyner 				if (!fi->fltVeb_en)
120271d10453SEric Joyner 					fi->lan_en = true;
1203*f2635e84SEric Joyner 			}
120471d10453SEric Joyner 		} else {
120571d10453SEric Joyner 			fi->lan_en = true;
120671d10453SEric Joyner 		}
120771d10453SEric Joyner 	}
12089e54973fSEric Joyner 	/* To be able to receive packets coming from the VF on the same PF,
12099e54973fSEric Joyner 	 * unicast filter needs to be added without LB_EN bit
12109e54973fSEric Joyner 	 */
12119e54973fSEric Joyner 	if (fi->flag & ICE_FLTR_RX_LB) {
12129e54973fSEric Joyner 		fi->lb_en = false;
12139e54973fSEric Joyner 		fi->lan_en = true;
12149e54973fSEric Joyner 	}
121571d10453SEric Joyner }
121671d10453SEric Joyner 
121771d10453SEric Joyner /**
121871d10453SEric Joyner  * ice_fill_sw_rule - Helper function to fill switch rule structure
121971d10453SEric Joyner  * @hw: pointer to the hardware structure
122071d10453SEric Joyner  * @f_info: entry containing packet forwarding information
122171d10453SEric Joyner  * @s_rule: switch rule structure to be filled in based on mac_entry
122271d10453SEric Joyner  * @opc: switch rules population command type - pass in the command opcode
122371d10453SEric Joyner  */
122471d10453SEric Joyner static void
122571d10453SEric Joyner ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
12269c30461dSEric Joyner 		 struct ice_sw_rule_lkup_rx_tx *s_rule,
12279c30461dSEric Joyner 		 enum ice_adminq_opc opc)
122871d10453SEric Joyner {
122971d10453SEric Joyner 	u16 vlan_id = ICE_MAX_VLAN_ID + 1;
12309cf1841cSEric Joyner 	u16 vlan_tpid = ICE_ETH_P_8021Q;
123171d10453SEric Joyner 	void *daddr = NULL;
123271d10453SEric Joyner 	u16 eth_hdr_sz;
123371d10453SEric Joyner 	u8 *eth_hdr;
123471d10453SEric Joyner 	u32 act = 0;
123571d10453SEric Joyner 	__be16 *off;
123671d10453SEric Joyner 	u8 q_rgn;
123771d10453SEric Joyner 
123871d10453SEric Joyner 	if (opc == ice_aqc_opc_remove_sw_rules) {
12399c30461dSEric Joyner 		s_rule->act = 0;
12409c30461dSEric Joyner 		s_rule->index = CPU_TO_LE16(f_info->fltr_rule_id);
12419c30461dSEric Joyner 		s_rule->hdr_len = 0;
124271d10453SEric Joyner 		return;
124371d10453SEric Joyner 	}
124471d10453SEric Joyner 
124571d10453SEric Joyner 	eth_hdr_sz = sizeof(dummy_eth_header);
12469c30461dSEric Joyner 	eth_hdr = s_rule->hdr_data;
124771d10453SEric Joyner 
124871d10453SEric Joyner 	/* initialize the ether header with a dummy header */
124971d10453SEric Joyner 	ice_memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz, ICE_NONDMA_TO_NONDMA);
125071d10453SEric Joyner 	ice_fill_sw_info(hw, f_info);
125171d10453SEric Joyner 
125271d10453SEric Joyner 	switch (f_info->fltr_act) {
125371d10453SEric Joyner 	case ICE_FWD_TO_VSI:
125471d10453SEric Joyner 		act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
125571d10453SEric Joyner 			ICE_SINGLE_ACT_VSI_ID_M;
125671d10453SEric Joyner 		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
125771d10453SEric Joyner 			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
125871d10453SEric Joyner 				ICE_SINGLE_ACT_VALID_BIT;
125971d10453SEric Joyner 		break;
126071d10453SEric Joyner 	case ICE_FWD_TO_VSI_LIST:
126171d10453SEric Joyner 		act |= ICE_SINGLE_ACT_VSI_LIST;
126271d10453SEric Joyner 		act |= (f_info->fwd_id.vsi_list_id <<
126371d10453SEric Joyner 			ICE_SINGLE_ACT_VSI_LIST_ID_S) &
126471d10453SEric Joyner 			ICE_SINGLE_ACT_VSI_LIST_ID_M;
126571d10453SEric Joyner 		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
126671d10453SEric Joyner 			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
126771d10453SEric Joyner 				ICE_SINGLE_ACT_VALID_BIT;
126871d10453SEric Joyner 		break;
126971d10453SEric Joyner 	case ICE_FWD_TO_Q:
127071d10453SEric Joyner 		act |= ICE_SINGLE_ACT_TO_Q;
127171d10453SEric Joyner 		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
127271d10453SEric Joyner 			ICE_SINGLE_ACT_Q_INDEX_M;
127371d10453SEric Joyner 		break;
127471d10453SEric Joyner 	case ICE_DROP_PACKET:
127571d10453SEric Joyner 		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
127671d10453SEric Joyner 			ICE_SINGLE_ACT_VALID_BIT;
127771d10453SEric Joyner 		break;
127871d10453SEric Joyner 	case ICE_FWD_TO_QGRP:
127971d10453SEric Joyner 		q_rgn = f_info->qgrp_size > 0 ?
128071d10453SEric Joyner 			(u8)ice_ilog2(f_info->qgrp_size) : 0;
128171d10453SEric Joyner 		act |= ICE_SINGLE_ACT_TO_Q;
128271d10453SEric Joyner 		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
128371d10453SEric Joyner 			ICE_SINGLE_ACT_Q_INDEX_M;
128471d10453SEric Joyner 		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
128571d10453SEric Joyner 			ICE_SINGLE_ACT_Q_REGION_M;
128671d10453SEric Joyner 		break;
128771d10453SEric Joyner 	default:
128871d10453SEric Joyner 		return;
128971d10453SEric Joyner 	}
129071d10453SEric Joyner 
129171d10453SEric Joyner 	if (f_info->lb_en)
129271d10453SEric Joyner 		act |= ICE_SINGLE_ACT_LB_ENABLE;
129371d10453SEric Joyner 	if (f_info->lan_en)
129471d10453SEric Joyner 		act |= ICE_SINGLE_ACT_LAN_ENABLE;
129571d10453SEric Joyner 
129671d10453SEric Joyner 	switch (f_info->lkup_type) {
129771d10453SEric Joyner 	case ICE_SW_LKUP_MAC:
129871d10453SEric Joyner 		daddr = f_info->l_data.mac.mac_addr;
129971d10453SEric Joyner 		break;
130071d10453SEric Joyner 	case ICE_SW_LKUP_VLAN:
130171d10453SEric Joyner 		vlan_id = f_info->l_data.vlan.vlan_id;
13029cf1841cSEric Joyner 		if (f_info->l_data.vlan.tpid_valid)
13039cf1841cSEric Joyner 			vlan_tpid = f_info->l_data.vlan.tpid;
130471d10453SEric Joyner 		if (f_info->fltr_act == ICE_FWD_TO_VSI ||
130571d10453SEric Joyner 		    f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
130671d10453SEric Joyner 			act |= ICE_SINGLE_ACT_PRUNE;
130771d10453SEric Joyner 			act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS;
130871d10453SEric Joyner 		}
130971d10453SEric Joyner 		break;
131071d10453SEric Joyner 	case ICE_SW_LKUP_ETHERTYPE_MAC:
131171d10453SEric Joyner 		daddr = f_info->l_data.ethertype_mac.mac_addr;
131271d10453SEric Joyner 		/* fall-through */
131371d10453SEric Joyner 	case ICE_SW_LKUP_ETHERTYPE:
131471d10453SEric Joyner 		off = (_FORCE_ __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
131571d10453SEric Joyner 		*off = CPU_TO_BE16(f_info->l_data.ethertype_mac.ethertype);
131671d10453SEric Joyner 		break;
131771d10453SEric Joyner 	case ICE_SW_LKUP_MAC_VLAN:
131871d10453SEric Joyner 		daddr = f_info->l_data.mac_vlan.mac_addr;
131971d10453SEric Joyner 		vlan_id = f_info->l_data.mac_vlan.vlan_id;
132071d10453SEric Joyner 		break;
132171d10453SEric Joyner 	case ICE_SW_LKUP_PROMISC_VLAN:
132271d10453SEric Joyner 		vlan_id = f_info->l_data.mac_vlan.vlan_id;
132371d10453SEric Joyner 		/* fall-through */
132471d10453SEric Joyner 	case ICE_SW_LKUP_PROMISC:
132571d10453SEric Joyner 		daddr = f_info->l_data.mac_vlan.mac_addr;
132671d10453SEric Joyner 		break;
132771d10453SEric Joyner 	default:
132871d10453SEric Joyner 		break;
132971d10453SEric Joyner 	}
133071d10453SEric Joyner 
13319c30461dSEric Joyner 	s_rule->hdr.type = (f_info->flag & ICE_FLTR_RX) ?
133271d10453SEric Joyner 		CPU_TO_LE16(ICE_AQC_SW_RULES_T_LKUP_RX) :
133371d10453SEric Joyner 		CPU_TO_LE16(ICE_AQC_SW_RULES_T_LKUP_TX);
133471d10453SEric Joyner 
133571d10453SEric Joyner 	/* Recipe set depending on lookup type */
13369c30461dSEric Joyner 	s_rule->recipe_id = CPU_TO_LE16(f_info->lkup_type);
13379c30461dSEric Joyner 	s_rule->src = CPU_TO_LE16(f_info->src);
13389c30461dSEric Joyner 	s_rule->act = CPU_TO_LE32(act);
133971d10453SEric Joyner 
134071d10453SEric Joyner 	if (daddr)
134171d10453SEric Joyner 		ice_memcpy(eth_hdr + ICE_ETH_DA_OFFSET, daddr, ETH_ALEN,
134271d10453SEric Joyner 			   ICE_NONDMA_TO_NONDMA);
134371d10453SEric Joyner 
134471d10453SEric Joyner 	if (!(vlan_id > ICE_MAX_VLAN_ID)) {
134571d10453SEric Joyner 		off = (_FORCE_ __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
134671d10453SEric Joyner 		*off = CPU_TO_BE16(vlan_id);
13479cf1841cSEric Joyner 		off = (_FORCE_ __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
13489cf1841cSEric Joyner 		*off = CPU_TO_BE16(vlan_tpid);
134971d10453SEric Joyner 	}
135071d10453SEric Joyner 
135171d10453SEric Joyner 	/* Create the switch rule with the final dummy Ethernet header */
135271d10453SEric Joyner 	if (opc != ice_aqc_opc_update_sw_rules)
13539c30461dSEric Joyner 		s_rule->hdr_len = CPU_TO_LE16(eth_hdr_sz);
135471d10453SEric Joyner }
135571d10453SEric Joyner 
135671d10453SEric Joyner /**
135771d10453SEric Joyner  * ice_add_marker_act
135871d10453SEric Joyner  * @hw: pointer to the hardware structure
135971d10453SEric Joyner  * @m_ent: the management entry for which sw marker needs to be added
136071d10453SEric Joyner  * @sw_marker: sw marker to tag the Rx descriptor with
136171d10453SEric Joyner  * @l_id: large action resource ID
136271d10453SEric Joyner  *
136371d10453SEric Joyner  * Create a large action to hold software marker and update the switch rule
136471d10453SEric Joyner  * entry pointed by m_ent with newly created large action
136571d10453SEric Joyner  */
1366*f2635e84SEric Joyner static int
136771d10453SEric Joyner ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
136871d10453SEric Joyner 		   u16 sw_marker, u16 l_id)
136971d10453SEric Joyner {
13709c30461dSEric Joyner 	struct ice_sw_rule_lkup_rx_tx *rx_tx;
13719c30461dSEric Joyner 	struct ice_sw_rule_lg_act *lg_act;
137271d10453SEric Joyner 	/* For software marker we need 3 large actions
137371d10453SEric Joyner 	 * 1. FWD action: FWD TO VSI or VSI LIST
137471d10453SEric Joyner 	 * 2. GENERIC VALUE action to hold the profile ID
137571d10453SEric Joyner 	 * 3. GENERIC VALUE action to hold the software marker ID
137671d10453SEric Joyner 	 */
137771d10453SEric Joyner 	const u16 num_lg_acts = 3;
137871d10453SEric Joyner 	u16 lg_act_size;
137971d10453SEric Joyner 	u16 rules_size;
1380*f2635e84SEric Joyner 	int status;
138171d10453SEric Joyner 	u32 act;
138271d10453SEric Joyner 	u16 id;
138371d10453SEric Joyner 
138471d10453SEric Joyner 	if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
138571d10453SEric Joyner 		return ICE_ERR_PARAM;
138671d10453SEric Joyner 
138771d10453SEric Joyner 	/* Create two back-to-back switch rules and submit them to the HW using
138871d10453SEric Joyner 	 * one memory buffer:
138971d10453SEric Joyner 	 *    1. Large Action
139071d10453SEric Joyner 	 *    2. Look up Tx Rx
139171d10453SEric Joyner 	 */
13929c30461dSEric Joyner 	lg_act_size = (u16)ice_struct_size(lg_act, act, num_lg_acts);
13939c30461dSEric Joyner 	rules_size = lg_act_size +
13949c30461dSEric Joyner 		     ice_struct_size(rx_tx, hdr_data, DUMMY_ETH_HDR_LEN);
13959c30461dSEric Joyner 	lg_act = (struct ice_sw_rule_lg_act *)ice_malloc(hw, rules_size);
139671d10453SEric Joyner 	if (!lg_act)
139771d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
139871d10453SEric Joyner 
13999c30461dSEric Joyner 	rx_tx = (struct ice_sw_rule_lkup_rx_tx *)((u8 *)lg_act + lg_act_size);
140071d10453SEric Joyner 
140171d10453SEric Joyner 	/* Fill in the first switch rule i.e. large action */
14029c30461dSEric Joyner 	lg_act->hdr.type = CPU_TO_LE16(ICE_AQC_SW_RULES_T_LG_ACT);
14039c30461dSEric Joyner 	lg_act->index = CPU_TO_LE16(l_id);
14049c30461dSEric Joyner 	lg_act->size = CPU_TO_LE16(num_lg_acts);
140571d10453SEric Joyner 
140671d10453SEric Joyner 	/* First action VSI forwarding or VSI list forwarding depending on how
140771d10453SEric Joyner 	 * many VSIs
140871d10453SEric Joyner 	 */
140971d10453SEric Joyner 	id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id :
141071d10453SEric Joyner 		m_ent->fltr_info.fwd_id.hw_vsi_id;
141171d10453SEric Joyner 
141271d10453SEric Joyner 	act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
14137d7af7f8SEric Joyner 	act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M;
141471d10453SEric Joyner 	if (m_ent->vsi_count > 1)
141571d10453SEric Joyner 		act |= ICE_LG_ACT_VSI_LIST;
14169c30461dSEric Joyner 	lg_act->act[0] = CPU_TO_LE32(act);
141771d10453SEric Joyner 
141871d10453SEric Joyner 	/* Second action descriptor type */
141971d10453SEric Joyner 	act = ICE_LG_ACT_GENERIC;
142071d10453SEric Joyner 
142171d10453SEric Joyner 	act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;
14229c30461dSEric Joyner 	lg_act->act[1] = CPU_TO_LE32(act);
142371d10453SEric Joyner 
142471d10453SEric Joyner 	act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<
142571d10453SEric Joyner 	       ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;
142671d10453SEric Joyner 
142771d10453SEric Joyner 	/* Third action Marker value */
142871d10453SEric Joyner 	act |= ICE_LG_ACT_GENERIC;
142971d10453SEric Joyner 	act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &
143071d10453SEric Joyner 		ICE_LG_ACT_GENERIC_VALUE_M;
143171d10453SEric Joyner 
14329c30461dSEric Joyner 	lg_act->act[2] = CPU_TO_LE32(act);
143371d10453SEric Joyner 
143471d10453SEric Joyner 	/* call the fill switch rule to fill the lookup Tx Rx structure */
143571d10453SEric Joyner 	ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx,
143671d10453SEric Joyner 			 ice_aqc_opc_update_sw_rules);
143771d10453SEric Joyner 
143871d10453SEric Joyner 	/* Update the action to point to the large action ID */
14399c30461dSEric Joyner 	rx_tx->act = CPU_TO_LE32(ICE_SINGLE_ACT_PTR |
144071d10453SEric Joyner 				 ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &
144171d10453SEric Joyner 				  ICE_SINGLE_ACT_PTR_VAL_M));
144271d10453SEric Joyner 
144371d10453SEric Joyner 	/* Use the filter rule ID of the previously created rule with single
144471d10453SEric Joyner 	 * act. Once the update happens, hardware will treat this as large
144571d10453SEric Joyner 	 * action
144671d10453SEric Joyner 	 */
14479c30461dSEric Joyner 	rx_tx->index = CPU_TO_LE16(m_ent->fltr_info.fltr_rule_id);
144871d10453SEric Joyner 
144971d10453SEric Joyner 	status = ice_aq_sw_rules(hw, lg_act, rules_size, 2,
145071d10453SEric Joyner 				 ice_aqc_opc_update_sw_rules, NULL);
145171d10453SEric Joyner 	if (!status) {
145271d10453SEric Joyner 		m_ent->lg_act_idx = l_id;
145371d10453SEric Joyner 		m_ent->sw_marker_id = sw_marker;
145471d10453SEric Joyner 	}
145571d10453SEric Joyner 
145671d10453SEric Joyner 	ice_free(hw, lg_act);
145771d10453SEric Joyner 	return status;
145871d10453SEric Joyner }
145971d10453SEric Joyner 
146071d10453SEric Joyner /**
146171d10453SEric Joyner  * ice_add_counter_act - add/update filter rule with counter action
146271d10453SEric Joyner  * @hw: pointer to the hardware structure
146371d10453SEric Joyner  * @m_ent: the management entry for which counter needs to be added
146471d10453SEric Joyner  * @counter_id: VLAN counter ID returned as part of allocate resource
146571d10453SEric Joyner  * @l_id: large action resource ID
146671d10453SEric Joyner  */
1467*f2635e84SEric Joyner static int
146871d10453SEric Joyner ice_add_counter_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
146971d10453SEric Joyner 		    u16 counter_id, u16 l_id)
147071d10453SEric Joyner {
14719c30461dSEric Joyner 	struct ice_sw_rule_lkup_rx_tx *rx_tx;
14729c30461dSEric Joyner 	struct ice_sw_rule_lg_act *lg_act;
147371d10453SEric Joyner 	/* 2 actions will be added while adding a large action counter */
147471d10453SEric Joyner 	const int num_acts = 2;
147571d10453SEric Joyner 	u16 lg_act_size;
147671d10453SEric Joyner 	u16 rules_size;
147771d10453SEric Joyner 	u16 f_rule_id;
147871d10453SEric Joyner 	u32 act;
1479*f2635e84SEric Joyner 	int status;
148071d10453SEric Joyner 	u16 id;
148171d10453SEric Joyner 
148271d10453SEric Joyner 	if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
148371d10453SEric Joyner 		return ICE_ERR_PARAM;
148471d10453SEric Joyner 
148571d10453SEric Joyner 	/* Create two back-to-back switch rules and submit them to the HW using
148671d10453SEric Joyner 	 * one memory buffer:
148771d10453SEric Joyner 	 * 1. Large Action
148871d10453SEric Joyner 	 * 2. Look up Tx Rx
148971d10453SEric Joyner 	 */
14909c30461dSEric Joyner 	lg_act_size = (u16)ice_struct_size(lg_act, act, num_acts);
14919c30461dSEric Joyner 	rules_size = lg_act_size +
14929c30461dSEric Joyner 		     ice_struct_size(rx_tx, hdr_data, DUMMY_ETH_HDR_LEN);
14939c30461dSEric Joyner 	lg_act = (struct ice_sw_rule_lg_act *)ice_malloc(hw, rules_size);
149471d10453SEric Joyner 	if (!lg_act)
149571d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
149671d10453SEric Joyner 
14979c30461dSEric Joyner 	rx_tx = (struct ice_sw_rule_lkup_rx_tx *)((u8 *)lg_act +
14989c30461dSEric Joyner 						      lg_act_size);
149971d10453SEric Joyner 
150071d10453SEric Joyner 	/* Fill in the first switch rule i.e. large action */
15019c30461dSEric Joyner 	lg_act->hdr.type = CPU_TO_LE16(ICE_AQC_SW_RULES_T_LG_ACT);
15029c30461dSEric Joyner 	lg_act->index = CPU_TO_LE16(l_id);
15039c30461dSEric Joyner 	lg_act->size = CPU_TO_LE16(num_acts);
150471d10453SEric Joyner 
150571d10453SEric Joyner 	/* First action VSI forwarding or VSI list forwarding depending on how
150671d10453SEric Joyner 	 * many VSIs
150771d10453SEric Joyner 	 */
150871d10453SEric Joyner 	id = (m_ent->vsi_count > 1) ?  m_ent->fltr_info.fwd_id.vsi_list_id :
150971d10453SEric Joyner 		m_ent->fltr_info.fwd_id.hw_vsi_id;
151071d10453SEric Joyner 
151171d10453SEric Joyner 	act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
151271d10453SEric Joyner 	act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) &
151371d10453SEric Joyner 		ICE_LG_ACT_VSI_LIST_ID_M;
151471d10453SEric Joyner 	if (m_ent->vsi_count > 1)
151571d10453SEric Joyner 		act |= ICE_LG_ACT_VSI_LIST;
15169c30461dSEric Joyner 	lg_act->act[0] = CPU_TO_LE32(act);
151771d10453SEric Joyner 
151871d10453SEric Joyner 	/* Second action counter ID */
151971d10453SEric Joyner 	act = ICE_LG_ACT_STAT_COUNT;
152071d10453SEric Joyner 	act |= (counter_id << ICE_LG_ACT_STAT_COUNT_S) &
152171d10453SEric Joyner 		ICE_LG_ACT_STAT_COUNT_M;
15229c30461dSEric Joyner 	lg_act->act[1] = CPU_TO_LE32(act);
152371d10453SEric Joyner 
152471d10453SEric Joyner 	/* call the fill switch rule to fill the lookup Tx Rx structure */
152571d10453SEric Joyner 	ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx,
152671d10453SEric Joyner 			 ice_aqc_opc_update_sw_rules);
152771d10453SEric Joyner 
152871d10453SEric Joyner 	act = ICE_SINGLE_ACT_PTR;
152971d10453SEric Joyner 	act |= (l_id << ICE_SINGLE_ACT_PTR_VAL_S) & ICE_SINGLE_ACT_PTR_VAL_M;
15309c30461dSEric Joyner 	rx_tx->act = CPU_TO_LE32(act);
153171d10453SEric Joyner 
153271d10453SEric Joyner 	/* Use the filter rule ID of the previously created rule with single
153371d10453SEric Joyner 	 * act. Once the update happens, hardware will treat this as large
153471d10453SEric Joyner 	 * action
153571d10453SEric Joyner 	 */
153671d10453SEric Joyner 	f_rule_id = m_ent->fltr_info.fltr_rule_id;
15379c30461dSEric Joyner 	rx_tx->index = CPU_TO_LE16(f_rule_id);
153871d10453SEric Joyner 
153971d10453SEric Joyner 	status = ice_aq_sw_rules(hw, lg_act, rules_size, 2,
154071d10453SEric Joyner 				 ice_aqc_opc_update_sw_rules, NULL);
154171d10453SEric Joyner 	if (!status) {
154271d10453SEric Joyner 		m_ent->lg_act_idx = l_id;
15438923de59SPiotr Kubaj 		m_ent->counter_index = (u8)counter_id;
154471d10453SEric Joyner 	}
154571d10453SEric Joyner 
154671d10453SEric Joyner 	ice_free(hw, lg_act);
154771d10453SEric Joyner 	return status;
154871d10453SEric Joyner }
154971d10453SEric Joyner 
155071d10453SEric Joyner /**
155171d10453SEric Joyner  * ice_create_vsi_list_map
155271d10453SEric Joyner  * @hw: pointer to the hardware structure
155371d10453SEric Joyner  * @vsi_handle_arr: array of VSI handles to set in the VSI mapping
155471d10453SEric Joyner  * @num_vsi: number of VSI handles in the array
155571d10453SEric Joyner  * @vsi_list_id: VSI list ID generated as part of allocate resource
155671d10453SEric Joyner  *
155771d10453SEric Joyner  * Helper function to create a new entry of VSI list ID to VSI mapping
155871d10453SEric Joyner  * using the given VSI list ID
155971d10453SEric Joyner  */
156071d10453SEric Joyner static struct ice_vsi_list_map_info *
156171d10453SEric Joyner ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
156271d10453SEric Joyner 			u16 vsi_list_id)
156371d10453SEric Joyner {
156471d10453SEric Joyner 	struct ice_switch_info *sw = hw->switch_info;
156571d10453SEric Joyner 	struct ice_vsi_list_map_info *v_map;
156671d10453SEric Joyner 	int i;
156771d10453SEric Joyner 
1568d08b8680SEric Joyner 	v_map = (struct ice_vsi_list_map_info *)ice_malloc(hw, sizeof(*v_map));
156971d10453SEric Joyner 	if (!v_map)
157071d10453SEric Joyner 		return NULL;
157171d10453SEric Joyner 
157271d10453SEric Joyner 	v_map->vsi_list_id = vsi_list_id;
157371d10453SEric Joyner 	v_map->ref_cnt = 1;
157471d10453SEric Joyner 	for (i = 0; i < num_vsi; i++)
157571d10453SEric Joyner 		ice_set_bit(vsi_handle_arr[i], v_map->vsi_map);
157671d10453SEric Joyner 
157771d10453SEric Joyner 	LIST_ADD(&v_map->list_entry, &sw->vsi_list_map_head);
157871d10453SEric Joyner 	return v_map;
157971d10453SEric Joyner }
158071d10453SEric Joyner 
158171d10453SEric Joyner /**
158271d10453SEric Joyner  * ice_update_vsi_list_rule
158371d10453SEric Joyner  * @hw: pointer to the hardware structure
158471d10453SEric Joyner  * @vsi_handle_arr: array of VSI handles to form a VSI list
158571d10453SEric Joyner  * @num_vsi: number of VSI handles in the array
158671d10453SEric Joyner  * @vsi_list_id: VSI list ID generated as part of allocate resource
158771d10453SEric Joyner  * @remove: Boolean value to indicate if this is a remove action
158871d10453SEric Joyner  * @opc: switch rules population command type - pass in the command opcode
158971d10453SEric Joyner  * @lkup_type: lookup type of the filter
159071d10453SEric Joyner  *
159171d10453SEric Joyner  * Call AQ command to add a new switch rule or update existing switch rule
159271d10453SEric Joyner  * using the given VSI list ID
159371d10453SEric Joyner  */
1594*f2635e84SEric Joyner static int
159571d10453SEric Joyner ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
159671d10453SEric Joyner 			 u16 vsi_list_id, bool remove, enum ice_adminq_opc opc,
159771d10453SEric Joyner 			 enum ice_sw_lkup_type lkup_type)
159871d10453SEric Joyner {
15999c30461dSEric Joyner 	struct ice_sw_rule_vsi_list *s_rule;
160071d10453SEric Joyner 	u16 s_rule_size;
160171d10453SEric Joyner 	u16 rule_type;
1602*f2635e84SEric Joyner 	int status;
160371d10453SEric Joyner 	int i;
160471d10453SEric Joyner 
160571d10453SEric Joyner 	if (!num_vsi)
160671d10453SEric Joyner 		return ICE_ERR_PARAM;
160771d10453SEric Joyner 
160871d10453SEric Joyner 	if (lkup_type == ICE_SW_LKUP_MAC ||
160971d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
161071d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
161171d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
161271d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_PROMISC ||
161371d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
16148923de59SPiotr Kubaj 	    lkup_type == ICE_SW_LKUP_DFLT ||
161571d10453SEric Joyner 	    lkup_type == ICE_SW_LKUP_LAST)
161671d10453SEric Joyner 		rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR :
161771d10453SEric Joyner 			ICE_AQC_SW_RULES_T_VSI_LIST_SET;
161871d10453SEric Joyner 	else if (lkup_type == ICE_SW_LKUP_VLAN)
161971d10453SEric Joyner 		rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR :
162071d10453SEric Joyner 			ICE_AQC_SW_RULES_T_PRUNE_LIST_SET;
162171d10453SEric Joyner 	else
162271d10453SEric Joyner 		return ICE_ERR_PARAM;
162371d10453SEric Joyner 
16249c30461dSEric Joyner 	s_rule_size = (u16)ice_struct_size(s_rule, vsi, num_vsi);
16259c30461dSEric Joyner 	s_rule = (struct ice_sw_rule_vsi_list *)ice_malloc(hw, s_rule_size);
162671d10453SEric Joyner 	if (!s_rule)
162771d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
162871d10453SEric Joyner 	for (i = 0; i < num_vsi; i++) {
162971d10453SEric Joyner 		if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) {
163071d10453SEric Joyner 			status = ICE_ERR_PARAM;
163171d10453SEric Joyner 			goto exit;
163271d10453SEric Joyner 		}
163371d10453SEric Joyner 		/* AQ call requires hw_vsi_id(s) */
16349c30461dSEric Joyner 		s_rule->vsi[i] =
163571d10453SEric Joyner 			CPU_TO_LE16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i]));
163671d10453SEric Joyner 	}
163771d10453SEric Joyner 
16389c30461dSEric Joyner 	s_rule->hdr.type = CPU_TO_LE16(rule_type);
16399c30461dSEric Joyner 	s_rule->number_vsi = CPU_TO_LE16(num_vsi);
16409c30461dSEric Joyner 	s_rule->index = CPU_TO_LE16(vsi_list_id);
164171d10453SEric Joyner 
164271d10453SEric Joyner 	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL);
164371d10453SEric Joyner 
164471d10453SEric Joyner exit:
164571d10453SEric Joyner 	ice_free(hw, s_rule);
164671d10453SEric Joyner 	return status;
164771d10453SEric Joyner }
164871d10453SEric Joyner 
164971d10453SEric Joyner /**
165071d10453SEric Joyner  * ice_create_vsi_list_rule - Creates and populates a VSI list rule
165171d10453SEric Joyner  * @hw: pointer to the HW struct
165271d10453SEric Joyner  * @vsi_handle_arr: array of VSI handles to form a VSI list
165371d10453SEric Joyner  * @num_vsi: number of VSI handles in the array
165471d10453SEric Joyner  * @vsi_list_id: stores the ID of the VSI list to be created
165571d10453SEric Joyner  * @lkup_type: switch rule filter's lookup type
165671d10453SEric Joyner  */
1657*f2635e84SEric Joyner static int
165871d10453SEric Joyner ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
165971d10453SEric Joyner 			 u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type)
166071d10453SEric Joyner {
1661*f2635e84SEric Joyner 	int status;
166271d10453SEric Joyner 
166371d10453SEric Joyner 	status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type,
166471d10453SEric Joyner 					    ice_aqc_opc_alloc_res);
166571d10453SEric Joyner 	if (status)
166671d10453SEric Joyner 		return status;
166771d10453SEric Joyner 
166871d10453SEric Joyner 	/* Update the newly created VSI list to include the specified VSIs */
166971d10453SEric Joyner 	return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi,
167071d10453SEric Joyner 					*vsi_list_id, false,
167171d10453SEric Joyner 					ice_aqc_opc_add_sw_rules, lkup_type);
167271d10453SEric Joyner }
167371d10453SEric Joyner 
167471d10453SEric Joyner /**
167571d10453SEric Joyner  * ice_create_pkt_fwd_rule
167671d10453SEric Joyner  * @hw: pointer to the hardware structure
167771d10453SEric Joyner  * @recp_list: corresponding filter management list
167871d10453SEric Joyner  * @f_entry: entry containing packet forwarding information
167971d10453SEric Joyner  *
168071d10453SEric Joyner  * Create switch rule with given filter information and add an entry
168171d10453SEric Joyner  * to the corresponding filter management list to track this switch rule
168271d10453SEric Joyner  * and VSI mapping
168371d10453SEric Joyner  */
1684*f2635e84SEric Joyner static int
168571d10453SEric Joyner ice_create_pkt_fwd_rule(struct ice_hw *hw, struct ice_sw_recipe *recp_list,
168671d10453SEric Joyner 			struct ice_fltr_list_entry *f_entry)
168771d10453SEric Joyner {
168871d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *fm_entry;
16899c30461dSEric Joyner 	struct ice_sw_rule_lkup_rx_tx *s_rule;
1690*f2635e84SEric Joyner 	int status;
169171d10453SEric Joyner 
16929c30461dSEric Joyner 	s_rule = (struct ice_sw_rule_lkup_rx_tx *)
16939c30461dSEric Joyner 		ice_malloc(hw, ice_struct_size(s_rule, hdr_data,
16949c30461dSEric Joyner 					       DUMMY_ETH_HDR_LEN));
169571d10453SEric Joyner 	if (!s_rule)
169671d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
169771d10453SEric Joyner 	fm_entry = (struct ice_fltr_mgmt_list_entry *)
169871d10453SEric Joyner 		   ice_malloc(hw, sizeof(*fm_entry));
169971d10453SEric Joyner 	if (!fm_entry) {
170071d10453SEric Joyner 		status = ICE_ERR_NO_MEMORY;
170171d10453SEric Joyner 		goto ice_create_pkt_fwd_rule_exit;
170271d10453SEric Joyner 	}
170371d10453SEric Joyner 
170471d10453SEric Joyner 	fm_entry->fltr_info = f_entry->fltr_info;
170571d10453SEric Joyner 
170671d10453SEric Joyner 	/* Initialize all the fields for the management entry */
170771d10453SEric Joyner 	fm_entry->vsi_count = 1;
170871d10453SEric Joyner 	fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX;
170971d10453SEric Joyner 	fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID;
171071d10453SEric Joyner 	fm_entry->counter_index = ICE_INVAL_COUNTER_ID;
171171d10453SEric Joyner 
171271d10453SEric Joyner 	ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule,
171371d10453SEric Joyner 			 ice_aqc_opc_add_sw_rules);
171471d10453SEric Joyner 
17159c30461dSEric Joyner 	status = ice_aq_sw_rules(hw, s_rule,
17169c30461dSEric Joyner 				 ice_struct_size(s_rule, hdr_data,
17179c30461dSEric Joyner 						 DUMMY_ETH_HDR_LEN),
17189c30461dSEric Joyner 				 1, ice_aqc_opc_add_sw_rules, NULL);
171971d10453SEric Joyner 	if (status) {
172071d10453SEric Joyner 		ice_free(hw, fm_entry);
172171d10453SEric Joyner 		goto ice_create_pkt_fwd_rule_exit;
172271d10453SEric Joyner 	}
172371d10453SEric Joyner 
17249c30461dSEric Joyner 	f_entry->fltr_info.fltr_rule_id = LE16_TO_CPU(s_rule->index);
17259c30461dSEric Joyner 	fm_entry->fltr_info.fltr_rule_id = LE16_TO_CPU(s_rule->index);
172671d10453SEric Joyner 
172771d10453SEric Joyner 	/* The book keeping entries will get removed when base driver
172871d10453SEric Joyner 	 * calls remove filter AQ command
172971d10453SEric Joyner 	 */
173071d10453SEric Joyner 	LIST_ADD(&fm_entry->list_entry, &recp_list->filt_rules);
173171d10453SEric Joyner 
173271d10453SEric Joyner ice_create_pkt_fwd_rule_exit:
173371d10453SEric Joyner 	ice_free(hw, s_rule);
173471d10453SEric Joyner 	return status;
173571d10453SEric Joyner }
173671d10453SEric Joyner 
173771d10453SEric Joyner /**
173871d10453SEric Joyner  * ice_update_pkt_fwd_rule
173971d10453SEric Joyner  * @hw: pointer to the hardware structure
174071d10453SEric Joyner  * @f_info: filter information for switch rule
174171d10453SEric Joyner  *
174271d10453SEric Joyner  * Call AQ command to update a previously created switch rule with a
174371d10453SEric Joyner  * VSI list ID
174471d10453SEric Joyner  */
1745*f2635e84SEric Joyner static int
174671d10453SEric Joyner ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)
174771d10453SEric Joyner {
17489c30461dSEric Joyner 	struct ice_sw_rule_lkup_rx_tx *s_rule;
1749*f2635e84SEric Joyner 	int status;
175071d10453SEric Joyner 
17519c30461dSEric Joyner 	s_rule = (struct ice_sw_rule_lkup_rx_tx *)
17529c30461dSEric Joyner 		ice_malloc(hw, ice_struct_size(s_rule, hdr_data,
17539c30461dSEric Joyner 					       DUMMY_ETH_HDR_LEN));
175471d10453SEric Joyner 	if (!s_rule)
175571d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
175671d10453SEric Joyner 
175771d10453SEric Joyner 	ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules);
175871d10453SEric Joyner 
17599c30461dSEric Joyner 	s_rule->index = CPU_TO_LE16(f_info->fltr_rule_id);
176071d10453SEric Joyner 
176171d10453SEric Joyner 	/* Update switch rule with new rule set to forward VSI list */
17629c30461dSEric Joyner 	status = ice_aq_sw_rules(hw, s_rule,
17639c30461dSEric Joyner 				 ice_struct_size(s_rule, hdr_data,
17649c30461dSEric Joyner 						 DUMMY_ETH_HDR_LEN),
17659c30461dSEric Joyner 				 1, ice_aqc_opc_update_sw_rules, NULL);
176671d10453SEric Joyner 
176771d10453SEric Joyner 	ice_free(hw, s_rule);
176871d10453SEric Joyner 	return status;
176971d10453SEric Joyner }
177071d10453SEric Joyner 
177171d10453SEric Joyner /**
177271d10453SEric Joyner  * ice_update_sw_rule_bridge_mode
177371d10453SEric Joyner  * @hw: pointer to the HW struct
177471d10453SEric Joyner  *
177571d10453SEric Joyner  * Updates unicast switch filter rules based on VEB/VEPA mode
177671d10453SEric Joyner  */
1777*f2635e84SEric Joyner int ice_update_sw_rule_bridge_mode(struct ice_hw *hw)
177871d10453SEric Joyner {
177971d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *fm_entry;
178071d10453SEric Joyner 	struct LIST_HEAD_TYPE *rule_head;
178171d10453SEric Joyner 	struct ice_lock *rule_lock; /* Lock to protect filter rule list */
1782*f2635e84SEric Joyner 	struct ice_switch_info *sw;
1783*f2635e84SEric Joyner 	int status = 0;
1784*f2635e84SEric Joyner 
17858923de59SPiotr Kubaj 	sw = hw->switch_info;
178671d10453SEric Joyner 
178771d10453SEric Joyner 	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
178871d10453SEric Joyner 	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
178971d10453SEric Joyner 
179071d10453SEric Joyner 	ice_acquire_lock(rule_lock);
179171d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(fm_entry, rule_head, ice_fltr_mgmt_list_entry,
179271d10453SEric Joyner 			    list_entry) {
179371d10453SEric Joyner 		struct ice_fltr_info *fi = &fm_entry->fltr_info;
179471d10453SEric Joyner 		u8 *addr = fi->l_data.mac.mac_addr;
179571d10453SEric Joyner 
179671d10453SEric Joyner 		/* Update unicast Tx rules to reflect the selected
179771d10453SEric Joyner 		 * VEB/VEPA mode
179871d10453SEric Joyner 		 */
179971d10453SEric Joyner 		if ((fi->flag & ICE_FLTR_TX) && IS_UNICAST_ETHER_ADDR(addr) &&
180071d10453SEric Joyner 		    (fi->fltr_act == ICE_FWD_TO_VSI ||
180171d10453SEric Joyner 		     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
180271d10453SEric Joyner 		     fi->fltr_act == ICE_FWD_TO_Q ||
180371d10453SEric Joyner 		     fi->fltr_act == ICE_FWD_TO_QGRP)) {
180471d10453SEric Joyner 			status = ice_update_pkt_fwd_rule(hw, fi);
180571d10453SEric Joyner 			if (status)
180671d10453SEric Joyner 				break;
180771d10453SEric Joyner 		}
180871d10453SEric Joyner 	}
180971d10453SEric Joyner 
181071d10453SEric Joyner 	ice_release_lock(rule_lock);
181171d10453SEric Joyner 
181271d10453SEric Joyner 	return status;
181371d10453SEric Joyner }
181471d10453SEric Joyner 
181571d10453SEric Joyner /**
181671d10453SEric Joyner  * ice_add_update_vsi_list
181771d10453SEric Joyner  * @hw: pointer to the hardware structure
181871d10453SEric Joyner  * @m_entry: pointer to current filter management list entry
181971d10453SEric Joyner  * @cur_fltr: filter information from the book keeping entry
182071d10453SEric Joyner  * @new_fltr: filter information with the new VSI to be added
182171d10453SEric Joyner  *
182271d10453SEric Joyner  * Call AQ command to add or update previously created VSI list with new VSI.
182371d10453SEric Joyner  *
182471d10453SEric Joyner  * Helper function to do book keeping associated with adding filter information
182571d10453SEric Joyner  * The algorithm to do the book keeping is described below :
182671d10453SEric Joyner  * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.)
182771d10453SEric Joyner  *	if only one VSI has been added till now
182871d10453SEric Joyner  *		Allocate a new VSI list and add two VSIs
182971d10453SEric Joyner  *		to this list using switch rule command
183071d10453SEric Joyner  *		Update the previously created switch rule with the
183171d10453SEric Joyner  *		newly created VSI list ID
183271d10453SEric Joyner  *	if a VSI list was previously created
183371d10453SEric Joyner  *		Add the new VSI to the previously created VSI list set
183471d10453SEric Joyner  *		using the update switch rule command
183571d10453SEric Joyner  */
1836*f2635e84SEric Joyner static int
183771d10453SEric Joyner ice_add_update_vsi_list(struct ice_hw *hw,
183871d10453SEric Joyner 			struct ice_fltr_mgmt_list_entry *m_entry,
183971d10453SEric Joyner 			struct ice_fltr_info *cur_fltr,
184071d10453SEric Joyner 			struct ice_fltr_info *new_fltr)
184171d10453SEric Joyner {
184271d10453SEric Joyner 	u16 vsi_list_id = 0;
1843*f2635e84SEric Joyner 	int status = 0;
1844*f2635e84SEric Joyner 
184571d10453SEric Joyner 	if ((cur_fltr->fltr_act == ICE_FWD_TO_Q ||
184671d10453SEric Joyner 	     cur_fltr->fltr_act == ICE_FWD_TO_QGRP))
184771d10453SEric Joyner 		return ICE_ERR_NOT_IMPL;
184871d10453SEric Joyner 
184971d10453SEric Joyner 	if ((new_fltr->fltr_act == ICE_FWD_TO_Q ||
185071d10453SEric Joyner 	     new_fltr->fltr_act == ICE_FWD_TO_QGRP) &&
185171d10453SEric Joyner 	    (cur_fltr->fltr_act == ICE_FWD_TO_VSI ||
185271d10453SEric Joyner 	     cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST))
185371d10453SEric Joyner 		return ICE_ERR_NOT_IMPL;
185471d10453SEric Joyner 
185571d10453SEric Joyner 	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
185671d10453SEric Joyner 		/* Only one entry existed in the mapping and it was not already
185771d10453SEric Joyner 		 * a part of a VSI list. So, create a VSI list with the old and
185871d10453SEric Joyner 		 * new VSIs.
185971d10453SEric Joyner 		 */
186071d10453SEric Joyner 		struct ice_fltr_info tmp_fltr;
186171d10453SEric Joyner 		u16 vsi_handle_arr[2];
186271d10453SEric Joyner 
186371d10453SEric Joyner 		/* A rule already exists with the new VSI being added */
1864*f2635e84SEric Joyner 		if (cur_fltr->vsi_handle == new_fltr->vsi_handle)
186571d10453SEric Joyner 			return ICE_ERR_ALREADY_EXISTS;
186671d10453SEric Joyner 
186771d10453SEric Joyner 		vsi_handle_arr[0] = cur_fltr->vsi_handle;
186871d10453SEric Joyner 		vsi_handle_arr[1] = new_fltr->vsi_handle;
186971d10453SEric Joyner 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
187071d10453SEric Joyner 						  &vsi_list_id,
187171d10453SEric Joyner 						  new_fltr->lkup_type);
187271d10453SEric Joyner 		if (status)
187371d10453SEric Joyner 			return status;
187471d10453SEric Joyner 
187571d10453SEric Joyner 		tmp_fltr = *new_fltr;
187671d10453SEric Joyner 		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
187771d10453SEric Joyner 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
187871d10453SEric Joyner 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
187971d10453SEric Joyner 		/* Update the previous switch rule of "MAC forward to VSI" to
188071d10453SEric Joyner 		 * "MAC fwd to VSI list"
188171d10453SEric Joyner 		 */
188271d10453SEric Joyner 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
188371d10453SEric Joyner 		if (status)
188471d10453SEric Joyner 			return status;
188571d10453SEric Joyner 
188671d10453SEric Joyner 		cur_fltr->fwd_id.vsi_list_id = vsi_list_id;
188771d10453SEric Joyner 		cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
188871d10453SEric Joyner 		m_entry->vsi_list_info =
188971d10453SEric Joyner 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
189071d10453SEric Joyner 						vsi_list_id);
189171d10453SEric Joyner 
18929cf1841cSEric Joyner 		if (!m_entry->vsi_list_info)
18939cf1841cSEric Joyner 			return ICE_ERR_NO_MEMORY;
18949cf1841cSEric Joyner 
189571d10453SEric Joyner 		/* If this entry was large action then the large action needs
189671d10453SEric Joyner 		 * to be updated to point to FWD to VSI list
189771d10453SEric Joyner 		 */
189871d10453SEric Joyner 		if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID)
189971d10453SEric Joyner 			status =
190071d10453SEric Joyner 			    ice_add_marker_act(hw, m_entry,
190171d10453SEric Joyner 					       m_entry->sw_marker_id,
190271d10453SEric Joyner 					       m_entry->lg_act_idx);
190371d10453SEric Joyner 	} else {
190471d10453SEric Joyner 		u16 vsi_handle = new_fltr->vsi_handle;
190571d10453SEric Joyner 		enum ice_adminq_opc opcode;
190671d10453SEric Joyner 
190771d10453SEric Joyner 		if (!m_entry->vsi_list_info)
190871d10453SEric Joyner 			return ICE_ERR_CFG;
190971d10453SEric Joyner 
191071d10453SEric Joyner 		/* A rule already exists with the new VSI being added */
191171d10453SEric Joyner 		if (ice_is_bit_set(m_entry->vsi_list_info->vsi_map, vsi_handle))
1912*f2635e84SEric Joyner 			return ICE_ERR_ALREADY_EXISTS;
191371d10453SEric Joyner 
191471d10453SEric Joyner 		/* Update the previously created VSI list set with
191571d10453SEric Joyner 		 * the new VSI ID passed in
191671d10453SEric Joyner 		 */
191771d10453SEric Joyner 		vsi_list_id = cur_fltr->fwd_id.vsi_list_id;
191871d10453SEric Joyner 		opcode = ice_aqc_opc_update_sw_rules;
191971d10453SEric Joyner 
192071d10453SEric Joyner 		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
192171d10453SEric Joyner 						  vsi_list_id, false, opcode,
192271d10453SEric Joyner 						  new_fltr->lkup_type);
192371d10453SEric Joyner 		/* update VSI list mapping info with new VSI ID */
192471d10453SEric Joyner 		if (!status)
192571d10453SEric Joyner 			ice_set_bit(vsi_handle,
192671d10453SEric Joyner 				    m_entry->vsi_list_info->vsi_map);
192771d10453SEric Joyner 	}
192871d10453SEric Joyner 	if (!status)
192971d10453SEric Joyner 		m_entry->vsi_count++;
193071d10453SEric Joyner 	return status;
193171d10453SEric Joyner }
193271d10453SEric Joyner 
193371d10453SEric Joyner /**
193471d10453SEric Joyner  * ice_find_rule_entry - Search a rule entry
193571d10453SEric Joyner  * @list_head: head of rule list
193671d10453SEric Joyner  * @f_info: rule information
193771d10453SEric Joyner  *
193871d10453SEric Joyner  * Helper function to search for a given rule entry
193971d10453SEric Joyner  * Returns pointer to entry storing the rule if found
194071d10453SEric Joyner  */
194171d10453SEric Joyner static struct ice_fltr_mgmt_list_entry *
194271d10453SEric Joyner ice_find_rule_entry(struct LIST_HEAD_TYPE *list_head,
194371d10453SEric Joyner 		    struct ice_fltr_info *f_info)
194471d10453SEric Joyner {
194571d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL;
194671d10453SEric Joyner 
194771d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(list_itr, list_head, ice_fltr_mgmt_list_entry,
194871d10453SEric Joyner 			    list_entry) {
194971d10453SEric Joyner 		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
195071d10453SEric Joyner 			    sizeof(f_info->l_data)) &&
195171d10453SEric Joyner 		    f_info->flag == list_itr->fltr_info.flag) {
195271d10453SEric Joyner 			ret = list_itr;
195371d10453SEric Joyner 			break;
195471d10453SEric Joyner 		}
195571d10453SEric Joyner 	}
195671d10453SEric Joyner 	return ret;
195771d10453SEric Joyner }
195871d10453SEric Joyner 
195971d10453SEric Joyner /**
196071d10453SEric Joyner  * ice_find_vsi_list_entry - Search VSI list map with VSI count 1
196171d10453SEric Joyner  * @recp_list: VSI lists needs to be searched
196271d10453SEric Joyner  * @vsi_handle: VSI handle to be found in VSI list
196371d10453SEric Joyner  * @vsi_list_id: VSI list ID found containing vsi_handle
196471d10453SEric Joyner  *
196571d10453SEric Joyner  * Helper function to search a VSI list with single entry containing given VSI
196671d10453SEric Joyner  * handle element. This can be extended further to search VSI list with more
196771d10453SEric Joyner  * than 1 vsi_count. Returns pointer to VSI list entry if found.
196871d10453SEric Joyner  */
19698923de59SPiotr Kubaj struct ice_vsi_list_map_info *
197071d10453SEric Joyner ice_find_vsi_list_entry(struct ice_sw_recipe *recp_list, u16 vsi_handle,
197171d10453SEric Joyner 			u16 *vsi_list_id)
197271d10453SEric Joyner {
197371d10453SEric Joyner 	struct ice_vsi_list_map_info *map_info = NULL;
197471d10453SEric Joyner 	struct LIST_HEAD_TYPE *list_head;
197571d10453SEric Joyner 
197671d10453SEric Joyner 	list_head = &recp_list->filt_rules;
197771d10453SEric Joyner 	if (recp_list->adv_rule) {
197871d10453SEric Joyner 		struct ice_adv_fltr_mgmt_list_entry *list_itr;
197971d10453SEric Joyner 
198071d10453SEric Joyner 		LIST_FOR_EACH_ENTRY(list_itr, list_head,
198171d10453SEric Joyner 				    ice_adv_fltr_mgmt_list_entry,
198271d10453SEric Joyner 				    list_entry) {
198371d10453SEric Joyner 			if (list_itr->vsi_list_info) {
198471d10453SEric Joyner 				map_info = list_itr->vsi_list_info;
198571d10453SEric Joyner 				if (ice_is_bit_set(map_info->vsi_map,
198671d10453SEric Joyner 						   vsi_handle)) {
198771d10453SEric Joyner 					*vsi_list_id = map_info->vsi_list_id;
198871d10453SEric Joyner 					return map_info;
198971d10453SEric Joyner 				}
199071d10453SEric Joyner 			}
199171d10453SEric Joyner 		}
199271d10453SEric Joyner 	} else {
199371d10453SEric Joyner 		struct ice_fltr_mgmt_list_entry *list_itr;
199471d10453SEric Joyner 
199571d10453SEric Joyner 		LIST_FOR_EACH_ENTRY(list_itr, list_head,
199671d10453SEric Joyner 				    ice_fltr_mgmt_list_entry,
199771d10453SEric Joyner 				    list_entry) {
199871d10453SEric Joyner 			if (list_itr->vsi_count == 1 &&
199971d10453SEric Joyner 			    list_itr->vsi_list_info) {
200071d10453SEric Joyner 				map_info = list_itr->vsi_list_info;
200171d10453SEric Joyner 				if (ice_is_bit_set(map_info->vsi_map,
200271d10453SEric Joyner 						   vsi_handle)) {
200371d10453SEric Joyner 					*vsi_list_id = map_info->vsi_list_id;
200471d10453SEric Joyner 					return map_info;
200571d10453SEric Joyner 				}
200671d10453SEric Joyner 			}
200771d10453SEric Joyner 		}
200871d10453SEric Joyner 	}
200971d10453SEric Joyner 	return NULL;
201071d10453SEric Joyner }
201171d10453SEric Joyner 
201271d10453SEric Joyner /**
201371d10453SEric Joyner  * ice_add_rule_internal - add rule for a given lookup type
201471d10453SEric Joyner  * @hw: pointer to the hardware structure
201571d10453SEric Joyner  * @recp_list: recipe list for which rule has to be added
201671d10453SEric Joyner  * @lport: logic port number on which function add rule
201771d10453SEric Joyner  * @f_entry: structure containing MAC forwarding information
201871d10453SEric Joyner  *
201971d10453SEric Joyner  * Adds or updates the rule lists for a given recipe
202071d10453SEric Joyner  */
2021*f2635e84SEric Joyner static int
202271d10453SEric Joyner ice_add_rule_internal(struct ice_hw *hw, struct ice_sw_recipe *recp_list,
202371d10453SEric Joyner 		      u8 lport, struct ice_fltr_list_entry *f_entry)
202471d10453SEric Joyner {
202571d10453SEric Joyner 	struct ice_fltr_info *new_fltr, *cur_fltr;
202671d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *m_entry;
202771d10453SEric Joyner 	struct ice_lock *rule_lock; /* Lock to protect filter rule list */
2028*f2635e84SEric Joyner 	int status = 0;
202971d10453SEric Joyner 
203071d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
203171d10453SEric Joyner 		return ICE_ERR_PARAM;
203271d10453SEric Joyner 
203371d10453SEric Joyner 	/* Load the hw_vsi_id only if the fwd action is fwd to VSI */
203471d10453SEric Joyner 	if (f_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI)
203571d10453SEric Joyner 		f_entry->fltr_info.fwd_id.hw_vsi_id =
203671d10453SEric Joyner 			ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
203771d10453SEric Joyner 
203871d10453SEric Joyner 	rule_lock = &recp_list->filt_rule_lock;
203971d10453SEric Joyner 
204071d10453SEric Joyner 	ice_acquire_lock(rule_lock);
204171d10453SEric Joyner 	new_fltr = &f_entry->fltr_info;
204271d10453SEric Joyner 	if (new_fltr->flag & ICE_FLTR_RX)
204371d10453SEric Joyner 		new_fltr->src = lport;
20449e54973fSEric Joyner 	else if (new_fltr->flag & (ICE_FLTR_TX | ICE_FLTR_RX_LB))
204571d10453SEric Joyner 		new_fltr->src =
204671d10453SEric Joyner 			ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
204771d10453SEric Joyner 
204871d10453SEric Joyner 	m_entry = ice_find_rule_entry(&recp_list->filt_rules, new_fltr);
204971d10453SEric Joyner 	if (!m_entry) {
205071d10453SEric Joyner 		status = ice_create_pkt_fwd_rule(hw, recp_list, f_entry);
205171d10453SEric Joyner 		goto exit_add_rule_internal;
205271d10453SEric Joyner 	}
205371d10453SEric Joyner 
205471d10453SEric Joyner 	cur_fltr = &m_entry->fltr_info;
205571d10453SEric Joyner 	status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr);
205671d10453SEric Joyner 
205771d10453SEric Joyner exit_add_rule_internal:
205871d10453SEric Joyner 	ice_release_lock(rule_lock);
205971d10453SEric Joyner 	return status;
206071d10453SEric Joyner }
206171d10453SEric Joyner 
206271d10453SEric Joyner /**
206371d10453SEric Joyner  * ice_remove_vsi_list_rule
206471d10453SEric Joyner  * @hw: pointer to the hardware structure
206571d10453SEric Joyner  * @vsi_list_id: VSI list ID generated as part of allocate resource
206671d10453SEric Joyner  * @lkup_type: switch rule filter lookup type
206771d10453SEric Joyner  *
206871d10453SEric Joyner  * The VSI list should be emptied before this function is called to remove the
206971d10453SEric Joyner  * VSI list.
207071d10453SEric Joyner  */
2071*f2635e84SEric Joyner static int
207271d10453SEric Joyner ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,
207371d10453SEric Joyner 			 enum ice_sw_lkup_type lkup_type)
207471d10453SEric Joyner {
207571d10453SEric Joyner 	/* Free the vsi_list resource that we allocated. It is assumed that the
207671d10453SEric Joyner 	 * list is empty at this point.
207771d10453SEric Joyner 	 */
20787d7af7f8SEric Joyner 	return ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,
207971d10453SEric Joyner 					    ice_aqc_opc_free_res);
208071d10453SEric Joyner }
208171d10453SEric Joyner 
208271d10453SEric Joyner /**
208371d10453SEric Joyner  * ice_rem_update_vsi_list
208471d10453SEric Joyner  * @hw: pointer to the hardware structure
208571d10453SEric Joyner  * @vsi_handle: VSI handle of the VSI to remove
208671d10453SEric Joyner  * @fm_list: filter management entry for which the VSI list management needs to
208771d10453SEric Joyner  *           be done
208871d10453SEric Joyner  */
2089*f2635e84SEric Joyner static int
209071d10453SEric Joyner ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
209171d10453SEric Joyner 			struct ice_fltr_mgmt_list_entry *fm_list)
209271d10453SEric Joyner {
209371d10453SEric Joyner 	enum ice_sw_lkup_type lkup_type;
209471d10453SEric Joyner 	u16 vsi_list_id;
2095*f2635e84SEric Joyner 	int status = 0;
209671d10453SEric Joyner 
209771d10453SEric Joyner 	if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST ||
209871d10453SEric Joyner 	    fm_list->vsi_count == 0)
209971d10453SEric Joyner 		return ICE_ERR_PARAM;
210071d10453SEric Joyner 
210171d10453SEric Joyner 	/* A rule with the VSI being removed does not exist */
210271d10453SEric Joyner 	if (!ice_is_bit_set(fm_list->vsi_list_info->vsi_map, vsi_handle))
210371d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
210471d10453SEric Joyner 
210571d10453SEric Joyner 	lkup_type = fm_list->fltr_info.lkup_type;
210671d10453SEric Joyner 	vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id;
210771d10453SEric Joyner 	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
210871d10453SEric Joyner 					  ice_aqc_opc_update_sw_rules,
210971d10453SEric Joyner 					  lkup_type);
211071d10453SEric Joyner 	if (status)
211171d10453SEric Joyner 		return status;
211271d10453SEric Joyner 
211371d10453SEric Joyner 	fm_list->vsi_count--;
211471d10453SEric Joyner 	ice_clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
211571d10453SEric Joyner 
211671d10453SEric Joyner 	if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) {
211771d10453SEric Joyner 		struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info;
211871d10453SEric Joyner 		struct ice_vsi_list_map_info *vsi_list_info =
211971d10453SEric Joyner 			fm_list->vsi_list_info;
212071d10453SEric Joyner 		u16 rem_vsi_handle;
212171d10453SEric Joyner 
212271d10453SEric Joyner 		rem_vsi_handle = ice_find_first_bit(vsi_list_info->vsi_map,
212371d10453SEric Joyner 						    ICE_MAX_VSI);
212471d10453SEric Joyner 		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
212571d10453SEric Joyner 			return ICE_ERR_OUT_OF_RANGE;
212671d10453SEric Joyner 
212771d10453SEric Joyner 		/* Make sure VSI list is empty before removing it below */
212871d10453SEric Joyner 		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
212971d10453SEric Joyner 						  vsi_list_id, true,
213071d10453SEric Joyner 						  ice_aqc_opc_update_sw_rules,
213171d10453SEric Joyner 						  lkup_type);
213271d10453SEric Joyner 		if (status)
213371d10453SEric Joyner 			return status;
213471d10453SEric Joyner 
213571d10453SEric Joyner 		tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI;
213671d10453SEric Joyner 		tmp_fltr_info.fwd_id.hw_vsi_id =
213771d10453SEric Joyner 			ice_get_hw_vsi_num(hw, rem_vsi_handle);
213871d10453SEric Joyner 		tmp_fltr_info.vsi_handle = rem_vsi_handle;
213971d10453SEric Joyner 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info);
214071d10453SEric Joyner 		if (status) {
21417d7af7f8SEric Joyner 			ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
214271d10453SEric Joyner 				  tmp_fltr_info.fwd_id.hw_vsi_id, status);
214371d10453SEric Joyner 			return status;
214471d10453SEric Joyner 		}
214571d10453SEric Joyner 
214671d10453SEric Joyner 		fm_list->fltr_info = tmp_fltr_info;
214771d10453SEric Joyner 	}
214871d10453SEric Joyner 
214971d10453SEric Joyner 	if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) ||
215071d10453SEric Joyner 	    (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) {
215171d10453SEric Joyner 		struct ice_vsi_list_map_info *vsi_list_info =
215271d10453SEric Joyner 			fm_list->vsi_list_info;
215371d10453SEric Joyner 
215471d10453SEric Joyner 		/* Remove the VSI list since it is no longer used */
215571d10453SEric Joyner 		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
215671d10453SEric Joyner 		if (status) {
21577d7af7f8SEric Joyner 			ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n",
215871d10453SEric Joyner 				  vsi_list_id, status);
215971d10453SEric Joyner 			return status;
216071d10453SEric Joyner 		}
216171d10453SEric Joyner 
216271d10453SEric Joyner 		LIST_DEL(&vsi_list_info->list_entry);
216371d10453SEric Joyner 		ice_free(hw, vsi_list_info);
216471d10453SEric Joyner 		fm_list->vsi_list_info = NULL;
216571d10453SEric Joyner 	}
216671d10453SEric Joyner 
216771d10453SEric Joyner 	return status;
216871d10453SEric Joyner }
216971d10453SEric Joyner 
217071d10453SEric Joyner /**
217171d10453SEric Joyner  * ice_remove_rule_internal - Remove a filter rule of a given type
217271d10453SEric Joyner  * @hw: pointer to the hardware structure
217371d10453SEric Joyner  * @recp_list: recipe list for which the rule needs to removed
217471d10453SEric Joyner  * @f_entry: rule entry containing filter information
217571d10453SEric Joyner  */
2176*f2635e84SEric Joyner static int
217771d10453SEric Joyner ice_remove_rule_internal(struct ice_hw *hw, struct ice_sw_recipe *recp_list,
217871d10453SEric Joyner 			 struct ice_fltr_list_entry *f_entry)
217971d10453SEric Joyner {
218071d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *list_elem;
218171d10453SEric Joyner 	struct ice_lock *rule_lock; /* Lock to protect filter rule list */
218271d10453SEric Joyner 	bool remove_rule = false;
2183*f2635e84SEric Joyner 	int status = 0;
218471d10453SEric Joyner 	u16 vsi_handle;
218571d10453SEric Joyner 
218671d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
218771d10453SEric Joyner 		return ICE_ERR_PARAM;
218871d10453SEric Joyner 	f_entry->fltr_info.fwd_id.hw_vsi_id =
218971d10453SEric Joyner 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
219071d10453SEric Joyner 
219171d10453SEric Joyner 	rule_lock = &recp_list->filt_rule_lock;
219271d10453SEric Joyner 	ice_acquire_lock(rule_lock);
2193*f2635e84SEric Joyner 
219471d10453SEric Joyner 	list_elem = ice_find_rule_entry(&recp_list->filt_rules,
219571d10453SEric Joyner 					&f_entry->fltr_info);
219671d10453SEric Joyner 	if (!list_elem) {
219771d10453SEric Joyner 		status = ICE_ERR_DOES_NOT_EXIST;
219871d10453SEric Joyner 		goto exit;
219971d10453SEric Joyner 	}
220071d10453SEric Joyner 
220171d10453SEric Joyner 	if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {
220271d10453SEric Joyner 		remove_rule = true;
220371d10453SEric Joyner 	} else if (!list_elem->vsi_list_info) {
220471d10453SEric Joyner 		status = ICE_ERR_DOES_NOT_EXIST;
220571d10453SEric Joyner 		goto exit;
220671d10453SEric Joyner 	} else if (list_elem->vsi_list_info->ref_cnt > 1) {
220771d10453SEric Joyner 		/* a ref_cnt > 1 indicates that the vsi_list is being
220871d10453SEric Joyner 		 * shared by multiple rules. Decrement the ref_cnt and
220971d10453SEric Joyner 		 * remove this rule, but do not modify the list, as it
221071d10453SEric Joyner 		 * is in-use by other rules.
221171d10453SEric Joyner 		 */
221271d10453SEric Joyner 		list_elem->vsi_list_info->ref_cnt--;
221371d10453SEric Joyner 		remove_rule = true;
221471d10453SEric Joyner 	} else {
221571d10453SEric Joyner 		/* a ref_cnt of 1 indicates the vsi_list is only used
221671d10453SEric Joyner 		 * by one rule. However, the original removal request is only
221771d10453SEric Joyner 		 * for a single VSI. Update the vsi_list first, and only
221871d10453SEric Joyner 		 * remove the rule if there are no further VSIs in this list.
221971d10453SEric Joyner 		 */
222071d10453SEric Joyner 		vsi_handle = f_entry->fltr_info.vsi_handle;
222171d10453SEric Joyner 		status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem);
222271d10453SEric Joyner 		if (status)
222371d10453SEric Joyner 			goto exit;
222471d10453SEric Joyner 		/* if VSI count goes to zero after updating the VSI list */
222571d10453SEric Joyner 		if (list_elem->vsi_count == 0)
222671d10453SEric Joyner 			remove_rule = true;
222771d10453SEric Joyner 	}
222871d10453SEric Joyner 
222971d10453SEric Joyner 	if (remove_rule) {
223071d10453SEric Joyner 		/* Remove the lookup rule */
22319c30461dSEric Joyner 		struct ice_sw_rule_lkup_rx_tx *s_rule;
223271d10453SEric Joyner 
22339c30461dSEric Joyner 		s_rule = (struct ice_sw_rule_lkup_rx_tx *)
22349c30461dSEric Joyner 			ice_malloc(hw, ice_struct_size(s_rule, hdr_data, 0));
223571d10453SEric Joyner 		if (!s_rule) {
223671d10453SEric Joyner 			status = ICE_ERR_NO_MEMORY;
223771d10453SEric Joyner 			goto exit;
223871d10453SEric Joyner 		}
223971d10453SEric Joyner 
224071d10453SEric Joyner 		ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule,
224171d10453SEric Joyner 				 ice_aqc_opc_remove_sw_rules);
224271d10453SEric Joyner 
224371d10453SEric Joyner 		status = ice_aq_sw_rules(hw, s_rule,
22449c30461dSEric Joyner 					 ice_struct_size(s_rule, hdr_data, 0),
22459c30461dSEric Joyner 					 1, ice_aqc_opc_remove_sw_rules, NULL);
224671d10453SEric Joyner 
224771d10453SEric Joyner 		/* Remove a book keeping from the list */
224871d10453SEric Joyner 		ice_free(hw, s_rule);
224971d10453SEric Joyner 
225071d10453SEric Joyner 		if (status)
225171d10453SEric Joyner 			goto exit;
225271d10453SEric Joyner 
225371d10453SEric Joyner 		LIST_DEL(&list_elem->list_entry);
225471d10453SEric Joyner 		ice_free(hw, list_elem);
225571d10453SEric Joyner 	}
225671d10453SEric Joyner exit:
225771d10453SEric Joyner 	ice_release_lock(rule_lock);
225871d10453SEric Joyner 	return status;
225971d10453SEric Joyner }
226071d10453SEric Joyner 
226171d10453SEric Joyner /**
226271d10453SEric Joyner  * ice_aq_get_res_alloc - get allocated resources
226371d10453SEric Joyner  * @hw: pointer to the HW struct
226471d10453SEric Joyner  * @num_entries: pointer to u16 to store the number of resource entries returned
22657d7af7f8SEric Joyner  * @buf: pointer to buffer
22667d7af7f8SEric Joyner  * @buf_size: size of buf
226771d10453SEric Joyner  * @cd: pointer to command details structure or NULL
226871d10453SEric Joyner  *
22697d7af7f8SEric Joyner  * The caller-supplied buffer must be large enough to store the resource
227071d10453SEric Joyner  * information for all resource types. Each resource type is an
22717d7af7f8SEric Joyner  * ice_aqc_get_res_resp_elem structure.
227271d10453SEric Joyner  */
2273*f2635e84SEric Joyner int
22747d7af7f8SEric Joyner ice_aq_get_res_alloc(struct ice_hw *hw, u16 *num_entries,
22757d7af7f8SEric Joyner 		     struct ice_aqc_get_res_resp_elem *buf, u16 buf_size,
22767d7af7f8SEric Joyner 		     struct ice_sq_cd *cd)
227771d10453SEric Joyner {
227871d10453SEric Joyner 	struct ice_aqc_get_res_alloc *resp;
227971d10453SEric Joyner 	struct ice_aq_desc desc;
2280*f2635e84SEric Joyner 	int status;
228171d10453SEric Joyner 
228271d10453SEric Joyner 	if (!buf)
228371d10453SEric Joyner 		return ICE_ERR_BAD_PTR;
228471d10453SEric Joyner 
228571d10453SEric Joyner 	if (buf_size < ICE_AQ_GET_RES_ALLOC_BUF_LEN)
228671d10453SEric Joyner 		return ICE_ERR_INVAL_SIZE;
228771d10453SEric Joyner 
228871d10453SEric Joyner 	resp = &desc.params.get_res;
228971d10453SEric Joyner 
229071d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_res_alloc);
229171d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
229271d10453SEric Joyner 
229371d10453SEric Joyner 	if (!status && num_entries)
229471d10453SEric Joyner 		*num_entries = LE16_TO_CPU(resp->resp_elem_num);
229571d10453SEric Joyner 
229671d10453SEric Joyner 	return status;
229771d10453SEric Joyner }
229871d10453SEric Joyner 
229971d10453SEric Joyner /**
230071d10453SEric Joyner  * ice_aq_get_res_descs - get allocated resource descriptors
230171d10453SEric Joyner  * @hw: pointer to the hardware structure
230271d10453SEric Joyner  * @num_entries: number of resource entries in buffer
23037d7af7f8SEric Joyner  * @buf: structure to hold response data buffer
23047d7af7f8SEric Joyner  * @buf_size: size of buffer
230571d10453SEric Joyner  * @res_type: resource type
230671d10453SEric Joyner  * @res_shared: is resource shared
230771d10453SEric Joyner  * @desc_id: input - first desc ID to start; output - next desc ID
230871d10453SEric Joyner  * @cd: pointer to command details structure or NULL
230971d10453SEric Joyner  */
2310*f2635e84SEric Joyner int
231171d10453SEric Joyner ice_aq_get_res_descs(struct ice_hw *hw, u16 num_entries,
23127d7af7f8SEric Joyner 		     struct ice_aqc_res_elem *buf, u16 buf_size, u16 res_type,
23137d7af7f8SEric Joyner 		     bool res_shared, u16 *desc_id, struct ice_sq_cd *cd)
231471d10453SEric Joyner {
231571d10453SEric Joyner 	struct ice_aqc_get_allocd_res_desc *cmd;
231671d10453SEric Joyner 	struct ice_aq_desc desc;
2317*f2635e84SEric Joyner 	int status;
231871d10453SEric Joyner 
231971d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
232071d10453SEric Joyner 
232171d10453SEric Joyner 	cmd = &desc.params.get_res_desc;
232271d10453SEric Joyner 
232371d10453SEric Joyner 	if (!buf)
232471d10453SEric Joyner 		return ICE_ERR_PARAM;
232571d10453SEric Joyner 
232671d10453SEric Joyner 	if (buf_size != (num_entries * sizeof(*buf)))
232771d10453SEric Joyner 		return ICE_ERR_PARAM;
232871d10453SEric Joyner 
232971d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_allocd_res_desc);
233071d10453SEric Joyner 
233171d10453SEric Joyner 	cmd->ops.cmd.res = CPU_TO_LE16(((res_type << ICE_AQC_RES_TYPE_S) &
233271d10453SEric Joyner 					 ICE_AQC_RES_TYPE_M) | (res_shared ?
233371d10453SEric Joyner 					ICE_AQC_RES_TYPE_FLAG_SHARED : 0));
233471d10453SEric Joyner 	cmd->ops.cmd.first_desc = CPU_TO_LE16(*desc_id);
233571d10453SEric Joyner 
233671d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
233771d10453SEric Joyner 	if (!status)
233871d10453SEric Joyner 		*desc_id = LE16_TO_CPU(cmd->ops.resp.next_desc);
233971d10453SEric Joyner 
234071d10453SEric Joyner 	return status;
234171d10453SEric Joyner }
234271d10453SEric Joyner 
234371d10453SEric Joyner /**
234471d10453SEric Joyner  * ice_add_mac_rule - Add a MAC address based filter rule
234571d10453SEric Joyner  * @hw: pointer to the hardware structure
234671d10453SEric Joyner  * @m_list: list of MAC addresses and forwarding information
234771d10453SEric Joyner  * @sw: pointer to switch info struct for which function add rule
234871d10453SEric Joyner  * @lport: logic port number on which function add rule
234971d10453SEric Joyner  *
235056429daeSEric Joyner  * IMPORTANT: When the umac_shared flag is set to false and m_list has
235171d10453SEric Joyner  * multiple unicast addresses, the function assumes that all the
235271d10453SEric Joyner  * addresses are unique in a given add_mac call. It doesn't
235371d10453SEric Joyner  * check for duplicates in this case, removing duplicates from a given
235471d10453SEric Joyner  * list should be taken care of in the caller of this function.
235571d10453SEric Joyner  */
2356*f2635e84SEric Joyner static int
235771d10453SEric Joyner ice_add_mac_rule(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list,
235871d10453SEric Joyner 		 struct ice_switch_info *sw, u8 lport)
235971d10453SEric Joyner {
236071d10453SEric Joyner 	struct ice_sw_recipe *recp_list = &sw->recp_list[ICE_SW_LKUP_MAC];
23619c30461dSEric Joyner 	struct ice_sw_rule_lkup_rx_tx *s_rule, *r_iter;
236271d10453SEric Joyner 	struct ice_fltr_list_entry *m_list_itr;
236371d10453SEric Joyner 	struct LIST_HEAD_TYPE *rule_head;
236471d10453SEric Joyner 	u16 total_elem_left, s_rule_size;
236571d10453SEric Joyner 	struct ice_lock *rule_lock; /* Lock to protect filter rule list */
236671d10453SEric Joyner 	u16 num_unicast = 0;
2367*f2635e84SEric Joyner 	int status = 0;
236871d10453SEric Joyner 	u8 elem_sent;
236971d10453SEric Joyner 
237071d10453SEric Joyner 	s_rule = NULL;
237171d10453SEric Joyner 	rule_lock = &recp_list->filt_rule_lock;
237271d10453SEric Joyner 	rule_head = &recp_list->filt_rules;
237371d10453SEric Joyner 
237471d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(m_list_itr, m_list, ice_fltr_list_entry,
237571d10453SEric Joyner 			    list_entry) {
237671d10453SEric Joyner 		u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
237771d10453SEric Joyner 		u16 vsi_handle;
237871d10453SEric Joyner 		u16 hw_vsi_id;
237971d10453SEric Joyner 
238071d10453SEric Joyner 		m_list_itr->fltr_info.flag = ICE_FLTR_TX;
238171d10453SEric Joyner 		vsi_handle = m_list_itr->fltr_info.vsi_handle;
238271d10453SEric Joyner 		if (!ice_is_vsi_valid(hw, vsi_handle))
238371d10453SEric Joyner 			return ICE_ERR_PARAM;
238471d10453SEric Joyner 		hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
23858923de59SPiotr Kubaj 		if (m_list_itr->fltr_info.fltr_act == ICE_FWD_TO_VSI)
238671d10453SEric Joyner 			m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id;
238771d10453SEric Joyner 		/* update the src in case it is VSI num */
238871d10453SEric Joyner 		if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI)
238971d10453SEric Joyner 			return ICE_ERR_PARAM;
239071d10453SEric Joyner 		m_list_itr->fltr_info.src = hw_vsi_id;
239171d10453SEric Joyner 		if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||
239271d10453SEric Joyner 		    IS_ZERO_ETHER_ADDR(add))
239371d10453SEric Joyner 			return ICE_ERR_PARAM;
239456429daeSEric Joyner 		if (IS_UNICAST_ETHER_ADDR(add) && !hw->umac_shared) {
239571d10453SEric Joyner 			/* Don't overwrite the unicast address */
239671d10453SEric Joyner 			ice_acquire_lock(rule_lock);
239771d10453SEric Joyner 			if (ice_find_rule_entry(rule_head,
239871d10453SEric Joyner 						&m_list_itr->fltr_info)) {
239971d10453SEric Joyner 				ice_release_lock(rule_lock);
240056429daeSEric Joyner 				continue;
240171d10453SEric Joyner 			}
240271d10453SEric Joyner 			ice_release_lock(rule_lock);
240371d10453SEric Joyner 			num_unicast++;
240471d10453SEric Joyner 		} else if (IS_MULTICAST_ETHER_ADDR(add) ||
240556429daeSEric Joyner 			   (IS_UNICAST_ETHER_ADDR(add) && hw->umac_shared)) {
240671d10453SEric Joyner 			m_list_itr->status =
240771d10453SEric Joyner 				ice_add_rule_internal(hw, recp_list, lport,
240871d10453SEric Joyner 						      m_list_itr);
240971d10453SEric Joyner 			if (m_list_itr->status)
241071d10453SEric Joyner 				return m_list_itr->status;
241171d10453SEric Joyner 		}
241271d10453SEric Joyner 	}
241371d10453SEric Joyner 
241471d10453SEric Joyner 	ice_acquire_lock(rule_lock);
241571d10453SEric Joyner 	/* Exit if no suitable entries were found for adding bulk switch rule */
241671d10453SEric Joyner 	if (!num_unicast) {
2417*f2635e84SEric Joyner 		status = 0;
241871d10453SEric Joyner 		goto ice_add_mac_exit;
241971d10453SEric Joyner 	}
242071d10453SEric Joyner 
242171d10453SEric Joyner 	/* Allocate switch rule buffer for the bulk update for unicast */
24229c30461dSEric Joyner 	s_rule_size = ice_struct_size(s_rule, hdr_data, DUMMY_ETH_HDR_LEN);
24239c30461dSEric Joyner 	s_rule = (struct ice_sw_rule_lkup_rx_tx *)
242471d10453SEric Joyner 		ice_calloc(hw, num_unicast, s_rule_size);
242571d10453SEric Joyner 	if (!s_rule) {
242671d10453SEric Joyner 		status = ICE_ERR_NO_MEMORY;
242771d10453SEric Joyner 		goto ice_add_mac_exit;
242871d10453SEric Joyner 	}
242971d10453SEric Joyner 
243071d10453SEric Joyner 	r_iter = s_rule;
243171d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(m_list_itr, m_list, ice_fltr_list_entry,
243271d10453SEric Joyner 			    list_entry) {
243371d10453SEric Joyner 		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
243471d10453SEric Joyner 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
243571d10453SEric Joyner 
243671d10453SEric Joyner 		if (IS_UNICAST_ETHER_ADDR(mac_addr)) {
243771d10453SEric Joyner 			ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter,
243871d10453SEric Joyner 					 ice_aqc_opc_add_sw_rules);
24399c30461dSEric Joyner 			r_iter = (struct ice_sw_rule_lkup_rx_tx *)
244071d10453SEric Joyner 				((u8 *)r_iter + s_rule_size);
244171d10453SEric Joyner 		}
244271d10453SEric Joyner 	}
244371d10453SEric Joyner 
244471d10453SEric Joyner 	/* Call AQ bulk switch rule update for all unicast addresses */
244571d10453SEric Joyner 	r_iter = s_rule;
244671d10453SEric Joyner 	/* Call AQ switch rule in AQ_MAX chunk */
244771d10453SEric Joyner 	for (total_elem_left = num_unicast; total_elem_left > 0;
244871d10453SEric Joyner 	     total_elem_left -= elem_sent) {
24499c30461dSEric Joyner 		struct ice_sw_rule_lkup_rx_tx *entry = r_iter;
245071d10453SEric Joyner 
245171d10453SEric Joyner 		elem_sent = MIN_T(u8, total_elem_left,
245271d10453SEric Joyner 				  (ICE_AQ_MAX_BUF_LEN / s_rule_size));
245371d10453SEric Joyner 		status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size,
245471d10453SEric Joyner 					 elem_sent, ice_aqc_opc_add_sw_rules,
245571d10453SEric Joyner 					 NULL);
245671d10453SEric Joyner 		if (status)
245771d10453SEric Joyner 			goto ice_add_mac_exit;
24589c30461dSEric Joyner 		r_iter = (struct ice_sw_rule_lkup_rx_tx *)
245971d10453SEric Joyner 			((u8 *)r_iter + (elem_sent * s_rule_size));
246071d10453SEric Joyner 	}
246171d10453SEric Joyner 
246271d10453SEric Joyner 	/* Fill up rule ID based on the value returned from FW */
246371d10453SEric Joyner 	r_iter = s_rule;
246471d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(m_list_itr, m_list, ice_fltr_list_entry,
246571d10453SEric Joyner 			    list_entry) {
246671d10453SEric Joyner 		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
246771d10453SEric Joyner 		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
246871d10453SEric Joyner 		struct ice_fltr_mgmt_list_entry *fm_entry;
246971d10453SEric Joyner 
247071d10453SEric Joyner 		if (IS_UNICAST_ETHER_ADDR(mac_addr)) {
247171d10453SEric Joyner 			f_info->fltr_rule_id =
24729c30461dSEric Joyner 				LE16_TO_CPU(r_iter->index);
247371d10453SEric Joyner 			f_info->fltr_act = ICE_FWD_TO_VSI;
247471d10453SEric Joyner 			/* Create an entry to track this MAC address */
247571d10453SEric Joyner 			fm_entry = (struct ice_fltr_mgmt_list_entry *)
247671d10453SEric Joyner 				ice_malloc(hw, sizeof(*fm_entry));
247771d10453SEric Joyner 			if (!fm_entry) {
247871d10453SEric Joyner 				status = ICE_ERR_NO_MEMORY;
247971d10453SEric Joyner 				goto ice_add_mac_exit;
248071d10453SEric Joyner 			}
248171d10453SEric Joyner 			fm_entry->fltr_info = *f_info;
248271d10453SEric Joyner 			fm_entry->vsi_count = 1;
248371d10453SEric Joyner 			/* The book keeping entries will get removed when
248471d10453SEric Joyner 			 * base driver calls remove filter AQ command
248571d10453SEric Joyner 			 */
248671d10453SEric Joyner 
248771d10453SEric Joyner 			LIST_ADD(&fm_entry->list_entry, rule_head);
24889c30461dSEric Joyner 			r_iter = (struct ice_sw_rule_lkup_rx_tx *)
248971d10453SEric Joyner 				((u8 *)r_iter + s_rule_size);
249071d10453SEric Joyner 		}
249171d10453SEric Joyner 	}
249271d10453SEric Joyner 
249371d10453SEric Joyner ice_add_mac_exit:
249471d10453SEric Joyner 	ice_release_lock(rule_lock);
249571d10453SEric Joyner 	if (s_rule)
249671d10453SEric Joyner 		ice_free(hw, s_rule);
249771d10453SEric Joyner 	return status;
249871d10453SEric Joyner }
249971d10453SEric Joyner 
250071d10453SEric Joyner /**
250171d10453SEric Joyner  * ice_add_mac - Add a MAC address based filter rule
250271d10453SEric Joyner  * @hw: pointer to the hardware structure
250371d10453SEric Joyner  * @m_list: list of MAC addresses and forwarding information
250471d10453SEric Joyner  *
250571d10453SEric Joyner  * Function add MAC rule for logical port from HW struct
250671d10453SEric Joyner  */
2507*f2635e84SEric Joyner int ice_add_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list)
250871d10453SEric Joyner {
250971d10453SEric Joyner 	if (!m_list || !hw)
251071d10453SEric Joyner 		return ICE_ERR_PARAM;
251171d10453SEric Joyner 
251271d10453SEric Joyner 	return ice_add_mac_rule(hw, m_list, hw->switch_info,
251371d10453SEric Joyner 				hw->port_info->lport);
251471d10453SEric Joyner }
251571d10453SEric Joyner 
251671d10453SEric Joyner /**
251771d10453SEric Joyner  * ice_add_vlan_internal - Add one VLAN based filter rule
251871d10453SEric Joyner  * @hw: pointer to the hardware structure
251971d10453SEric Joyner  * @recp_list: recipe list for which rule has to be added
252071d10453SEric Joyner  * @f_entry: filter entry containing one VLAN information
252171d10453SEric Joyner  */
2522*f2635e84SEric Joyner static int
252371d10453SEric Joyner ice_add_vlan_internal(struct ice_hw *hw, struct ice_sw_recipe *recp_list,
252471d10453SEric Joyner 		      struct ice_fltr_list_entry *f_entry)
252571d10453SEric Joyner {
252671d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *v_list_itr;
252771d10453SEric Joyner 	struct ice_fltr_info *new_fltr, *cur_fltr;
252871d10453SEric Joyner 	enum ice_sw_lkup_type lkup_type;
252971d10453SEric Joyner 	u16 vsi_list_id = 0, vsi_handle;
253071d10453SEric Joyner 	struct ice_lock *rule_lock; /* Lock to protect filter rule list */
2531*f2635e84SEric Joyner 	int status = 0;
253271d10453SEric Joyner 
253371d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
253471d10453SEric Joyner 		return ICE_ERR_PARAM;
253571d10453SEric Joyner 
253671d10453SEric Joyner 	f_entry->fltr_info.fwd_id.hw_vsi_id =
253771d10453SEric Joyner 		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
253871d10453SEric Joyner 	new_fltr = &f_entry->fltr_info;
253971d10453SEric Joyner 
254071d10453SEric Joyner 	/* VLAN ID should only be 12 bits */
254171d10453SEric Joyner 	if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)
254271d10453SEric Joyner 		return ICE_ERR_PARAM;
254371d10453SEric Joyner 
254471d10453SEric Joyner 	if (new_fltr->src_id != ICE_SRC_ID_VSI)
254571d10453SEric Joyner 		return ICE_ERR_PARAM;
254671d10453SEric Joyner 
254771d10453SEric Joyner 	new_fltr->src = new_fltr->fwd_id.hw_vsi_id;
254871d10453SEric Joyner 	lkup_type = new_fltr->lkup_type;
254971d10453SEric Joyner 	vsi_handle = new_fltr->vsi_handle;
255071d10453SEric Joyner 	rule_lock = &recp_list->filt_rule_lock;
255171d10453SEric Joyner 	ice_acquire_lock(rule_lock);
255271d10453SEric Joyner 	v_list_itr = ice_find_rule_entry(&recp_list->filt_rules, new_fltr);
255371d10453SEric Joyner 	if (!v_list_itr) {
255471d10453SEric Joyner 		struct ice_vsi_list_map_info *map_info = NULL;
255571d10453SEric Joyner 
255671d10453SEric Joyner 		if (new_fltr->fltr_act == ICE_FWD_TO_VSI) {
255771d10453SEric Joyner 			/* All VLAN pruning rules use a VSI list. Check if
255871d10453SEric Joyner 			 * there is already a VSI list containing VSI that we
255971d10453SEric Joyner 			 * want to add. If found, use the same vsi_list_id for
256071d10453SEric Joyner 			 * this new VLAN rule or else create a new list.
256171d10453SEric Joyner 			 */
256271d10453SEric Joyner 			map_info = ice_find_vsi_list_entry(recp_list,
256371d10453SEric Joyner 							   vsi_handle,
256471d10453SEric Joyner 							   &vsi_list_id);
256571d10453SEric Joyner 			if (!map_info) {
256671d10453SEric Joyner 				status = ice_create_vsi_list_rule(hw,
256771d10453SEric Joyner 								  &vsi_handle,
256871d10453SEric Joyner 								  1,
256971d10453SEric Joyner 								  &vsi_list_id,
257071d10453SEric Joyner 								  lkup_type);
257171d10453SEric Joyner 				if (status)
257271d10453SEric Joyner 					goto exit;
257371d10453SEric Joyner 			}
257471d10453SEric Joyner 			/* Convert the action to forwarding to a VSI list. */
257571d10453SEric Joyner 			new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
257671d10453SEric Joyner 			new_fltr->fwd_id.vsi_list_id = vsi_list_id;
257771d10453SEric Joyner 		}
257871d10453SEric Joyner 
257971d10453SEric Joyner 		status = ice_create_pkt_fwd_rule(hw, recp_list, f_entry);
258071d10453SEric Joyner 		if (!status) {
258171d10453SEric Joyner 			v_list_itr = ice_find_rule_entry(&recp_list->filt_rules,
258271d10453SEric Joyner 							 new_fltr);
258371d10453SEric Joyner 			if (!v_list_itr) {
258471d10453SEric Joyner 				status = ICE_ERR_DOES_NOT_EXIST;
258571d10453SEric Joyner 				goto exit;
258671d10453SEric Joyner 			}
258771d10453SEric Joyner 			/* reuse VSI list for new rule and increment ref_cnt */
258871d10453SEric Joyner 			if (map_info) {
258971d10453SEric Joyner 				v_list_itr->vsi_list_info = map_info;
259071d10453SEric Joyner 				map_info->ref_cnt++;
259171d10453SEric Joyner 			} else {
259271d10453SEric Joyner 				v_list_itr->vsi_list_info =
259371d10453SEric Joyner 					ice_create_vsi_list_map(hw, &vsi_handle,
259471d10453SEric Joyner 								1, vsi_list_id);
259571d10453SEric Joyner 			}
259671d10453SEric Joyner 		}
259771d10453SEric Joyner 	} else if (v_list_itr->vsi_list_info->ref_cnt == 1) {
259871d10453SEric Joyner 		/* Update existing VSI list to add new VSI ID only if it used
259971d10453SEric Joyner 		 * by one VLAN rule.
260071d10453SEric Joyner 		 */
260171d10453SEric Joyner 		cur_fltr = &v_list_itr->fltr_info;
260271d10453SEric Joyner 		status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr,
260371d10453SEric Joyner 						 new_fltr);
260471d10453SEric Joyner 	} else {
260571d10453SEric Joyner 		/* If VLAN rule exists and VSI list being used by this rule is
260671d10453SEric Joyner 		 * referenced by more than 1 VLAN rule. Then create a new VSI
260771d10453SEric Joyner 		 * list appending previous VSI with new VSI and update existing
260871d10453SEric Joyner 		 * VLAN rule to point to new VSI list ID
260971d10453SEric Joyner 		 */
261071d10453SEric Joyner 		struct ice_fltr_info tmp_fltr;
261171d10453SEric Joyner 		u16 vsi_handle_arr[2];
261271d10453SEric Joyner 		u16 cur_handle;
261371d10453SEric Joyner 
261471d10453SEric Joyner 		/* Current implementation only supports reusing VSI list with
261571d10453SEric Joyner 		 * one VSI count. We should never hit below condition
261671d10453SEric Joyner 		 */
261771d10453SEric Joyner 		if (v_list_itr->vsi_count > 1 &&
261871d10453SEric Joyner 		    v_list_itr->vsi_list_info->ref_cnt > 1) {
26197d7af7f8SEric Joyner 			ice_debug(hw, ICE_DBG_SW, "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n");
262071d10453SEric Joyner 			status = ICE_ERR_CFG;
262171d10453SEric Joyner 			goto exit;
262271d10453SEric Joyner 		}
262371d10453SEric Joyner 
262471d10453SEric Joyner 		cur_handle =
262571d10453SEric Joyner 			ice_find_first_bit(v_list_itr->vsi_list_info->vsi_map,
262671d10453SEric Joyner 					   ICE_MAX_VSI);
262771d10453SEric Joyner 
262871d10453SEric Joyner 		/* A rule already exists with the new VSI being added */
262971d10453SEric Joyner 		if (cur_handle == vsi_handle) {
263071d10453SEric Joyner 			status = ICE_ERR_ALREADY_EXISTS;
263171d10453SEric Joyner 			goto exit;
263271d10453SEric Joyner 		}
263371d10453SEric Joyner 
263471d10453SEric Joyner 		vsi_handle_arr[0] = cur_handle;
263571d10453SEric Joyner 		vsi_handle_arr[1] = vsi_handle;
263671d10453SEric Joyner 		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
263771d10453SEric Joyner 						  &vsi_list_id, lkup_type);
263871d10453SEric Joyner 		if (status)
263971d10453SEric Joyner 			goto exit;
264071d10453SEric Joyner 
264171d10453SEric Joyner 		tmp_fltr = v_list_itr->fltr_info;
264271d10453SEric Joyner 		tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id;
264371d10453SEric Joyner 		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
264471d10453SEric Joyner 		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
264571d10453SEric Joyner 		/* Update the previous switch rule to a new VSI list which
264671d10453SEric Joyner 		 * includes current VSI that is requested
264771d10453SEric Joyner 		 */
264871d10453SEric Joyner 		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
264971d10453SEric Joyner 		if (status)
265071d10453SEric Joyner 			goto exit;
265171d10453SEric Joyner 
265271d10453SEric Joyner 		/* before overriding VSI list map info. decrement ref_cnt of
265371d10453SEric Joyner 		 * previous VSI list
265471d10453SEric Joyner 		 */
265571d10453SEric Joyner 		v_list_itr->vsi_list_info->ref_cnt--;
265671d10453SEric Joyner 
265771d10453SEric Joyner 		/* now update to newly created list */
265871d10453SEric Joyner 		v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id;
265971d10453SEric Joyner 		v_list_itr->vsi_list_info =
266071d10453SEric Joyner 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
266171d10453SEric Joyner 						vsi_list_id);
266271d10453SEric Joyner 		v_list_itr->vsi_count++;
266371d10453SEric Joyner 	}
266471d10453SEric Joyner 
266571d10453SEric Joyner exit:
266671d10453SEric Joyner 	ice_release_lock(rule_lock);
266771d10453SEric Joyner 	return status;
266871d10453SEric Joyner }
266971d10453SEric Joyner 
267071d10453SEric Joyner /**
267171d10453SEric Joyner  * ice_add_vlan_rule - Add VLAN based filter rule
267271d10453SEric Joyner  * @hw: pointer to the hardware structure
267371d10453SEric Joyner  * @v_list: list of VLAN entries and forwarding information
267471d10453SEric Joyner  * @sw: pointer to switch info struct for which function add rule
267571d10453SEric Joyner  */
2676*f2635e84SEric Joyner static int
267771d10453SEric Joyner ice_add_vlan_rule(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list,
267871d10453SEric Joyner 		  struct ice_switch_info *sw)
267971d10453SEric Joyner {
268071d10453SEric Joyner 	struct ice_fltr_list_entry *v_list_itr;
268171d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
268271d10453SEric Joyner 
268371d10453SEric Joyner 	recp_list = &sw->recp_list[ICE_SW_LKUP_VLAN];
268471d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(v_list_itr, v_list, ice_fltr_list_entry,
268571d10453SEric Joyner 			    list_entry) {
268671d10453SEric Joyner 		if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)
268771d10453SEric Joyner 			return ICE_ERR_PARAM;
268871d10453SEric Joyner 		v_list_itr->fltr_info.flag = ICE_FLTR_TX;
268971d10453SEric Joyner 		v_list_itr->status = ice_add_vlan_internal(hw, recp_list,
269071d10453SEric Joyner 							   v_list_itr);
269171d10453SEric Joyner 		if (v_list_itr->status)
269271d10453SEric Joyner 			return v_list_itr->status;
269371d10453SEric Joyner 	}
2694*f2635e84SEric Joyner 	return 0;
269571d10453SEric Joyner }
269671d10453SEric Joyner 
269771d10453SEric Joyner /**
269871d10453SEric Joyner  * ice_add_vlan - Add a VLAN based filter rule
269971d10453SEric Joyner  * @hw: pointer to the hardware structure
270071d10453SEric Joyner  * @v_list: list of VLAN and forwarding information
270171d10453SEric Joyner  *
270271d10453SEric Joyner  * Function add VLAN rule for logical port from HW struct
270371d10453SEric Joyner  */
2704*f2635e84SEric Joyner int ice_add_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list)
270571d10453SEric Joyner {
270671d10453SEric Joyner 	if (!v_list || !hw)
270771d10453SEric Joyner 		return ICE_ERR_PARAM;
270871d10453SEric Joyner 
270971d10453SEric Joyner 	return ice_add_vlan_rule(hw, v_list, hw->switch_info);
271071d10453SEric Joyner }
271171d10453SEric Joyner 
271271d10453SEric Joyner /**
271371d10453SEric Joyner  * ice_add_eth_mac_rule - Add ethertype and MAC based filter rule
271471d10453SEric Joyner  * @hw: pointer to the hardware structure
271571d10453SEric Joyner  * @em_list: list of ether type MAC filter, MAC is optional
271671d10453SEric Joyner  * @sw: pointer to switch info struct for which function add rule
271771d10453SEric Joyner  * @lport: logic port number on which function add rule
271871d10453SEric Joyner  *
271971d10453SEric Joyner  * This function requires the caller to populate the entries in
272071d10453SEric Joyner  * the filter list with the necessary fields (including flags to
272171d10453SEric Joyner  * indicate Tx or Rx rules).
272271d10453SEric Joyner  */
2723*f2635e84SEric Joyner static int
272471d10453SEric Joyner ice_add_eth_mac_rule(struct ice_hw *hw, struct LIST_HEAD_TYPE *em_list,
272571d10453SEric Joyner 		     struct ice_switch_info *sw, u8 lport)
272671d10453SEric Joyner {
272771d10453SEric Joyner 	struct ice_fltr_list_entry *em_list_itr;
272871d10453SEric Joyner 
272971d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(em_list_itr, em_list, ice_fltr_list_entry,
273071d10453SEric Joyner 			    list_entry) {
273171d10453SEric Joyner 		struct ice_sw_recipe *recp_list;
273271d10453SEric Joyner 		enum ice_sw_lkup_type l_type;
273371d10453SEric Joyner 
273471d10453SEric Joyner 		l_type = em_list_itr->fltr_info.lkup_type;
273571d10453SEric Joyner 		recp_list = &sw->recp_list[l_type];
273671d10453SEric Joyner 
273771d10453SEric Joyner 		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
273871d10453SEric Joyner 		    l_type != ICE_SW_LKUP_ETHERTYPE)
273971d10453SEric Joyner 			return ICE_ERR_PARAM;
274071d10453SEric Joyner 
274171d10453SEric Joyner 		em_list_itr->status = ice_add_rule_internal(hw, recp_list,
274271d10453SEric Joyner 							    lport,
274371d10453SEric Joyner 							    em_list_itr);
274471d10453SEric Joyner 		if (em_list_itr->status)
274571d10453SEric Joyner 			return em_list_itr->status;
274671d10453SEric Joyner 	}
2747*f2635e84SEric Joyner 	return 0;
274871d10453SEric Joyner }
274971d10453SEric Joyner 
275071d10453SEric Joyner /**
275171d10453SEric Joyner  * ice_add_eth_mac - Add a ethertype based filter rule
275271d10453SEric Joyner  * @hw: pointer to the hardware structure
275371d10453SEric Joyner  * @em_list: list of ethertype and forwarding information
275471d10453SEric Joyner  *
275571d10453SEric Joyner  * Function add ethertype rule for logical port from HW struct
275671d10453SEric Joyner  */
2757*f2635e84SEric Joyner int
275871d10453SEric Joyner ice_add_eth_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *em_list)
275971d10453SEric Joyner {
276071d10453SEric Joyner 	if (!em_list || !hw)
276171d10453SEric Joyner 		return ICE_ERR_PARAM;
276271d10453SEric Joyner 
276371d10453SEric Joyner 	return ice_add_eth_mac_rule(hw, em_list, hw->switch_info,
276471d10453SEric Joyner 				    hw->port_info->lport);
276571d10453SEric Joyner }
276671d10453SEric Joyner 
276771d10453SEric Joyner /**
276871d10453SEric Joyner  * ice_remove_eth_mac_rule - Remove an ethertype (or MAC) based filter rule
276971d10453SEric Joyner  * @hw: pointer to the hardware structure
277071d10453SEric Joyner  * @em_list: list of ethertype or ethertype MAC entries
277171d10453SEric Joyner  * @sw: pointer to switch info struct for which function add rule
277271d10453SEric Joyner  */
2773*f2635e84SEric Joyner static int
277471d10453SEric Joyner ice_remove_eth_mac_rule(struct ice_hw *hw, struct LIST_HEAD_TYPE *em_list,
277571d10453SEric Joyner 			struct ice_switch_info *sw)
277671d10453SEric Joyner {
277771d10453SEric Joyner 	struct ice_fltr_list_entry *em_list_itr, *tmp;
277871d10453SEric Joyner 
277971d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(em_list_itr, tmp, em_list, ice_fltr_list_entry,
278071d10453SEric Joyner 				 list_entry) {
278171d10453SEric Joyner 		struct ice_sw_recipe *recp_list;
278271d10453SEric Joyner 		enum ice_sw_lkup_type l_type;
278371d10453SEric Joyner 
278471d10453SEric Joyner 		l_type = em_list_itr->fltr_info.lkup_type;
278571d10453SEric Joyner 
278671d10453SEric Joyner 		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
278771d10453SEric Joyner 		    l_type != ICE_SW_LKUP_ETHERTYPE)
278871d10453SEric Joyner 			return ICE_ERR_PARAM;
278971d10453SEric Joyner 
279071d10453SEric Joyner 		recp_list = &sw->recp_list[l_type];
279171d10453SEric Joyner 		em_list_itr->status = ice_remove_rule_internal(hw, recp_list,
279271d10453SEric Joyner 							       em_list_itr);
279371d10453SEric Joyner 		if (em_list_itr->status)
279471d10453SEric Joyner 			return em_list_itr->status;
279571d10453SEric Joyner 	}
2796*f2635e84SEric Joyner 	return 0;
279771d10453SEric Joyner }
279871d10453SEric Joyner 
279971d10453SEric Joyner /**
280071d10453SEric Joyner  * ice_remove_eth_mac - remove a ethertype based filter rule
280171d10453SEric Joyner  * @hw: pointer to the hardware structure
280271d10453SEric Joyner  * @em_list: list of ethertype and forwarding information
280371d10453SEric Joyner  *
280471d10453SEric Joyner  */
2805*f2635e84SEric Joyner int
280671d10453SEric Joyner ice_remove_eth_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *em_list)
280771d10453SEric Joyner {
280871d10453SEric Joyner 	if (!em_list || !hw)
280971d10453SEric Joyner 		return ICE_ERR_PARAM;
281071d10453SEric Joyner 
281171d10453SEric Joyner 	return ice_remove_eth_mac_rule(hw, em_list, hw->switch_info);
281271d10453SEric Joyner }
281371d10453SEric Joyner 
281471d10453SEric Joyner /**
28158923de59SPiotr Kubaj  * ice_get_lg_act_aqc_res_type - get resource type for a large action
28168923de59SPiotr Kubaj  * @res_type: resource type to be filled in case of function success
28178923de59SPiotr Kubaj  * @num_acts: number of actions to hold with a large action entry
28188923de59SPiotr Kubaj  *
28198923de59SPiotr Kubaj  * Get resource type for a large action depending on the number
28208923de59SPiotr Kubaj  * of single actions that it contains.
28218923de59SPiotr Kubaj  */
2822*f2635e84SEric Joyner static int
28238923de59SPiotr Kubaj ice_get_lg_act_aqc_res_type(u16 *res_type, int num_acts)
28248923de59SPiotr Kubaj {
28258923de59SPiotr Kubaj 	if (!res_type)
28268923de59SPiotr Kubaj 		return ICE_ERR_BAD_PTR;
28278923de59SPiotr Kubaj 
28288923de59SPiotr Kubaj 	/* If num_acts is 1, use ICE_AQC_RES_TYPE_WIDE_TABLE_1.
28298923de59SPiotr Kubaj 	 * If num_acts is 2, use ICE_AQC_RES_TYPE_WIDE_TABLE_3.
28308923de59SPiotr Kubaj 	 * If num_acts is greater than 2, then use
28318923de59SPiotr Kubaj 	 * ICE_AQC_RES_TYPE_WIDE_TABLE_4.
28328923de59SPiotr Kubaj 	 * The num_acts cannot be equal to 0 or greater than 4.
28338923de59SPiotr Kubaj 	 */
28348923de59SPiotr Kubaj 	switch (num_acts) {
28358923de59SPiotr Kubaj 	case 1:
28368923de59SPiotr Kubaj 		*res_type = ICE_AQC_RES_TYPE_WIDE_TABLE_1;
28378923de59SPiotr Kubaj 		break;
28388923de59SPiotr Kubaj 	case 2:
28398923de59SPiotr Kubaj 		*res_type = ICE_AQC_RES_TYPE_WIDE_TABLE_2;
28408923de59SPiotr Kubaj 		break;
28418923de59SPiotr Kubaj 	case 3:
28428923de59SPiotr Kubaj 	case 4:
28438923de59SPiotr Kubaj 		*res_type = ICE_AQC_RES_TYPE_WIDE_TABLE_4;
28448923de59SPiotr Kubaj 		break;
28458923de59SPiotr Kubaj 	default:
28468923de59SPiotr Kubaj 		return ICE_ERR_PARAM;
28478923de59SPiotr Kubaj 	}
28488923de59SPiotr Kubaj 
2849*f2635e84SEric Joyner 	return 0;
28508923de59SPiotr Kubaj }
28518923de59SPiotr Kubaj 
28528923de59SPiotr Kubaj /**
28538923de59SPiotr Kubaj  * ice_alloc_res_lg_act - add large action resource
28548923de59SPiotr Kubaj  * @hw: pointer to the hardware structure
28558923de59SPiotr Kubaj  * @l_id: large action ID to fill it in
28568923de59SPiotr Kubaj  * @num_acts: number of actions to hold with a large action entry
28578923de59SPiotr Kubaj  */
2858*f2635e84SEric Joyner static int
28598923de59SPiotr Kubaj ice_alloc_res_lg_act(struct ice_hw *hw, u16 *l_id, u16 num_acts)
28608923de59SPiotr Kubaj {
28618923de59SPiotr Kubaj 	struct ice_aqc_alloc_free_res_elem *sw_buf;
28628923de59SPiotr Kubaj 	u16 buf_len, res_type;
2863*f2635e84SEric Joyner 	int status;
28648923de59SPiotr Kubaj 
28658923de59SPiotr Kubaj 	if (!l_id)
28668923de59SPiotr Kubaj 		return ICE_ERR_BAD_PTR;
28678923de59SPiotr Kubaj 
28688923de59SPiotr Kubaj 	status = ice_get_lg_act_aqc_res_type(&res_type, num_acts);
28698923de59SPiotr Kubaj 	if (status)
28708923de59SPiotr Kubaj 		return status;
28718923de59SPiotr Kubaj 
28728923de59SPiotr Kubaj 	/* Allocate resource for large action */
28738923de59SPiotr Kubaj 	buf_len = ice_struct_size(sw_buf, elem, 1);
28748923de59SPiotr Kubaj 	sw_buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
28758923de59SPiotr Kubaj 	if (!sw_buf)
28768923de59SPiotr Kubaj 		return ICE_ERR_NO_MEMORY;
28778923de59SPiotr Kubaj 
28788923de59SPiotr Kubaj 	sw_buf->res_type = CPU_TO_LE16(res_type);
28798923de59SPiotr Kubaj 	sw_buf->num_elems = CPU_TO_LE16(1);
28808923de59SPiotr Kubaj 
28818923de59SPiotr Kubaj 	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len,
28828923de59SPiotr Kubaj 				       ice_aqc_opc_alloc_res, NULL);
28838923de59SPiotr Kubaj 	if (!status)
28848923de59SPiotr Kubaj 		*l_id = LE16_TO_CPU(sw_buf->elem[0].e.sw_resp);
28858923de59SPiotr Kubaj 
28868923de59SPiotr Kubaj 	ice_free(hw, sw_buf);
28878923de59SPiotr Kubaj 
28888923de59SPiotr Kubaj 	return status;
28898923de59SPiotr Kubaj }
28908923de59SPiotr Kubaj 
28918923de59SPiotr Kubaj /**
289271d10453SEric Joyner  * ice_rem_sw_rule_info
289371d10453SEric Joyner  * @hw: pointer to the hardware structure
289471d10453SEric Joyner  * @rule_head: pointer to the switch list structure that we want to delete
289571d10453SEric Joyner  */
289671d10453SEric Joyner static void
289771d10453SEric Joyner ice_rem_sw_rule_info(struct ice_hw *hw, struct LIST_HEAD_TYPE *rule_head)
289871d10453SEric Joyner {
289971d10453SEric Joyner 	if (!LIST_EMPTY(rule_head)) {
290071d10453SEric Joyner 		struct ice_fltr_mgmt_list_entry *entry;
290171d10453SEric Joyner 		struct ice_fltr_mgmt_list_entry *tmp;
290271d10453SEric Joyner 
290371d10453SEric Joyner 		LIST_FOR_EACH_ENTRY_SAFE(entry, tmp, rule_head,
290471d10453SEric Joyner 					 ice_fltr_mgmt_list_entry, list_entry) {
290571d10453SEric Joyner 			LIST_DEL(&entry->list_entry);
290671d10453SEric Joyner 			ice_free(hw, entry);
290771d10453SEric Joyner 		}
290871d10453SEric Joyner 	}
290971d10453SEric Joyner }
291071d10453SEric Joyner 
291171d10453SEric Joyner /**
291271d10453SEric Joyner  * ice_rem_all_sw_rules_info
291371d10453SEric Joyner  * @hw: pointer to the hardware structure
291471d10453SEric Joyner  */
291571d10453SEric Joyner void ice_rem_all_sw_rules_info(struct ice_hw *hw)
291671d10453SEric Joyner {
291771d10453SEric Joyner 	struct ice_switch_info *sw = hw->switch_info;
291871d10453SEric Joyner 	u8 i;
291971d10453SEric Joyner 
292071d10453SEric Joyner 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
292171d10453SEric Joyner 		struct LIST_HEAD_TYPE *rule_head;
292271d10453SEric Joyner 
292371d10453SEric Joyner 		rule_head = &sw->recp_list[i].filt_rules;
292471d10453SEric Joyner 		if (!sw->recp_list[i].adv_rule)
292571d10453SEric Joyner 			ice_rem_sw_rule_info(hw, rule_head);
292671d10453SEric Joyner 	}
292771d10453SEric Joyner }
292871d10453SEric Joyner 
292971d10453SEric Joyner /**
293071d10453SEric Joyner  * ice_cfg_dflt_vsi - change state of VSI to set/clear default
293171d10453SEric Joyner  * @pi: pointer to the port_info structure
293271d10453SEric Joyner  * @vsi_handle: VSI handle to set as default
293371d10453SEric Joyner  * @set: true to add the above mentioned switch rule, false to remove it
293471d10453SEric Joyner  * @direction: ICE_FLTR_RX or ICE_FLTR_TX
293571d10453SEric Joyner  *
293671d10453SEric Joyner  * add filter rule to set/unset given VSI as default VSI for the switch
293771d10453SEric Joyner  * (represented by swid)
293871d10453SEric Joyner  */
2939*f2635e84SEric Joyner int
294071d10453SEric Joyner ice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set,
294171d10453SEric Joyner 		 u8 direction)
294271d10453SEric Joyner {
29438923de59SPiotr Kubaj 	struct ice_fltr_list_entry f_list_entry;
29449c30461dSEric Joyner 	struct ice_sw_recipe *recp_list = NULL;
294571d10453SEric Joyner 	struct ice_fltr_info f_info;
294671d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
29478923de59SPiotr Kubaj 	u8 lport = pi->lport;
294871d10453SEric Joyner 	u16 hw_vsi_id;
2949*f2635e84SEric Joyner 	int status;
2950*f2635e84SEric Joyner 
29518923de59SPiotr Kubaj 	recp_list = &pi->hw->switch_info->recp_list[ICE_SW_LKUP_DFLT];
295271d10453SEric Joyner 
295371d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle))
295471d10453SEric Joyner 		return ICE_ERR_PARAM;
29558923de59SPiotr Kubaj 
295671d10453SEric Joyner 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
295771d10453SEric Joyner 
295871d10453SEric Joyner 	ice_memset(&f_info, 0, sizeof(f_info), ICE_NONDMA_MEM);
295971d10453SEric Joyner 
296071d10453SEric Joyner 	f_info.lkup_type = ICE_SW_LKUP_DFLT;
296171d10453SEric Joyner 	f_info.flag = direction;
296271d10453SEric Joyner 	f_info.fltr_act = ICE_FWD_TO_VSI;
296371d10453SEric Joyner 	f_info.fwd_id.hw_vsi_id = hw_vsi_id;
29648923de59SPiotr Kubaj 	f_info.vsi_handle = vsi_handle;
296571d10453SEric Joyner 
296671d10453SEric Joyner 	if (f_info.flag & ICE_FLTR_RX) {
296771d10453SEric Joyner 		f_info.src = pi->lport;
296871d10453SEric Joyner 		f_info.src_id = ICE_SRC_ID_LPORT;
296971d10453SEric Joyner 	} else if (f_info.flag & ICE_FLTR_TX) {
297071d10453SEric Joyner 		f_info.src_id = ICE_SRC_ID_VSI;
297171d10453SEric Joyner 		f_info.src = hw_vsi_id;
297271d10453SEric Joyner 	}
29738923de59SPiotr Kubaj 	f_list_entry.fltr_info = f_info;
297471d10453SEric Joyner 
297571d10453SEric Joyner 	if (set)
29768923de59SPiotr Kubaj 		status = ice_add_rule_internal(hw, recp_list, lport,
29778923de59SPiotr Kubaj 					       &f_list_entry);
297871d10453SEric Joyner 	else
29798923de59SPiotr Kubaj 		status = ice_remove_rule_internal(hw, recp_list,
29808923de59SPiotr Kubaj 						  &f_list_entry);
298171d10453SEric Joyner 
298271d10453SEric Joyner 	return status;
298371d10453SEric Joyner }
298471d10453SEric Joyner 
298571d10453SEric Joyner /**
29868923de59SPiotr Kubaj  * ice_check_if_dflt_vsi - check if VSI is default VSI
29878923de59SPiotr Kubaj  * @pi: pointer to the port_info structure
29888923de59SPiotr Kubaj  * @vsi_handle: vsi handle to check for in filter list
29898923de59SPiotr Kubaj  * @rule_exists: indicates if there are any VSI's in the rule list
29908923de59SPiotr Kubaj  *
29918923de59SPiotr Kubaj  * checks if the VSI is in a default VSI list, and also indicates
29928923de59SPiotr Kubaj  * if the default VSI list is empty
29938923de59SPiotr Kubaj  */
29948923de59SPiotr Kubaj bool ice_check_if_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle,
29958923de59SPiotr Kubaj 			   bool *rule_exists)
29968923de59SPiotr Kubaj {
29978923de59SPiotr Kubaj 	struct ice_fltr_mgmt_list_entry *fm_entry;
29988923de59SPiotr Kubaj 	struct LIST_HEAD_TYPE *rule_head;
29998923de59SPiotr Kubaj 	struct ice_sw_recipe *recp_list;
30008923de59SPiotr Kubaj 	struct ice_lock *rule_lock;
30018923de59SPiotr Kubaj 	bool ret = false;
30028923de59SPiotr Kubaj 	recp_list = &pi->hw->switch_info->recp_list[ICE_SW_LKUP_DFLT];
30038923de59SPiotr Kubaj 	rule_lock = &recp_list->filt_rule_lock;
30048923de59SPiotr Kubaj 	rule_head = &recp_list->filt_rules;
30058923de59SPiotr Kubaj 
30068923de59SPiotr Kubaj 	ice_acquire_lock(rule_lock);
30078923de59SPiotr Kubaj 
30088923de59SPiotr Kubaj 	if (rule_exists && !LIST_EMPTY(rule_head))
30098923de59SPiotr Kubaj 		*rule_exists = true;
30108923de59SPiotr Kubaj 
30118923de59SPiotr Kubaj 	LIST_FOR_EACH_ENTRY(fm_entry, rule_head,
30128923de59SPiotr Kubaj 			    ice_fltr_mgmt_list_entry, list_entry) {
30138923de59SPiotr Kubaj 		if (ice_vsi_uses_fltr(fm_entry, vsi_handle)) {
30148923de59SPiotr Kubaj 			ret = true;
30158923de59SPiotr Kubaj 			break;
30168923de59SPiotr Kubaj 		}
30178923de59SPiotr Kubaj 	}
30188923de59SPiotr Kubaj 
30198923de59SPiotr Kubaj 	ice_release_lock(rule_lock);
30208923de59SPiotr Kubaj 	return ret;
30218923de59SPiotr Kubaj }
30228923de59SPiotr Kubaj 
30238923de59SPiotr Kubaj /**
302471d10453SEric Joyner  * ice_find_ucast_rule_entry - Search for a unicast MAC filter rule entry
302571d10453SEric Joyner  * @list_head: head of rule list
302671d10453SEric Joyner  * @f_info: rule information
302771d10453SEric Joyner  *
302871d10453SEric Joyner  * Helper function to search for a unicast rule entry - this is to be used
302971d10453SEric Joyner  * to remove unicast MAC filter that is not shared with other VSIs on the
303071d10453SEric Joyner  * PF switch.
303171d10453SEric Joyner  *
303271d10453SEric Joyner  * Returns pointer to entry storing the rule if found
303371d10453SEric Joyner  */
303471d10453SEric Joyner static struct ice_fltr_mgmt_list_entry *
303571d10453SEric Joyner ice_find_ucast_rule_entry(struct LIST_HEAD_TYPE *list_head,
303671d10453SEric Joyner 			  struct ice_fltr_info *f_info)
303771d10453SEric Joyner {
303871d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *list_itr;
303971d10453SEric Joyner 
304071d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(list_itr, list_head, ice_fltr_mgmt_list_entry,
304171d10453SEric Joyner 			    list_entry) {
304271d10453SEric Joyner 		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
304371d10453SEric Joyner 			    sizeof(f_info->l_data)) &&
304471d10453SEric Joyner 		    f_info->fwd_id.hw_vsi_id ==
304571d10453SEric Joyner 		    list_itr->fltr_info.fwd_id.hw_vsi_id &&
304671d10453SEric Joyner 		    f_info->flag == list_itr->fltr_info.flag)
304771d10453SEric Joyner 			return list_itr;
304871d10453SEric Joyner 	}
304971d10453SEric Joyner 	return NULL;
305071d10453SEric Joyner }
305171d10453SEric Joyner 
305271d10453SEric Joyner /**
305371d10453SEric Joyner  * ice_remove_mac_rule - remove a MAC based filter rule
305471d10453SEric Joyner  * @hw: pointer to the hardware structure
305571d10453SEric Joyner  * @m_list: list of MAC addresses and forwarding information
305671d10453SEric Joyner  * @recp_list: list from which function remove MAC address
305771d10453SEric Joyner  *
305871d10453SEric Joyner  * This function removes either a MAC filter rule or a specific VSI from a
305971d10453SEric Joyner  * VSI list for a multicast MAC address.
306071d10453SEric Joyner  *
306171d10453SEric Joyner  * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by
306271d10453SEric Joyner  * ice_add_mac. Caller should be aware that this call will only work if all
306371d10453SEric Joyner  * the entries passed into m_list were added previously. It will not attempt to
306471d10453SEric Joyner  * do a partial remove of entries that were found.
306571d10453SEric Joyner  */
3066*f2635e84SEric Joyner static int
306771d10453SEric Joyner ice_remove_mac_rule(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list,
306871d10453SEric Joyner 		    struct ice_sw_recipe *recp_list)
306971d10453SEric Joyner {
307071d10453SEric Joyner 	struct ice_fltr_list_entry *list_itr, *tmp;
307171d10453SEric Joyner 	struct ice_lock *rule_lock; /* Lock to protect filter rule list */
307271d10453SEric Joyner 
307371d10453SEric Joyner 	if (!m_list)
307471d10453SEric Joyner 		return ICE_ERR_PARAM;
307571d10453SEric Joyner 
307671d10453SEric Joyner 	rule_lock = &recp_list->filt_rule_lock;
307771d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(list_itr, tmp, m_list, ice_fltr_list_entry,
307871d10453SEric Joyner 				 list_entry) {
307971d10453SEric Joyner 		enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;
308071d10453SEric Joyner 		u8 *add = &list_itr->fltr_info.l_data.mac.mac_addr[0];
308171d10453SEric Joyner 		u16 vsi_handle;
308271d10453SEric Joyner 
308371d10453SEric Joyner 		if (l_type != ICE_SW_LKUP_MAC)
308471d10453SEric Joyner 			return ICE_ERR_PARAM;
308571d10453SEric Joyner 
308671d10453SEric Joyner 		vsi_handle = list_itr->fltr_info.vsi_handle;
308771d10453SEric Joyner 		if (!ice_is_vsi_valid(hw, vsi_handle))
308871d10453SEric Joyner 			return ICE_ERR_PARAM;
308971d10453SEric Joyner 
309071d10453SEric Joyner 		list_itr->fltr_info.fwd_id.hw_vsi_id =
309171d10453SEric Joyner 					ice_get_hw_vsi_num(hw, vsi_handle);
309256429daeSEric Joyner 		if (IS_UNICAST_ETHER_ADDR(add) && !hw->umac_shared) {
309371d10453SEric Joyner 			/* Don't remove the unicast address that belongs to
309471d10453SEric Joyner 			 * another VSI on the switch, since it is not being
309571d10453SEric Joyner 			 * shared...
309671d10453SEric Joyner 			 */
309771d10453SEric Joyner 			ice_acquire_lock(rule_lock);
309871d10453SEric Joyner 			if (!ice_find_ucast_rule_entry(&recp_list->filt_rules,
309971d10453SEric Joyner 						       &list_itr->fltr_info)) {
310071d10453SEric Joyner 				ice_release_lock(rule_lock);
310171d10453SEric Joyner 				return ICE_ERR_DOES_NOT_EXIST;
310271d10453SEric Joyner 			}
310371d10453SEric Joyner 			ice_release_lock(rule_lock);
310471d10453SEric Joyner 		}
310571d10453SEric Joyner 		list_itr->status = ice_remove_rule_internal(hw, recp_list,
310671d10453SEric Joyner 							    list_itr);
310771d10453SEric Joyner 		if (list_itr->status)
310871d10453SEric Joyner 			return list_itr->status;
310971d10453SEric Joyner 	}
3110*f2635e84SEric Joyner 	return 0;
311171d10453SEric Joyner }
311271d10453SEric Joyner 
311371d10453SEric Joyner /**
311471d10453SEric Joyner  * ice_remove_mac - remove a MAC address based filter rule
311571d10453SEric Joyner  * @hw: pointer to the hardware structure
311671d10453SEric Joyner  * @m_list: list of MAC addresses and forwarding information
311771d10453SEric Joyner  *
311871d10453SEric Joyner  */
3119*f2635e84SEric Joyner int ice_remove_mac(struct ice_hw *hw, struct LIST_HEAD_TYPE *m_list)
312071d10453SEric Joyner {
312171d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
312271d10453SEric Joyner 
312371d10453SEric Joyner 	recp_list = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC];
312471d10453SEric Joyner 	return ice_remove_mac_rule(hw, m_list, recp_list);
312571d10453SEric Joyner }
312671d10453SEric Joyner 
312771d10453SEric Joyner /**
312871d10453SEric Joyner  * ice_remove_vlan_rule - Remove VLAN based filter rule
312971d10453SEric Joyner  * @hw: pointer to the hardware structure
313071d10453SEric Joyner  * @v_list: list of VLAN entries and forwarding information
313171d10453SEric Joyner  * @recp_list: list from which function remove VLAN
313271d10453SEric Joyner  */
3133*f2635e84SEric Joyner static int
313471d10453SEric Joyner ice_remove_vlan_rule(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list,
313571d10453SEric Joyner 		     struct ice_sw_recipe *recp_list)
313671d10453SEric Joyner {
313771d10453SEric Joyner 	struct ice_fltr_list_entry *v_list_itr, *tmp;
313871d10453SEric Joyner 
313971d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(v_list_itr, tmp, v_list, ice_fltr_list_entry,
314071d10453SEric Joyner 				 list_entry) {
314171d10453SEric Joyner 		enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;
314271d10453SEric Joyner 
314371d10453SEric Joyner 		if (l_type != ICE_SW_LKUP_VLAN)
314471d10453SEric Joyner 			return ICE_ERR_PARAM;
314571d10453SEric Joyner 		v_list_itr->status = ice_remove_rule_internal(hw, recp_list,
314671d10453SEric Joyner 							      v_list_itr);
314771d10453SEric Joyner 		if (v_list_itr->status)
314871d10453SEric Joyner 			return v_list_itr->status;
314971d10453SEric Joyner 	}
3150*f2635e84SEric Joyner 	return 0;
315171d10453SEric Joyner }
315271d10453SEric Joyner 
315371d10453SEric Joyner /**
315471d10453SEric Joyner  * ice_remove_vlan - remove a VLAN address based filter rule
315571d10453SEric Joyner  * @hw: pointer to the hardware structure
315671d10453SEric Joyner  * @v_list: list of VLAN and forwarding information
315771d10453SEric Joyner  *
315871d10453SEric Joyner  */
3159*f2635e84SEric Joyner int
316071d10453SEric Joyner ice_remove_vlan(struct ice_hw *hw, struct LIST_HEAD_TYPE *v_list)
316171d10453SEric Joyner {
316271d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
316371d10453SEric Joyner 
316471d10453SEric Joyner 	if (!v_list || !hw)
316571d10453SEric Joyner 		return ICE_ERR_PARAM;
316671d10453SEric Joyner 
316771d10453SEric Joyner 	recp_list = &hw->switch_info->recp_list[ICE_SW_LKUP_VLAN];
316871d10453SEric Joyner 	return ice_remove_vlan_rule(hw, v_list, recp_list);
316971d10453SEric Joyner }
317071d10453SEric Joyner 
317171d10453SEric Joyner /**
317271d10453SEric Joyner  * ice_vsi_uses_fltr - Determine if given VSI uses specified filter
317371d10453SEric Joyner  * @fm_entry: filter entry to inspect
317471d10453SEric Joyner  * @vsi_handle: VSI handle to compare with filter info
317571d10453SEric Joyner  */
317671d10453SEric Joyner static bool
317771d10453SEric Joyner ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle)
317871d10453SEric Joyner {
317971d10453SEric Joyner 	return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&
318071d10453SEric Joyner 		 fm_entry->fltr_info.vsi_handle == vsi_handle) ||
318171d10453SEric Joyner 		(fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&
31829cf1841cSEric Joyner 		 fm_entry->vsi_list_info &&
318371d10453SEric Joyner 		 (ice_is_bit_set(fm_entry->vsi_list_info->vsi_map,
318471d10453SEric Joyner 				 vsi_handle))));
318571d10453SEric Joyner }
318671d10453SEric Joyner 
318771d10453SEric Joyner /**
318871d10453SEric Joyner  * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list
318971d10453SEric Joyner  * @hw: pointer to the hardware structure
319071d10453SEric Joyner  * @vsi_handle: VSI handle to remove filters from
319171d10453SEric Joyner  * @vsi_list_head: pointer to the list to add entry to
319271d10453SEric Joyner  * @fi: pointer to fltr_info of filter entry to copy & add
319371d10453SEric Joyner  *
319471d10453SEric Joyner  * Helper function, used when creating a list of filters to remove from
319571d10453SEric Joyner  * a specific VSI. The entry added to vsi_list_head is a COPY of the
319671d10453SEric Joyner  * original filter entry, with the exception of fltr_info.fltr_act and
319771d10453SEric Joyner  * fltr_info.fwd_id fields. These are set such that later logic can
319871d10453SEric Joyner  * extract which VSI to remove the fltr from, and pass on that information.
319971d10453SEric Joyner  */
3200*f2635e84SEric Joyner static int
320171d10453SEric Joyner ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
320271d10453SEric Joyner 			       struct LIST_HEAD_TYPE *vsi_list_head,
320371d10453SEric Joyner 			       struct ice_fltr_info *fi)
320471d10453SEric Joyner {
320571d10453SEric Joyner 	struct ice_fltr_list_entry *tmp;
320671d10453SEric Joyner 
320771d10453SEric Joyner 	/* this memory is freed up in the caller function
320871d10453SEric Joyner 	 * once filters for this VSI are removed
320971d10453SEric Joyner 	 */
321071d10453SEric Joyner 	tmp = (struct ice_fltr_list_entry *)ice_malloc(hw, sizeof(*tmp));
321171d10453SEric Joyner 	if (!tmp)
321271d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
321371d10453SEric Joyner 
321471d10453SEric Joyner 	tmp->fltr_info = *fi;
321571d10453SEric Joyner 
321671d10453SEric Joyner 	/* Overwrite these fields to indicate which VSI to remove filter from,
321771d10453SEric Joyner 	 * so find and remove logic can extract the information from the
321871d10453SEric Joyner 	 * list entries. Note that original entries will still have proper
321971d10453SEric Joyner 	 * values.
322071d10453SEric Joyner 	 */
322171d10453SEric Joyner 	tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
322271d10453SEric Joyner 	tmp->fltr_info.vsi_handle = vsi_handle;
322371d10453SEric Joyner 	tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
322471d10453SEric Joyner 
322571d10453SEric Joyner 	LIST_ADD(&tmp->list_entry, vsi_list_head);
322671d10453SEric Joyner 
3227*f2635e84SEric Joyner 	return 0;
322871d10453SEric Joyner }
322971d10453SEric Joyner 
323071d10453SEric Joyner /**
323171d10453SEric Joyner  * ice_add_to_vsi_fltr_list - Add VSI filters to the list
323271d10453SEric Joyner  * @hw: pointer to the hardware structure
323371d10453SEric Joyner  * @vsi_handle: VSI handle to remove filters from
323471d10453SEric Joyner  * @lkup_list_head: pointer to the list that has certain lookup type filters
323571d10453SEric Joyner  * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle
323671d10453SEric Joyner  *
323771d10453SEric Joyner  * Locates all filters in lkup_list_head that are used by the given VSI,
323871d10453SEric Joyner  * and adds COPIES of those entries to vsi_list_head (intended to be used
323971d10453SEric Joyner  * to remove the listed filters).
324071d10453SEric Joyner  * Note that this means all entries in vsi_list_head must be explicitly
324171d10453SEric Joyner  * deallocated by the caller when done with list.
324271d10453SEric Joyner  */
3243*f2635e84SEric Joyner static int
324471d10453SEric Joyner ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
324571d10453SEric Joyner 			 struct LIST_HEAD_TYPE *lkup_list_head,
324671d10453SEric Joyner 			 struct LIST_HEAD_TYPE *vsi_list_head)
324771d10453SEric Joyner {
324871d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *fm_entry;
3249*f2635e84SEric Joyner 	int status = 0;
325071d10453SEric Joyner 
325171d10453SEric Joyner 	/* check to make sure VSI ID is valid and within boundary */
325271d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle))
325371d10453SEric Joyner 		return ICE_ERR_PARAM;
325471d10453SEric Joyner 
325571d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(fm_entry, lkup_list_head,
325671d10453SEric Joyner 			    ice_fltr_mgmt_list_entry, list_entry) {
32579cf1841cSEric Joyner 		if (!ice_vsi_uses_fltr(fm_entry, vsi_handle))
325871d10453SEric Joyner 			continue;
325971d10453SEric Joyner 
326071d10453SEric Joyner 		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
32619cf1841cSEric Joyner 							vsi_list_head,
32629cf1841cSEric Joyner 							&fm_entry->fltr_info);
326371d10453SEric Joyner 		if (status)
326471d10453SEric Joyner 			return status;
326571d10453SEric Joyner 	}
326671d10453SEric Joyner 	return status;
326771d10453SEric Joyner }
326871d10453SEric Joyner 
326971d10453SEric Joyner /**
327071d10453SEric Joyner  * ice_determine_promisc_mask
327171d10453SEric Joyner  * @fi: filter info to parse
32729c30461dSEric Joyner  * @promisc_mask: pointer to mask to be filled in
327371d10453SEric Joyner  *
327471d10453SEric Joyner  * Helper function to determine which ICE_PROMISC_ mask corresponds
327571d10453SEric Joyner  * to given filter into.
327671d10453SEric Joyner  */
32779c30461dSEric Joyner static void ice_determine_promisc_mask(struct ice_fltr_info *fi,
32789c30461dSEric Joyner 				       ice_bitmap_t *promisc_mask)
327971d10453SEric Joyner {
328071d10453SEric Joyner 	u16 vid = fi->l_data.mac_vlan.vlan_id;
328171d10453SEric Joyner 	u8 *macaddr = fi->l_data.mac.mac_addr;
32829e54973fSEric Joyner 	bool is_rx_lb_fltr = false;
328371d10453SEric Joyner 	bool is_tx_fltr = false;
32849c30461dSEric Joyner 
32859c30461dSEric Joyner 	ice_zero_bitmap(promisc_mask, ICE_PROMISC_MAX);
328671d10453SEric Joyner 
328771d10453SEric Joyner 	if (fi->flag == ICE_FLTR_TX)
328871d10453SEric Joyner 		is_tx_fltr = true;
32899e54973fSEric Joyner 	if (fi->flag == ICE_FLTR_RX_LB)
32909e54973fSEric Joyner 		is_rx_lb_fltr = true;
329171d10453SEric Joyner 
32929c30461dSEric Joyner 	if (IS_BROADCAST_ETHER_ADDR(macaddr)) {
32939c30461dSEric Joyner 		ice_set_bit(is_tx_fltr ? ICE_PROMISC_BCAST_TX
32949c30461dSEric Joyner 				       : ICE_PROMISC_BCAST_RX, promisc_mask);
32959c30461dSEric Joyner 	} else if (IS_MULTICAST_ETHER_ADDR(macaddr)) {
32969c30461dSEric Joyner 		ice_set_bit(is_tx_fltr ? ICE_PROMISC_MCAST_TX
32979c30461dSEric Joyner 				       : ICE_PROMISC_MCAST_RX, promisc_mask);
32989c30461dSEric Joyner 	} else if (IS_UNICAST_ETHER_ADDR(macaddr)) {
32999e54973fSEric Joyner 		if (is_tx_fltr)
33009e54973fSEric Joyner 			ice_set_bit(ICE_PROMISC_UCAST_TX, promisc_mask);
33019e54973fSEric Joyner 		else if (is_rx_lb_fltr)
33029e54973fSEric Joyner 			ice_set_bit(ICE_PROMISC_UCAST_RX_LB, promisc_mask);
33039e54973fSEric Joyner 		else
33049e54973fSEric Joyner 			ice_set_bit(ICE_PROMISC_UCAST_RX, promisc_mask);
33059c30461dSEric Joyner 	}
330671d10453SEric Joyner 
33079c30461dSEric Joyner 	if (vid) {
33089c30461dSEric Joyner 		ice_set_bit(is_tx_fltr ? ICE_PROMISC_VLAN_TX
33099c30461dSEric Joyner 				       : ICE_PROMISC_VLAN_RX, promisc_mask);
33109c30461dSEric Joyner 	}
331171d10453SEric Joyner }
331271d10453SEric Joyner 
331371d10453SEric Joyner /**
33147d7af7f8SEric Joyner  * _ice_get_vsi_promisc - get promiscuous mode of given VSI
331571d10453SEric Joyner  * @hw: pointer to the hardware structure
331671d10453SEric Joyner  * @vsi_handle: VSI handle to retrieve info from
331771d10453SEric Joyner  * @promisc_mask: pointer to mask to be filled in
331871d10453SEric Joyner  * @vid: VLAN ID of promisc VLAN VSI
33197d7af7f8SEric Joyner  * @sw: pointer to switch info struct for which function add rule
332056429daeSEric Joyner  * @lkup: switch rule filter lookup type
332171d10453SEric Joyner  */
3322*f2635e84SEric Joyner static int
33239c30461dSEric Joyner _ice_get_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
33249c30461dSEric Joyner 		     ice_bitmap_t *promisc_mask, u16 *vid,
33259c30461dSEric Joyner 		     struct ice_switch_info *sw, enum ice_sw_lkup_type lkup)
332671d10453SEric Joyner {
33279c30461dSEric Joyner 	ice_declare_bitmap(fltr_promisc_mask, ICE_PROMISC_MAX);
332871d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *itr;
332971d10453SEric Joyner 	struct LIST_HEAD_TYPE *rule_head;
333071d10453SEric Joyner 	struct ice_lock *rule_lock;	/* Lock to protect filter rule list */
333171d10453SEric Joyner 
333256429daeSEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle) ||
333356429daeSEric Joyner 	    (lkup != ICE_SW_LKUP_PROMISC && lkup != ICE_SW_LKUP_PROMISC_VLAN))
333471d10453SEric Joyner 		return ICE_ERR_PARAM;
333571d10453SEric Joyner 
333671d10453SEric Joyner 	*vid = 0;
333756429daeSEric Joyner 	rule_head = &sw->recp_list[lkup].filt_rules;
333856429daeSEric Joyner 	rule_lock = &sw->recp_list[lkup].filt_rule_lock;
333971d10453SEric Joyner 
33409c30461dSEric Joyner 	ice_zero_bitmap(promisc_mask, ICE_PROMISC_MAX);
33419c30461dSEric Joyner 
334271d10453SEric Joyner 	ice_acquire_lock(rule_lock);
334371d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(itr, rule_head,
334471d10453SEric Joyner 			    ice_fltr_mgmt_list_entry, list_entry) {
334571d10453SEric Joyner 		/* Continue if this filter doesn't apply to this VSI or the
334671d10453SEric Joyner 		 * VSI ID is not in the VSI map for this filter
334771d10453SEric Joyner 		 */
334871d10453SEric Joyner 		if (!ice_vsi_uses_fltr(itr, vsi_handle))
334971d10453SEric Joyner 			continue;
335071d10453SEric Joyner 
33519c30461dSEric Joyner 		ice_determine_promisc_mask(&itr->fltr_info, fltr_promisc_mask);
33529c30461dSEric Joyner 		ice_or_bitmap(promisc_mask, promisc_mask, fltr_promisc_mask,
33539c30461dSEric Joyner 			      ICE_PROMISC_MAX);
33549c30461dSEric Joyner 
335571d10453SEric Joyner 	}
335671d10453SEric Joyner 	ice_release_lock(rule_lock);
335771d10453SEric Joyner 
3358*f2635e84SEric Joyner 	return 0;
335971d10453SEric Joyner }
336071d10453SEric Joyner 
336171d10453SEric Joyner /**
33627d7af7f8SEric Joyner  * ice_get_vsi_promisc - get promiscuous mode of given VSI
336371d10453SEric Joyner  * @hw: pointer to the hardware structure
336471d10453SEric Joyner  * @vsi_handle: VSI handle to retrieve info from
336571d10453SEric Joyner  * @promisc_mask: pointer to mask to be filled in
336671d10453SEric Joyner  * @vid: VLAN ID of promisc VLAN VSI
336771d10453SEric Joyner  */
3368*f2635e84SEric Joyner int
33699c30461dSEric Joyner ice_get_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
33709c30461dSEric Joyner 		    ice_bitmap_t *promisc_mask, u16 *vid)
337171d10453SEric Joyner {
33729c30461dSEric Joyner 	if (!vid || !promisc_mask || !hw)
33739c30461dSEric Joyner 		return ICE_ERR_PARAM;
33749c30461dSEric Joyner 
33757d7af7f8SEric Joyner 	return _ice_get_vsi_promisc(hw, vsi_handle, promisc_mask,
337656429daeSEric Joyner 				    vid, hw->switch_info, ICE_SW_LKUP_PROMISC);
337771d10453SEric Joyner }
337871d10453SEric Joyner 
337971d10453SEric Joyner /**
33807d7af7f8SEric Joyner  * ice_get_vsi_vlan_promisc - get VLAN promiscuous mode of given VSI
33817d7af7f8SEric Joyner  * @hw: pointer to the hardware structure
33827d7af7f8SEric Joyner  * @vsi_handle: VSI handle to retrieve info from
33837d7af7f8SEric Joyner  * @promisc_mask: pointer to mask to be filled in
33847d7af7f8SEric Joyner  * @vid: VLAN ID of promisc VLAN VSI
33857d7af7f8SEric Joyner  */
3386*f2635e84SEric Joyner int
33879c30461dSEric Joyner ice_get_vsi_vlan_promisc(struct ice_hw *hw, u16 vsi_handle,
33889c30461dSEric Joyner 			 ice_bitmap_t *promisc_mask, u16 *vid)
33897d7af7f8SEric Joyner {
33909c30461dSEric Joyner 	if (!hw || !promisc_mask || !vid)
33919c30461dSEric Joyner 		return ICE_ERR_PARAM;
33929c30461dSEric Joyner 
339356429daeSEric Joyner 	return _ice_get_vsi_promisc(hw, vsi_handle, promisc_mask,
339456429daeSEric Joyner 				    vid, hw->switch_info,
339556429daeSEric Joyner 				    ICE_SW_LKUP_PROMISC_VLAN);
33967d7af7f8SEric Joyner }
33977d7af7f8SEric Joyner 
33987d7af7f8SEric Joyner /**
339971d10453SEric Joyner  * ice_remove_promisc - Remove promisc based filter rules
340071d10453SEric Joyner  * @hw: pointer to the hardware structure
340171d10453SEric Joyner  * @recp_id: recipe ID for which the rule needs to removed
340271d10453SEric Joyner  * @v_list: list of promisc entries
340371d10453SEric Joyner  */
3404*f2635e84SEric Joyner static int
340571d10453SEric Joyner ice_remove_promisc(struct ice_hw *hw, u8 recp_id,
340671d10453SEric Joyner 		   struct LIST_HEAD_TYPE *v_list)
340771d10453SEric Joyner {
340871d10453SEric Joyner 	struct ice_fltr_list_entry *v_list_itr, *tmp;
340971d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
341071d10453SEric Joyner 
341171d10453SEric Joyner 	recp_list = &hw->switch_info->recp_list[recp_id];
341271d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(v_list_itr, tmp, v_list, ice_fltr_list_entry,
341371d10453SEric Joyner 				 list_entry) {
341471d10453SEric Joyner 		v_list_itr->status =
341571d10453SEric Joyner 			ice_remove_rule_internal(hw, recp_list, v_list_itr);
341671d10453SEric Joyner 		if (v_list_itr->status)
341771d10453SEric Joyner 			return v_list_itr->status;
341871d10453SEric Joyner 	}
3419*f2635e84SEric Joyner 	return 0;
342071d10453SEric Joyner }
342171d10453SEric Joyner 
342271d10453SEric Joyner /**
34237d7af7f8SEric Joyner  * _ice_clear_vsi_promisc - clear specified promiscuous mode(s)
342471d10453SEric Joyner  * @hw: pointer to the hardware structure
342571d10453SEric Joyner  * @vsi_handle: VSI handle to clear mode
34269c30461dSEric Joyner  * @promisc_mask: pointer to mask of promiscuous config bits to clear
342771d10453SEric Joyner  * @vid: VLAN ID to clear VLAN promiscuous
34287d7af7f8SEric Joyner  * @sw: pointer to switch info struct for which function add rule
342971d10453SEric Joyner  */
3430*f2635e84SEric Joyner static int
34319c30461dSEric Joyner _ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
34329c30461dSEric Joyner 		       ice_bitmap_t *promisc_mask, u16 vid,
34339c30461dSEric Joyner 		       struct ice_switch_info *sw)
343471d10453SEric Joyner {
34359c30461dSEric Joyner 	ice_declare_bitmap(compl_promisc_mask, ICE_PROMISC_MAX);
34369c30461dSEric Joyner 	ice_declare_bitmap(fltr_promisc_mask, ICE_PROMISC_MAX);
343771d10453SEric Joyner 	struct ice_fltr_list_entry *fm_entry, *tmp;
343871d10453SEric Joyner 	struct LIST_HEAD_TYPE remove_list_head;
343971d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *itr;
344071d10453SEric Joyner 	struct LIST_HEAD_TYPE *rule_head;
344171d10453SEric Joyner 	struct ice_lock *rule_lock;	/* Lock to protect filter rule list */
3442*f2635e84SEric Joyner 	int status = 0;
344371d10453SEric Joyner 	u8 recipe_id;
344471d10453SEric Joyner 
344571d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle))
344671d10453SEric Joyner 		return ICE_ERR_PARAM;
344771d10453SEric Joyner 
34489c30461dSEric Joyner 	if (ice_is_bit_set(promisc_mask, ICE_PROMISC_VLAN_RX) &&
34499c30461dSEric Joyner 	    ice_is_bit_set(promisc_mask, ICE_PROMISC_VLAN_TX))
345071d10453SEric Joyner 		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
345171d10453SEric Joyner 	else
345271d10453SEric Joyner 		recipe_id = ICE_SW_LKUP_PROMISC;
345371d10453SEric Joyner 
345471d10453SEric Joyner 	rule_head = &sw->recp_list[recipe_id].filt_rules;
345571d10453SEric Joyner 	rule_lock = &sw->recp_list[recipe_id].filt_rule_lock;
345671d10453SEric Joyner 
345771d10453SEric Joyner 	INIT_LIST_HEAD(&remove_list_head);
345871d10453SEric Joyner 
345971d10453SEric Joyner 	ice_acquire_lock(rule_lock);
346071d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(itr, rule_head,
346171d10453SEric Joyner 			    ice_fltr_mgmt_list_entry, list_entry) {
346271d10453SEric Joyner 		struct ice_fltr_info *fltr_info;
34639c30461dSEric Joyner 		ice_zero_bitmap(compl_promisc_mask, ICE_PROMISC_MAX);
346471d10453SEric Joyner 
346571d10453SEric Joyner 		if (!ice_vsi_uses_fltr(itr, vsi_handle))
346671d10453SEric Joyner 			continue;
346771d10453SEric Joyner 		fltr_info = &itr->fltr_info;
346871d10453SEric Joyner 
346971d10453SEric Joyner 		if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN &&
347071d10453SEric Joyner 		    vid != fltr_info->l_data.mac_vlan.vlan_id)
347171d10453SEric Joyner 			continue;
347271d10453SEric Joyner 
34739c30461dSEric Joyner 		ice_determine_promisc_mask(fltr_info, fltr_promisc_mask);
34749c30461dSEric Joyner 		ice_andnot_bitmap(compl_promisc_mask, fltr_promisc_mask,
34759c30461dSEric Joyner 				  promisc_mask, ICE_PROMISC_MAX);
347671d10453SEric Joyner 
347771d10453SEric Joyner 		/* Skip if filter is not completely specified by given mask */
34789c30461dSEric Joyner 		if (ice_is_any_bit_set(compl_promisc_mask, ICE_PROMISC_MAX))
347971d10453SEric Joyner 			continue;
348071d10453SEric Joyner 
348171d10453SEric Joyner 		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
348271d10453SEric Joyner 							&remove_list_head,
348371d10453SEric Joyner 							fltr_info);
348471d10453SEric Joyner 		if (status) {
348571d10453SEric Joyner 			ice_release_lock(rule_lock);
348671d10453SEric Joyner 			goto free_fltr_list;
348771d10453SEric Joyner 		}
348871d10453SEric Joyner 	}
348971d10453SEric Joyner 	ice_release_lock(rule_lock);
349071d10453SEric Joyner 
349171d10453SEric Joyner 	status = ice_remove_promisc(hw, recipe_id, &remove_list_head);
349271d10453SEric Joyner 
349371d10453SEric Joyner free_fltr_list:
349471d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(fm_entry, tmp, &remove_list_head,
349571d10453SEric Joyner 				 ice_fltr_list_entry, list_entry) {
349671d10453SEric Joyner 		LIST_DEL(&fm_entry->list_entry);
349771d10453SEric Joyner 		ice_free(hw, fm_entry);
349871d10453SEric Joyner 	}
349971d10453SEric Joyner 
350071d10453SEric Joyner 	return status;
350171d10453SEric Joyner }
350271d10453SEric Joyner 
350371d10453SEric Joyner /**
35047d7af7f8SEric Joyner  * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI
35057d7af7f8SEric Joyner  * @hw: pointer to the hardware structure
35067d7af7f8SEric Joyner  * @vsi_handle: VSI handle to clear mode
35079c30461dSEric Joyner  * @promisc_mask: pointer to mask of promiscuous config bits to clear
35087d7af7f8SEric Joyner  * @vid: VLAN ID to clear VLAN promiscuous
35097d7af7f8SEric Joyner  */
3510*f2635e84SEric Joyner int
35117d7af7f8SEric Joyner ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
35129c30461dSEric Joyner 		      ice_bitmap_t *promisc_mask, u16 vid)
35137d7af7f8SEric Joyner {
35149c30461dSEric Joyner 	if (!hw || !promisc_mask)
35159c30461dSEric Joyner 		return ICE_ERR_PARAM;
35169c30461dSEric Joyner 
35177d7af7f8SEric Joyner 	return _ice_clear_vsi_promisc(hw, vsi_handle, promisc_mask,
35187d7af7f8SEric Joyner 				      vid, hw->switch_info);
35197d7af7f8SEric Joyner }
35207d7af7f8SEric Joyner 
35217d7af7f8SEric Joyner /**
35227d7af7f8SEric Joyner  * _ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)
352371d10453SEric Joyner  * @hw: pointer to the hardware structure
352471d10453SEric Joyner  * @vsi_handle: VSI handle to configure
35259c30461dSEric Joyner  * @promisc_mask: pointer to mask of promiscuous config bits
352671d10453SEric Joyner  * @vid: VLAN ID to set VLAN promiscuous
35277d7af7f8SEric Joyner  * @lport: logical port number to configure promisc mode
35287d7af7f8SEric Joyner  * @sw: pointer to switch info struct for which function add rule
352971d10453SEric Joyner  */
3530*f2635e84SEric Joyner static int
35319c30461dSEric Joyner _ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
35329c30461dSEric Joyner 		     ice_bitmap_t *promisc_mask, u16 vid, u8 lport,
35339c30461dSEric Joyner 		     struct ice_switch_info *sw)
353471d10453SEric Joyner {
353571d10453SEric Joyner 	enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR };
35369c30461dSEric Joyner 	ice_declare_bitmap(p_mask, ICE_PROMISC_MAX);
353771d10453SEric Joyner 	struct ice_fltr_list_entry f_list_entry;
35389e54973fSEric Joyner 	bool is_tx_fltr, is_rx_lb_fltr;
3539*f2635e84SEric Joyner 	struct ice_fltr_info new_fltr;
3540*f2635e84SEric Joyner 	int status = 0;
354171d10453SEric Joyner 	u16 hw_vsi_id;
354271d10453SEric Joyner 	int pkt_type;
354371d10453SEric Joyner 	u8 recipe_id;
354471d10453SEric Joyner 
354571d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
354671d10453SEric Joyner 
354771d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle))
354871d10453SEric Joyner 		return ICE_ERR_PARAM;
354971d10453SEric Joyner 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
355071d10453SEric Joyner 
355171d10453SEric Joyner 	ice_memset(&new_fltr, 0, sizeof(new_fltr), ICE_NONDMA_MEM);
355271d10453SEric Joyner 
35539c30461dSEric Joyner 	/* Do not modify original bitmap */
35549c30461dSEric Joyner 	ice_cp_bitmap(p_mask, promisc_mask, ICE_PROMISC_MAX);
35559c30461dSEric Joyner 
35569c30461dSEric Joyner 	if (ice_is_bit_set(p_mask, ICE_PROMISC_VLAN_RX) &&
35579c30461dSEric Joyner 	    ice_is_bit_set(p_mask, ICE_PROMISC_VLAN_TX)) {
355871d10453SEric Joyner 		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN;
355971d10453SEric Joyner 		new_fltr.l_data.mac_vlan.vlan_id = vid;
356071d10453SEric Joyner 		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
356171d10453SEric Joyner 	} else {
356271d10453SEric Joyner 		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC;
356371d10453SEric Joyner 		recipe_id = ICE_SW_LKUP_PROMISC;
356471d10453SEric Joyner 	}
356571d10453SEric Joyner 
356671d10453SEric Joyner 	/* Separate filters must be set for each direction/packet type
356771d10453SEric Joyner 	 * combination, so we will loop over the mask value, store the
356871d10453SEric Joyner 	 * individual type, and clear it out in the input mask as it
356971d10453SEric Joyner 	 * is found.
357071d10453SEric Joyner 	 */
35719c30461dSEric Joyner 	while (ice_is_any_bit_set(p_mask, ICE_PROMISC_MAX)) {
357271d10453SEric Joyner 		struct ice_sw_recipe *recp_list;
357371d10453SEric Joyner 		u8 *mac_addr;
357471d10453SEric Joyner 
357571d10453SEric Joyner 		pkt_type = 0;
357671d10453SEric Joyner 		is_tx_fltr = false;
35779e54973fSEric Joyner 		is_rx_lb_fltr = false;
357871d10453SEric Joyner 
35799c30461dSEric Joyner 		if (ice_test_and_clear_bit(ICE_PROMISC_UCAST_RX,
35809c30461dSEric Joyner 					   p_mask)) {
358171d10453SEric Joyner 			pkt_type = UCAST_FLTR;
35829c30461dSEric Joyner 		} else if (ice_test_and_clear_bit(ICE_PROMISC_UCAST_TX,
35839c30461dSEric Joyner 						  p_mask)) {
358471d10453SEric Joyner 			pkt_type = UCAST_FLTR;
358571d10453SEric Joyner 			is_tx_fltr = true;
35869c30461dSEric Joyner 		} else if (ice_test_and_clear_bit(ICE_PROMISC_MCAST_RX,
35879c30461dSEric Joyner 						  p_mask)) {
358871d10453SEric Joyner 			pkt_type = MCAST_FLTR;
35899c30461dSEric Joyner 		} else if (ice_test_and_clear_bit(ICE_PROMISC_MCAST_TX,
35909c30461dSEric Joyner 						  p_mask)) {
359171d10453SEric Joyner 			pkt_type = MCAST_FLTR;
359271d10453SEric Joyner 			is_tx_fltr = true;
35939c30461dSEric Joyner 		} else if (ice_test_and_clear_bit(ICE_PROMISC_BCAST_RX,
35949c30461dSEric Joyner 						  p_mask)) {
359571d10453SEric Joyner 			pkt_type = BCAST_FLTR;
35969c30461dSEric Joyner 		} else if (ice_test_and_clear_bit(ICE_PROMISC_BCAST_TX,
35979c30461dSEric Joyner 						  p_mask)) {
359871d10453SEric Joyner 			pkt_type = BCAST_FLTR;
359971d10453SEric Joyner 			is_tx_fltr = true;
36009e54973fSEric Joyner 		} else if (ice_test_and_clear_bit(ICE_PROMISC_UCAST_RX_LB,
36019e54973fSEric Joyner 						  p_mask)) {
36029e54973fSEric Joyner 			pkt_type = UCAST_FLTR;
36039e54973fSEric Joyner 			is_rx_lb_fltr = true;
360471d10453SEric Joyner 		}
360571d10453SEric Joyner 
360671d10453SEric Joyner 		/* Check for VLAN promiscuous flag */
36079c30461dSEric Joyner 		if (ice_is_bit_set(p_mask, ICE_PROMISC_VLAN_RX)) {
36089c30461dSEric Joyner 			ice_clear_bit(ICE_PROMISC_VLAN_RX, p_mask);
36099c30461dSEric Joyner 		} else if (ice_test_and_clear_bit(ICE_PROMISC_VLAN_TX,
36109c30461dSEric Joyner 						  p_mask)) {
361171d10453SEric Joyner 			is_tx_fltr = true;
361271d10453SEric Joyner 		}
361371d10453SEric Joyner 		/* Set filter DA based on packet type */
361471d10453SEric Joyner 		mac_addr = new_fltr.l_data.mac.mac_addr;
361571d10453SEric Joyner 		if (pkt_type == BCAST_FLTR) {
361671d10453SEric Joyner 			ice_memset(mac_addr, 0xff, ETH_ALEN, ICE_NONDMA_MEM);
361771d10453SEric Joyner 		} else if (pkt_type == MCAST_FLTR ||
361871d10453SEric Joyner 			   pkt_type == UCAST_FLTR) {
361971d10453SEric Joyner 			/* Use the dummy ether header DA */
362071d10453SEric Joyner 			ice_memcpy(mac_addr, dummy_eth_header, ETH_ALEN,
362171d10453SEric Joyner 				   ICE_NONDMA_TO_NONDMA);
362271d10453SEric Joyner 			if (pkt_type == MCAST_FLTR)
362371d10453SEric Joyner 				mac_addr[0] |= 0x1;	/* Set multicast bit */
362471d10453SEric Joyner 		}
362571d10453SEric Joyner 
362671d10453SEric Joyner 		/* Need to reset this to zero for all iterations */
362771d10453SEric Joyner 		new_fltr.flag = 0;
362871d10453SEric Joyner 		if (is_tx_fltr) {
362971d10453SEric Joyner 			new_fltr.flag |= ICE_FLTR_TX;
363071d10453SEric Joyner 			new_fltr.src = hw_vsi_id;
36319e54973fSEric Joyner 		} else if (is_rx_lb_fltr) {
36329e54973fSEric Joyner 			new_fltr.flag |= ICE_FLTR_RX_LB;
36339e54973fSEric Joyner 			new_fltr.src = hw_vsi_id;
363471d10453SEric Joyner 		} else {
363571d10453SEric Joyner 			new_fltr.flag |= ICE_FLTR_RX;
36367d7af7f8SEric Joyner 			new_fltr.src = lport;
363771d10453SEric Joyner 		}
363871d10453SEric Joyner 
363971d10453SEric Joyner 		new_fltr.fltr_act = ICE_FWD_TO_VSI;
364071d10453SEric Joyner 		new_fltr.vsi_handle = vsi_handle;
364171d10453SEric Joyner 		new_fltr.fwd_id.hw_vsi_id = hw_vsi_id;
364271d10453SEric Joyner 		f_list_entry.fltr_info = new_fltr;
36437d7af7f8SEric Joyner 		recp_list = &sw->recp_list[recipe_id];
364471d10453SEric Joyner 
36457d7af7f8SEric Joyner 		status = ice_add_rule_internal(hw, recp_list, lport,
364671d10453SEric Joyner 					       &f_list_entry);
3647*f2635e84SEric Joyner 		if (status)
364871d10453SEric Joyner 			goto set_promisc_exit;
364971d10453SEric Joyner 	}
365071d10453SEric Joyner 
365171d10453SEric Joyner set_promisc_exit:
365271d10453SEric Joyner 	return status;
365371d10453SEric Joyner }
365471d10453SEric Joyner 
365571d10453SEric Joyner /**
36567d7af7f8SEric Joyner  * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)
36577d7af7f8SEric Joyner  * @hw: pointer to the hardware structure
36587d7af7f8SEric Joyner  * @vsi_handle: VSI handle to configure
36599c30461dSEric Joyner  * @promisc_mask: pointer to mask of promiscuous config bits
36607d7af7f8SEric Joyner  * @vid: VLAN ID to set VLAN promiscuous
36617d7af7f8SEric Joyner  */
3662*f2635e84SEric Joyner int
36639c30461dSEric Joyner ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
36649c30461dSEric Joyner 		    ice_bitmap_t *promisc_mask, u16 vid)
36657d7af7f8SEric Joyner {
36669c30461dSEric Joyner 	if (!hw || !promisc_mask)
36679c30461dSEric Joyner 		return ICE_ERR_PARAM;
36689c30461dSEric Joyner 
36697d7af7f8SEric Joyner 	return _ice_set_vsi_promisc(hw, vsi_handle, promisc_mask, vid,
36707d7af7f8SEric Joyner 				    hw->port_info->lport,
36717d7af7f8SEric Joyner 				    hw->switch_info);
36727d7af7f8SEric Joyner }
36737d7af7f8SEric Joyner 
36747d7af7f8SEric Joyner /**
36757d7af7f8SEric Joyner  * _ice_set_vlan_vsi_promisc
367671d10453SEric Joyner  * @hw: pointer to the hardware structure
367771d10453SEric Joyner  * @vsi_handle: VSI handle to configure
36789c30461dSEric Joyner  * @promisc_mask: pointer to mask of promiscuous config bits
367971d10453SEric Joyner  * @rm_vlan_promisc: Clear VLANs VSI promisc mode
36807d7af7f8SEric Joyner  * @lport: logical port number to configure promisc mode
36817d7af7f8SEric Joyner  * @sw: pointer to switch info struct for which function add rule
368271d10453SEric Joyner  *
368371d10453SEric Joyner  * Configure VSI with all associated VLANs to given promiscuous mode(s)
368471d10453SEric Joyner  */
3685*f2635e84SEric Joyner static int
36869c30461dSEric Joyner _ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
36879c30461dSEric Joyner 			  ice_bitmap_t *promisc_mask, bool rm_vlan_promisc,
36889c30461dSEric Joyner 			  u8 lport, struct ice_switch_info *sw)
368971d10453SEric Joyner {
369071d10453SEric Joyner 	struct ice_fltr_list_entry *list_itr, *tmp;
369171d10453SEric Joyner 	struct LIST_HEAD_TYPE vsi_list_head;
369271d10453SEric Joyner 	struct LIST_HEAD_TYPE *vlan_head;
369371d10453SEric Joyner 	struct ice_lock *vlan_lock; /* Lock to protect filter rule list */
3694*f2635e84SEric Joyner 	int status;
369571d10453SEric Joyner 	u16 vlan_id;
369671d10453SEric Joyner 
369771d10453SEric Joyner 	INIT_LIST_HEAD(&vsi_list_head);
369871d10453SEric Joyner 	vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
369971d10453SEric Joyner 	vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
370071d10453SEric Joyner 	ice_acquire_lock(vlan_lock);
370171d10453SEric Joyner 	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head,
370271d10453SEric Joyner 					  &vsi_list_head);
370371d10453SEric Joyner 	ice_release_lock(vlan_lock);
370471d10453SEric Joyner 	if (status)
370571d10453SEric Joyner 		goto free_fltr_list;
370671d10453SEric Joyner 
370771d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(list_itr, &vsi_list_head, ice_fltr_list_entry,
370871d10453SEric Joyner 			    list_entry) {
37098923de59SPiotr Kubaj 		/* Avoid enabling or disabling vlan zero twice when in double
37108923de59SPiotr Kubaj 		 * vlan mode
37118923de59SPiotr Kubaj 		 */
37128923de59SPiotr Kubaj 		if (ice_is_dvm_ena(hw) &&
37138923de59SPiotr Kubaj 		    list_itr->fltr_info.l_data.vlan.tpid == 0)
37148923de59SPiotr Kubaj 			continue;
37158923de59SPiotr Kubaj 
371671d10453SEric Joyner 		vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
371771d10453SEric Joyner 		if (rm_vlan_promisc)
37187d7af7f8SEric Joyner 			status =  _ice_clear_vsi_promisc(hw, vsi_handle,
37197d7af7f8SEric Joyner 							 promisc_mask,
37207d7af7f8SEric Joyner 							 vlan_id, sw);
372171d10453SEric Joyner 		else
37227d7af7f8SEric Joyner 			status =  _ice_set_vsi_promisc(hw, vsi_handle,
37237d7af7f8SEric Joyner 						       promisc_mask, vlan_id,
37247d7af7f8SEric Joyner 						       lport, sw);
37258923de59SPiotr Kubaj 		if (status && status != ICE_ERR_ALREADY_EXISTS)
372671d10453SEric Joyner 			break;
372771d10453SEric Joyner 	}
372871d10453SEric Joyner 
372971d10453SEric Joyner free_fltr_list:
373071d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(list_itr, tmp, &vsi_list_head,
373171d10453SEric Joyner 				 ice_fltr_list_entry, list_entry) {
373271d10453SEric Joyner 		LIST_DEL(&list_itr->list_entry);
373371d10453SEric Joyner 		ice_free(hw, list_itr);
373471d10453SEric Joyner 	}
373571d10453SEric Joyner 	return status;
373671d10453SEric Joyner }
373771d10453SEric Joyner 
373871d10453SEric Joyner /**
37397d7af7f8SEric Joyner  * ice_set_vlan_vsi_promisc
37407d7af7f8SEric Joyner  * @hw: pointer to the hardware structure
37417d7af7f8SEric Joyner  * @vsi_handle: VSI handle to configure
37427d7af7f8SEric Joyner  * @promisc_mask: mask of promiscuous config bits
37437d7af7f8SEric Joyner  * @rm_vlan_promisc: Clear VLANs VSI promisc mode
37447d7af7f8SEric Joyner  *
37457d7af7f8SEric Joyner  * Configure VSI with all associated VLANs to given promiscuous mode(s)
37467d7af7f8SEric Joyner  */
3747*f2635e84SEric Joyner int
37489c30461dSEric Joyner ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle,
37499c30461dSEric Joyner 			 ice_bitmap_t *promisc_mask, bool rm_vlan_promisc)
37507d7af7f8SEric Joyner {
37519c30461dSEric Joyner 	if (!hw || !promisc_mask)
37529c30461dSEric Joyner 		return ICE_ERR_PARAM;
37539c30461dSEric Joyner 
37547d7af7f8SEric Joyner 	return _ice_set_vlan_vsi_promisc(hw, vsi_handle, promisc_mask,
37557d7af7f8SEric Joyner 					 rm_vlan_promisc, hw->port_info->lport,
37567d7af7f8SEric Joyner 					 hw->switch_info);
37577d7af7f8SEric Joyner }
37587d7af7f8SEric Joyner 
37597d7af7f8SEric Joyner /**
376071d10453SEric Joyner  * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI
376171d10453SEric Joyner  * @hw: pointer to the hardware structure
376271d10453SEric Joyner  * @vsi_handle: VSI handle to remove filters from
376371d10453SEric Joyner  * @recp_list: recipe list from which function remove fltr
376471d10453SEric Joyner  * @lkup: switch rule filter lookup type
376571d10453SEric Joyner  */
376671d10453SEric Joyner static void
376771d10453SEric Joyner ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,
376871d10453SEric Joyner 			 struct ice_sw_recipe *recp_list,
376971d10453SEric Joyner 			 enum ice_sw_lkup_type lkup)
377071d10453SEric Joyner {
377171d10453SEric Joyner 	struct ice_fltr_list_entry *fm_entry;
377271d10453SEric Joyner 	struct LIST_HEAD_TYPE remove_list_head;
377371d10453SEric Joyner 	struct LIST_HEAD_TYPE *rule_head;
377471d10453SEric Joyner 	struct ice_fltr_list_entry *tmp;
377571d10453SEric Joyner 	struct ice_lock *rule_lock;	/* Lock to protect filter rule list */
3776*f2635e84SEric Joyner 	int status;
377771d10453SEric Joyner 
377871d10453SEric Joyner 	INIT_LIST_HEAD(&remove_list_head);
377971d10453SEric Joyner 	rule_lock = &recp_list[lkup].filt_rule_lock;
378071d10453SEric Joyner 	rule_head = &recp_list[lkup].filt_rules;
378171d10453SEric Joyner 	ice_acquire_lock(rule_lock);
378271d10453SEric Joyner 	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head,
378371d10453SEric Joyner 					  &remove_list_head);
378471d10453SEric Joyner 	ice_release_lock(rule_lock);
378571d10453SEric Joyner 	if (status)
37869cf1841cSEric Joyner 		goto free_fltr_list;
378771d10453SEric Joyner 
378871d10453SEric Joyner 	switch (lkup) {
378971d10453SEric Joyner 	case ICE_SW_LKUP_MAC:
379071d10453SEric Joyner 		ice_remove_mac_rule(hw, &remove_list_head, &recp_list[lkup]);
379171d10453SEric Joyner 		break;
379271d10453SEric Joyner 	case ICE_SW_LKUP_VLAN:
379371d10453SEric Joyner 		ice_remove_vlan_rule(hw, &remove_list_head, &recp_list[lkup]);
379471d10453SEric Joyner 		break;
379571d10453SEric Joyner 	case ICE_SW_LKUP_PROMISC:
379671d10453SEric Joyner 	case ICE_SW_LKUP_PROMISC_VLAN:
37978923de59SPiotr Kubaj 		ice_remove_promisc(hw, (u8)lkup, &remove_list_head);
379871d10453SEric Joyner 		break;
379971d10453SEric Joyner 	case ICE_SW_LKUP_MAC_VLAN:
380071d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SW, "MAC VLAN look up is not supported yet\n");
380171d10453SEric Joyner 		break;
380271d10453SEric Joyner 	case ICE_SW_LKUP_ETHERTYPE:
380371d10453SEric Joyner 	case ICE_SW_LKUP_ETHERTYPE_MAC:
380471d10453SEric Joyner 		ice_remove_eth_mac(hw, &remove_list_head);
380571d10453SEric Joyner 		break;
380671d10453SEric Joyner 	case ICE_SW_LKUP_DFLT:
38077d7af7f8SEric Joyner 		ice_debug(hw, ICE_DBG_SW, "Remove filters for this lookup type hasn't been implemented yet\n");
380871d10453SEric Joyner 		break;
380971d10453SEric Joyner 	case ICE_SW_LKUP_LAST:
381071d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type\n");
381171d10453SEric Joyner 		break;
381271d10453SEric Joyner 	}
381371d10453SEric Joyner 
38149cf1841cSEric Joyner free_fltr_list:
381571d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(fm_entry, tmp, &remove_list_head,
381671d10453SEric Joyner 				 ice_fltr_list_entry, list_entry) {
381771d10453SEric Joyner 		LIST_DEL(&fm_entry->list_entry);
381871d10453SEric Joyner 		ice_free(hw, fm_entry);
381971d10453SEric Joyner 	}
382071d10453SEric Joyner }
382171d10453SEric Joyner 
382271d10453SEric Joyner /**
382371d10453SEric Joyner  * ice_remove_vsi_fltr_rule - Remove all filters for a VSI
382471d10453SEric Joyner  * @hw: pointer to the hardware structure
382571d10453SEric Joyner  * @vsi_handle: VSI handle to remove filters from
382671d10453SEric Joyner  * @sw: pointer to switch info struct
382771d10453SEric Joyner  */
382871d10453SEric Joyner static void
382971d10453SEric Joyner ice_remove_vsi_fltr_rule(struct ice_hw *hw, u16 vsi_handle,
383071d10453SEric Joyner 			 struct ice_switch_info *sw)
383171d10453SEric Joyner {
383271d10453SEric Joyner 	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
383371d10453SEric Joyner 
383471d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
383571d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_MAC);
383671d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
383771d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_MAC_VLAN);
383871d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
383971d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_PROMISC);
384071d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
384171d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_VLAN);
384271d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
384371d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_DFLT);
384471d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
384571d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_ETHERTYPE);
384671d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
384771d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_ETHERTYPE_MAC);
384871d10453SEric Joyner 	ice_remove_vsi_lkup_fltr(hw, vsi_handle,
384971d10453SEric Joyner 				 sw->recp_list, ICE_SW_LKUP_PROMISC_VLAN);
385071d10453SEric Joyner }
385171d10453SEric Joyner 
385271d10453SEric Joyner /**
385371d10453SEric Joyner  * ice_remove_vsi_fltr - Remove all filters for a VSI
385471d10453SEric Joyner  * @hw: pointer to the hardware structure
385571d10453SEric Joyner  * @vsi_handle: VSI handle to remove filters from
385671d10453SEric Joyner  */
385771d10453SEric Joyner void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)
385871d10453SEric Joyner {
385971d10453SEric Joyner 	ice_remove_vsi_fltr_rule(hw, vsi_handle, hw->switch_info);
386071d10453SEric Joyner }
386171d10453SEric Joyner 
386271d10453SEric Joyner /**
386371d10453SEric Joyner  * ice_alloc_res_cntr - allocating resource counter
386471d10453SEric Joyner  * @hw: pointer to the hardware structure
386571d10453SEric Joyner  * @type: type of resource
386671d10453SEric Joyner  * @alloc_shared: if set it is shared else dedicated
386771d10453SEric Joyner  * @num_items: number of entries requested for FD resource type
386871d10453SEric Joyner  * @counter_id: counter index returned by AQ call
386971d10453SEric Joyner  */
3870*f2635e84SEric Joyner static int
387171d10453SEric Joyner ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
387271d10453SEric Joyner 		   u16 *counter_id)
387371d10453SEric Joyner {
387471d10453SEric Joyner 	struct ice_aqc_alloc_free_res_elem *buf;
387571d10453SEric Joyner 	u16 buf_len;
3876*f2635e84SEric Joyner 	int status;
387771d10453SEric Joyner 
387871d10453SEric Joyner 	/* Allocate resource */
38797d7af7f8SEric Joyner 	buf_len = ice_struct_size(buf, elem, 1);
38807d7af7f8SEric Joyner 	buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
388171d10453SEric Joyner 	if (!buf)
388271d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
388371d10453SEric Joyner 
388471d10453SEric Joyner 	buf->num_elems = CPU_TO_LE16(num_items);
388571d10453SEric Joyner 	buf->res_type = CPU_TO_LE16(((type << ICE_AQC_RES_TYPE_S) &
388671d10453SEric Joyner 				      ICE_AQC_RES_TYPE_M) | alloc_shared);
388771d10453SEric Joyner 
388871d10453SEric Joyner 	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
388971d10453SEric Joyner 				       ice_aqc_opc_alloc_res, NULL);
389071d10453SEric Joyner 	if (status)
389171d10453SEric Joyner 		goto exit;
389271d10453SEric Joyner 
389371d10453SEric Joyner 	*counter_id = LE16_TO_CPU(buf->elem[0].e.sw_resp);
389471d10453SEric Joyner 
389571d10453SEric Joyner exit:
389671d10453SEric Joyner 	ice_free(hw, buf);
389771d10453SEric Joyner 	return status;
389871d10453SEric Joyner }
389971d10453SEric Joyner 
390071d10453SEric Joyner /**
390171d10453SEric Joyner  * ice_free_res_cntr - free resource counter
390271d10453SEric Joyner  * @hw: pointer to the hardware structure
390371d10453SEric Joyner  * @type: type of resource
390471d10453SEric Joyner  * @alloc_shared: if set it is shared else dedicated
390571d10453SEric Joyner  * @num_items: number of entries to be freed for FD resource type
390671d10453SEric Joyner  * @counter_id: counter ID resource which needs to be freed
390771d10453SEric Joyner  */
3908*f2635e84SEric Joyner static int
390971d10453SEric Joyner ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
391071d10453SEric Joyner 		  u16 counter_id)
391171d10453SEric Joyner {
391271d10453SEric Joyner 	struct ice_aqc_alloc_free_res_elem *buf;
391371d10453SEric Joyner 	u16 buf_len;
3914*f2635e84SEric Joyner 	int status;
391571d10453SEric Joyner 
391671d10453SEric Joyner 	/* Free resource */
39177d7af7f8SEric Joyner 	buf_len = ice_struct_size(buf, elem, 1);
39187d7af7f8SEric Joyner 	buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len);
391971d10453SEric Joyner 	if (!buf)
392071d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
392171d10453SEric Joyner 
392271d10453SEric Joyner 	buf->num_elems = CPU_TO_LE16(num_items);
392371d10453SEric Joyner 	buf->res_type = CPU_TO_LE16(((type << ICE_AQC_RES_TYPE_S) &
392471d10453SEric Joyner 				      ICE_AQC_RES_TYPE_M) | alloc_shared);
392571d10453SEric Joyner 	buf->elem[0].e.sw_resp = CPU_TO_LE16(counter_id);
392671d10453SEric Joyner 
392771d10453SEric Joyner 	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
392871d10453SEric Joyner 				       ice_aqc_opc_free_res, NULL);
392971d10453SEric Joyner 	if (status)
39307d7af7f8SEric Joyner 		ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n");
393171d10453SEric Joyner 
393271d10453SEric Joyner 	ice_free(hw, buf);
393371d10453SEric Joyner 	return status;
393471d10453SEric Joyner }
393571d10453SEric Joyner 
393671d10453SEric Joyner /**
393771d10453SEric Joyner  * ice_alloc_vlan_res_counter - obtain counter resource for VLAN type
393871d10453SEric Joyner  * @hw: pointer to the hardware structure
393971d10453SEric Joyner  * @counter_id: returns counter index
394071d10453SEric Joyner  */
3941*f2635e84SEric Joyner int ice_alloc_vlan_res_counter(struct ice_hw *hw, u16 *counter_id)
394271d10453SEric Joyner {
394371d10453SEric Joyner 	return ice_alloc_res_cntr(hw, ICE_AQC_RES_TYPE_VLAN_COUNTER,
394471d10453SEric Joyner 				  ICE_AQC_RES_TYPE_FLAG_DEDICATED, 1,
394571d10453SEric Joyner 				  counter_id);
394671d10453SEric Joyner }
394771d10453SEric Joyner 
394871d10453SEric Joyner /**
394971d10453SEric Joyner  * ice_free_vlan_res_counter - Free counter resource for VLAN type
395071d10453SEric Joyner  * @hw: pointer to the hardware structure
395171d10453SEric Joyner  * @counter_id: counter index to be freed
395271d10453SEric Joyner  */
3953*f2635e84SEric Joyner int ice_free_vlan_res_counter(struct ice_hw *hw, u16 counter_id)
395471d10453SEric Joyner {
395571d10453SEric Joyner 	return ice_free_res_cntr(hw, ICE_AQC_RES_TYPE_VLAN_COUNTER,
395671d10453SEric Joyner 				 ICE_AQC_RES_TYPE_FLAG_DEDICATED, 1,
395771d10453SEric Joyner 				 counter_id);
395871d10453SEric Joyner }
395971d10453SEric Joyner 
396071d10453SEric Joyner /**
396171d10453SEric Joyner  * ice_add_mac_with_sw_marker - add filter with sw marker
396271d10453SEric Joyner  * @hw: pointer to the hardware structure
396371d10453SEric Joyner  * @f_info: filter info structure containing the MAC filter information
396471d10453SEric Joyner  * @sw_marker: sw marker to tag the Rx descriptor with
396571d10453SEric Joyner  */
3966*f2635e84SEric Joyner int
396771d10453SEric Joyner ice_add_mac_with_sw_marker(struct ice_hw *hw, struct ice_fltr_info *f_info,
396871d10453SEric Joyner 			   u16 sw_marker)
396971d10453SEric Joyner {
397071d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *m_entry;
397171d10453SEric Joyner 	struct ice_fltr_list_entry fl_info;
397271d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
397371d10453SEric Joyner 	struct LIST_HEAD_TYPE l_head;
397471d10453SEric Joyner 	struct ice_lock *rule_lock;	/* Lock to protect filter rule list */
397571d10453SEric Joyner 	bool entry_exists;
397671d10453SEric Joyner 	u16 lg_act_id;
3977*f2635e84SEric Joyner 	int ret;
397871d10453SEric Joyner 
397971d10453SEric Joyner 	if (f_info->fltr_act != ICE_FWD_TO_VSI)
398071d10453SEric Joyner 		return ICE_ERR_PARAM;
398171d10453SEric Joyner 
398271d10453SEric Joyner 	if (f_info->lkup_type != ICE_SW_LKUP_MAC)
398371d10453SEric Joyner 		return ICE_ERR_PARAM;
398471d10453SEric Joyner 
398571d10453SEric Joyner 	if (sw_marker == ICE_INVAL_SW_MARKER_ID)
398671d10453SEric Joyner 		return ICE_ERR_PARAM;
398771d10453SEric Joyner 
398871d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, f_info->vsi_handle))
398971d10453SEric Joyner 		return ICE_ERR_PARAM;
399071d10453SEric Joyner 	f_info->fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, f_info->vsi_handle);
399171d10453SEric Joyner 
399271d10453SEric Joyner 	/* Add filter if it doesn't exist so then the adding of large
399371d10453SEric Joyner 	 * action always results in update
399471d10453SEric Joyner 	 */
399571d10453SEric Joyner 
399671d10453SEric Joyner 	INIT_LIST_HEAD(&l_head);
399771d10453SEric Joyner 	fl_info.fltr_info = *f_info;
399871d10453SEric Joyner 	LIST_ADD(&fl_info.list_entry, &l_head);
399971d10453SEric Joyner 
400071d10453SEric Joyner 	entry_exists = false;
400171d10453SEric Joyner 	ret = ice_add_mac_rule(hw, &l_head, hw->switch_info,
400271d10453SEric Joyner 			       hw->port_info->lport);
400371d10453SEric Joyner 	if (ret == ICE_ERR_ALREADY_EXISTS)
400471d10453SEric Joyner 		entry_exists = true;
400571d10453SEric Joyner 	else if (ret)
400671d10453SEric Joyner 		return ret;
400771d10453SEric Joyner 
400871d10453SEric Joyner 	recp_list = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC];
400971d10453SEric Joyner 	rule_lock = &recp_list->filt_rule_lock;
401071d10453SEric Joyner 	ice_acquire_lock(rule_lock);
401171d10453SEric Joyner 	/* Get the book keeping entry for the filter */
401271d10453SEric Joyner 	m_entry = ice_find_rule_entry(&recp_list->filt_rules, f_info);
401371d10453SEric Joyner 	if (!m_entry)
401471d10453SEric Joyner 		goto exit_error;
401571d10453SEric Joyner 
401671d10453SEric Joyner 	/* If counter action was enabled for this rule then don't enable
401771d10453SEric Joyner 	 * sw marker large action
401871d10453SEric Joyner 	 */
401971d10453SEric Joyner 	if (m_entry->counter_index != ICE_INVAL_COUNTER_ID) {
402071d10453SEric Joyner 		ret = ICE_ERR_PARAM;
402171d10453SEric Joyner 		goto exit_error;
402271d10453SEric Joyner 	}
402371d10453SEric Joyner 
402471d10453SEric Joyner 	/* if same marker was added before */
402571d10453SEric Joyner 	if (m_entry->sw_marker_id == sw_marker) {
402671d10453SEric Joyner 		ret = ICE_ERR_ALREADY_EXISTS;
402771d10453SEric Joyner 		goto exit_error;
402871d10453SEric Joyner 	}
402971d10453SEric Joyner 
403071d10453SEric Joyner 	/* Allocate a hardware table entry to hold large act. Three actions
403171d10453SEric Joyner 	 * for marker based large action
403271d10453SEric Joyner 	 */
403371d10453SEric Joyner 	ret = ice_alloc_res_lg_act(hw, &lg_act_id, 3);
403471d10453SEric Joyner 	if (ret)
403571d10453SEric Joyner 		goto exit_error;
403671d10453SEric Joyner 
403771d10453SEric Joyner 	if (lg_act_id == ICE_INVAL_LG_ACT_INDEX)
403871d10453SEric Joyner 		goto exit_error;
403971d10453SEric Joyner 
404071d10453SEric Joyner 	/* Update the switch rule to add the marker action */
404171d10453SEric Joyner 	ret = ice_add_marker_act(hw, m_entry, sw_marker, lg_act_id);
404271d10453SEric Joyner 	if (!ret) {
404371d10453SEric Joyner 		ice_release_lock(rule_lock);
404471d10453SEric Joyner 		return ret;
404571d10453SEric Joyner 	}
404671d10453SEric Joyner 
404771d10453SEric Joyner exit_error:
404871d10453SEric Joyner 	ice_release_lock(rule_lock);
404971d10453SEric Joyner 	/* only remove entry if it did not exist previously */
405071d10453SEric Joyner 	if (!entry_exists)
405171d10453SEric Joyner 		ret = ice_remove_mac(hw, &l_head);
405271d10453SEric Joyner 
405371d10453SEric Joyner 	return ret;
405471d10453SEric Joyner }
405571d10453SEric Joyner 
405671d10453SEric Joyner /**
405771d10453SEric Joyner  * ice_add_mac_with_counter - add filter with counter enabled
405871d10453SEric Joyner  * @hw: pointer to the hardware structure
405971d10453SEric Joyner  * @f_info: pointer to filter info structure containing the MAC filter
406071d10453SEric Joyner  *          information
406171d10453SEric Joyner  */
4062*f2635e84SEric Joyner int
406371d10453SEric Joyner ice_add_mac_with_counter(struct ice_hw *hw, struct ice_fltr_info *f_info)
406471d10453SEric Joyner {
406571d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *m_entry;
406671d10453SEric Joyner 	struct ice_fltr_list_entry fl_info;
406771d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
406871d10453SEric Joyner 	struct LIST_HEAD_TYPE l_head;
406971d10453SEric Joyner 	struct ice_lock *rule_lock;	/* Lock to protect filter rule list */
407071d10453SEric Joyner 	bool entry_exist;
407171d10453SEric Joyner 	u16 counter_id;
407271d10453SEric Joyner 	u16 lg_act_id;
4073*f2635e84SEric Joyner 	int ret;
407471d10453SEric Joyner 
407571d10453SEric Joyner 	if (f_info->fltr_act != ICE_FWD_TO_VSI)
407671d10453SEric Joyner 		return ICE_ERR_PARAM;
407771d10453SEric Joyner 
407871d10453SEric Joyner 	if (f_info->lkup_type != ICE_SW_LKUP_MAC)
407971d10453SEric Joyner 		return ICE_ERR_PARAM;
408071d10453SEric Joyner 
408171d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, f_info->vsi_handle))
408271d10453SEric Joyner 		return ICE_ERR_PARAM;
408371d10453SEric Joyner 	f_info->fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, f_info->vsi_handle);
408471d10453SEric Joyner 	recp_list = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC];
408571d10453SEric Joyner 
408671d10453SEric Joyner 	entry_exist = false;
408771d10453SEric Joyner 
408871d10453SEric Joyner 	rule_lock = &recp_list->filt_rule_lock;
408971d10453SEric Joyner 
409071d10453SEric Joyner 	/* Add filter if it doesn't exist so then the adding of large
409171d10453SEric Joyner 	 * action always results in update
409271d10453SEric Joyner 	 */
409371d10453SEric Joyner 	INIT_LIST_HEAD(&l_head);
409471d10453SEric Joyner 
409571d10453SEric Joyner 	fl_info.fltr_info = *f_info;
409671d10453SEric Joyner 	LIST_ADD(&fl_info.list_entry, &l_head);
409771d10453SEric Joyner 
409871d10453SEric Joyner 	ret = ice_add_mac_rule(hw, &l_head, hw->switch_info,
409971d10453SEric Joyner 			       hw->port_info->lport);
410071d10453SEric Joyner 	if (ret == ICE_ERR_ALREADY_EXISTS)
410171d10453SEric Joyner 		entry_exist = true;
410271d10453SEric Joyner 	else if (ret)
410371d10453SEric Joyner 		return ret;
410471d10453SEric Joyner 
410571d10453SEric Joyner 	ice_acquire_lock(rule_lock);
410671d10453SEric Joyner 	m_entry = ice_find_rule_entry(&recp_list->filt_rules, f_info);
410771d10453SEric Joyner 	if (!m_entry) {
410871d10453SEric Joyner 		ret = ICE_ERR_BAD_PTR;
410971d10453SEric Joyner 		goto exit_error;
411071d10453SEric Joyner 	}
411171d10453SEric Joyner 
411271d10453SEric Joyner 	/* Don't enable counter for a filter for which sw marker was enabled */
411371d10453SEric Joyner 	if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID) {
411471d10453SEric Joyner 		ret = ICE_ERR_PARAM;
411571d10453SEric Joyner 		goto exit_error;
411671d10453SEric Joyner 	}
411771d10453SEric Joyner 
411871d10453SEric Joyner 	/* If a counter was already enabled then don't need to add again */
411971d10453SEric Joyner 	if (m_entry->counter_index != ICE_INVAL_COUNTER_ID) {
412071d10453SEric Joyner 		ret = ICE_ERR_ALREADY_EXISTS;
412171d10453SEric Joyner 		goto exit_error;
412271d10453SEric Joyner 	}
412371d10453SEric Joyner 
412471d10453SEric Joyner 	/* Allocate a hardware table entry to VLAN counter */
412571d10453SEric Joyner 	ret = ice_alloc_vlan_res_counter(hw, &counter_id);
412671d10453SEric Joyner 	if (ret)
412771d10453SEric Joyner 		goto exit_error;
412871d10453SEric Joyner 
412971d10453SEric Joyner 	/* Allocate a hardware table entry to hold large act. Two actions for
413071d10453SEric Joyner 	 * counter based large action
413171d10453SEric Joyner 	 */
413271d10453SEric Joyner 	ret = ice_alloc_res_lg_act(hw, &lg_act_id, 2);
413371d10453SEric Joyner 	if (ret)
413471d10453SEric Joyner 		goto exit_error;
413571d10453SEric Joyner 
413671d10453SEric Joyner 	if (lg_act_id == ICE_INVAL_LG_ACT_INDEX)
413771d10453SEric Joyner 		goto exit_error;
413871d10453SEric Joyner 
413971d10453SEric Joyner 	/* Update the switch rule to add the counter action */
414071d10453SEric Joyner 	ret = ice_add_counter_act(hw, m_entry, counter_id, lg_act_id);
414171d10453SEric Joyner 	if (!ret) {
414271d10453SEric Joyner 		ice_release_lock(rule_lock);
414371d10453SEric Joyner 		return ret;
414471d10453SEric Joyner 	}
414571d10453SEric Joyner 
414671d10453SEric Joyner exit_error:
414771d10453SEric Joyner 	ice_release_lock(rule_lock);
414871d10453SEric Joyner 	/* only remove entry if it did not exist previously */
414971d10453SEric Joyner 	if (!entry_exist)
415071d10453SEric Joyner 		ret = ice_remove_mac(hw, &l_head);
415171d10453SEric Joyner 
415271d10453SEric Joyner 	return ret;
415371d10453SEric Joyner }
415471d10453SEric Joyner 
415571d10453SEric Joyner /**
415671d10453SEric Joyner  * ice_replay_fltr - Replay all the filters stored by a specific list head
415771d10453SEric Joyner  * @hw: pointer to the hardware structure
415871d10453SEric Joyner  * @list_head: list for which filters needs to be replayed
415971d10453SEric Joyner  * @recp_id: Recipe ID for which rules need to be replayed
416071d10453SEric Joyner  */
4161*f2635e84SEric Joyner static int
416271d10453SEric Joyner ice_replay_fltr(struct ice_hw *hw, u8 recp_id, struct LIST_HEAD_TYPE *list_head)
416371d10453SEric Joyner {
416471d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *itr;
416571d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
416671d10453SEric Joyner 	u8 lport = hw->port_info->lport;
416771d10453SEric Joyner 	struct LIST_HEAD_TYPE l_head;
4168*f2635e84SEric Joyner 	int status = 0;
416971d10453SEric Joyner 
417071d10453SEric Joyner 	if (LIST_EMPTY(list_head))
417171d10453SEric Joyner 		return status;
417271d10453SEric Joyner 
417371d10453SEric Joyner 	recp_list = &hw->switch_info->recp_list[recp_id];
417471d10453SEric Joyner 	/* Move entries from the given list_head to a temporary l_head so that
417571d10453SEric Joyner 	 * they can be replayed. Otherwise when trying to re-add the same
417671d10453SEric Joyner 	 * filter, the function will return already exists
417771d10453SEric Joyner 	 */
417871d10453SEric Joyner 	LIST_REPLACE_INIT(list_head, &l_head);
417971d10453SEric Joyner 
418071d10453SEric Joyner 	/* Mark the given list_head empty by reinitializing it so filters
418171d10453SEric Joyner 	 * could be added again by *handler
418271d10453SEric Joyner 	 */
418371d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(itr, &l_head, ice_fltr_mgmt_list_entry,
418471d10453SEric Joyner 			    list_entry) {
418571d10453SEric Joyner 		struct ice_fltr_list_entry f_entry;
41867d7af7f8SEric Joyner 		u16 vsi_handle;
418771d10453SEric Joyner 
418871d10453SEric Joyner 		f_entry.fltr_info = itr->fltr_info;
418971d10453SEric Joyner 		if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN) {
419071d10453SEric Joyner 			status = ice_add_rule_internal(hw, recp_list, lport,
419171d10453SEric Joyner 						       &f_entry);
4192*f2635e84SEric Joyner 			if (status)
419371d10453SEric Joyner 				goto end;
419471d10453SEric Joyner 			continue;
419571d10453SEric Joyner 		}
419671d10453SEric Joyner 
419771d10453SEric Joyner 		/* Add a filter per VSI separately */
41987d7af7f8SEric Joyner 		ice_for_each_set_bit(vsi_handle, itr->vsi_list_info->vsi_map,
41997d7af7f8SEric Joyner 				     ICE_MAX_VSI) {
420071d10453SEric Joyner 			if (!ice_is_vsi_valid(hw, vsi_handle))
420171d10453SEric Joyner 				break;
420271d10453SEric Joyner 
420371d10453SEric Joyner 			ice_clear_bit(vsi_handle, itr->vsi_list_info->vsi_map);
420471d10453SEric Joyner 			f_entry.fltr_info.vsi_handle = vsi_handle;
420571d10453SEric Joyner 			f_entry.fltr_info.fwd_id.hw_vsi_id =
420671d10453SEric Joyner 				ice_get_hw_vsi_num(hw, vsi_handle);
420771d10453SEric Joyner 			f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;
420871d10453SEric Joyner 			if (recp_id == ICE_SW_LKUP_VLAN)
420971d10453SEric Joyner 				status = ice_add_vlan_internal(hw, recp_list,
421071d10453SEric Joyner 							       &f_entry);
421171d10453SEric Joyner 			else
421271d10453SEric Joyner 				status = ice_add_rule_internal(hw, recp_list,
421371d10453SEric Joyner 							       lport,
421471d10453SEric Joyner 							       &f_entry);
4215*f2635e84SEric Joyner 			if (status)
421671d10453SEric Joyner 				goto end;
421771d10453SEric Joyner 		}
421871d10453SEric Joyner 	}
421971d10453SEric Joyner end:
422071d10453SEric Joyner 	/* Clear the filter management list */
422171d10453SEric Joyner 	ice_rem_sw_rule_info(hw, &l_head);
422271d10453SEric Joyner 	return status;
422371d10453SEric Joyner }
422471d10453SEric Joyner 
422571d10453SEric Joyner /**
422671d10453SEric Joyner  * ice_replay_all_fltr - replay all filters stored in bookkeeping lists
422771d10453SEric Joyner  * @hw: pointer to the hardware structure
422871d10453SEric Joyner  *
422971d10453SEric Joyner  * NOTE: This function does not clean up partially added filters on error.
423071d10453SEric Joyner  * It is up to caller of the function to issue a reset or fail early.
423171d10453SEric Joyner  */
4232*f2635e84SEric Joyner int ice_replay_all_fltr(struct ice_hw *hw)
423371d10453SEric Joyner {
423471d10453SEric Joyner 	struct ice_switch_info *sw = hw->switch_info;
4235*f2635e84SEric Joyner 	int status = ICE_SUCCESS;
423671d10453SEric Joyner 	u8 i;
423771d10453SEric Joyner 
423871d10453SEric Joyner 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
423971d10453SEric Joyner 		struct LIST_HEAD_TYPE *head = &sw->recp_list[i].filt_rules;
424071d10453SEric Joyner 
424171d10453SEric Joyner 		status = ice_replay_fltr(hw, i, head);
424271d10453SEric Joyner 		if (status != ICE_SUCCESS)
424371d10453SEric Joyner 			return status;
424471d10453SEric Joyner 	}
424571d10453SEric Joyner 	return status;
424671d10453SEric Joyner }
424771d10453SEric Joyner 
424871d10453SEric Joyner /**
424971d10453SEric Joyner  * ice_replay_vsi_fltr - Replay filters for requested VSI
425071d10453SEric Joyner  * @hw: pointer to the hardware structure
42517d7af7f8SEric Joyner  * @pi: pointer to port information structure
42527d7af7f8SEric Joyner  * @sw: pointer to switch info struct for which function replays filters
425371d10453SEric Joyner  * @vsi_handle: driver VSI handle
425471d10453SEric Joyner  * @recp_id: Recipe ID for which rules need to be replayed
425571d10453SEric Joyner  * @list_head: list for which filters need to be replayed
425671d10453SEric Joyner  *
425771d10453SEric Joyner  * Replays the filter of recipe recp_id for a VSI represented via vsi_handle.
425871d10453SEric Joyner  * It is required to pass valid VSI handle.
425971d10453SEric Joyner  */
4260*f2635e84SEric Joyner static int
42617d7af7f8SEric Joyner ice_replay_vsi_fltr(struct ice_hw *hw, struct ice_port_info *pi,
42627d7af7f8SEric Joyner 		    struct ice_switch_info *sw, u16 vsi_handle, u8 recp_id,
426371d10453SEric Joyner 		    struct LIST_HEAD_TYPE *list_head)
426471d10453SEric Joyner {
426571d10453SEric Joyner 	struct ice_fltr_mgmt_list_entry *itr;
426671d10453SEric Joyner 	struct ice_sw_recipe *recp_list;
4267*f2635e84SEric Joyner 	int status = 0;
426871d10453SEric Joyner 	u16 hw_vsi_id;
426971d10453SEric Joyner 
427071d10453SEric Joyner 	if (LIST_EMPTY(list_head))
427171d10453SEric Joyner 		return status;
42727d7af7f8SEric Joyner 	recp_list = &sw->recp_list[recp_id];
427371d10453SEric Joyner 	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
427471d10453SEric Joyner 
427571d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(itr, list_head, ice_fltr_mgmt_list_entry,
427671d10453SEric Joyner 			    list_entry) {
427771d10453SEric Joyner 		struct ice_fltr_list_entry f_entry;
427871d10453SEric Joyner 
427971d10453SEric Joyner 		f_entry.fltr_info = itr->fltr_info;
428071d10453SEric Joyner 		if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN &&
428171d10453SEric Joyner 		    itr->fltr_info.vsi_handle == vsi_handle) {
428271d10453SEric Joyner 			/* update the src in case it is VSI num */
428371d10453SEric Joyner 			if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
428471d10453SEric Joyner 				f_entry.fltr_info.src = hw_vsi_id;
428571d10453SEric Joyner 			status = ice_add_rule_internal(hw, recp_list,
42867d7af7f8SEric Joyner 						       pi->lport,
428771d10453SEric Joyner 						       &f_entry);
4288*f2635e84SEric Joyner 			if (status)
428971d10453SEric Joyner 				goto end;
429071d10453SEric Joyner 			continue;
429171d10453SEric Joyner 		}
429271d10453SEric Joyner 		if (!itr->vsi_list_info ||
429371d10453SEric Joyner 		    !ice_is_bit_set(itr->vsi_list_info->vsi_map, vsi_handle))
429471d10453SEric Joyner 			continue;
429571d10453SEric Joyner 		f_entry.fltr_info.vsi_handle = vsi_handle;
429671d10453SEric Joyner 		f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;
429771d10453SEric Joyner 		/* update the src in case it is VSI num */
429871d10453SEric Joyner 		if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
429971d10453SEric Joyner 			f_entry.fltr_info.src = hw_vsi_id;
430071d10453SEric Joyner 		if (recp_id == ICE_SW_LKUP_VLAN)
430171d10453SEric Joyner 			status = ice_add_vlan_internal(hw, recp_list, &f_entry);
430271d10453SEric Joyner 		else
430371d10453SEric Joyner 			status = ice_add_rule_internal(hw, recp_list,
43047d7af7f8SEric Joyner 						       pi->lport,
430571d10453SEric Joyner 						       &f_entry);
4306*f2635e84SEric Joyner 		if (status)
430771d10453SEric Joyner 			goto end;
430871d10453SEric Joyner 	}
430971d10453SEric Joyner end:
431071d10453SEric Joyner 	return status;
431171d10453SEric Joyner }
431271d10453SEric Joyner 
431371d10453SEric Joyner /**
431471d10453SEric Joyner  * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists
431571d10453SEric Joyner  * @hw: pointer to the hardware structure
43167d7af7f8SEric Joyner  * @pi: pointer to port information structure
431771d10453SEric Joyner  * @vsi_handle: driver VSI handle
431871d10453SEric Joyner  *
431971d10453SEric Joyner  * Replays filters for requested VSI via vsi_handle.
432071d10453SEric Joyner  */
4321*f2635e84SEric Joyner int
43227d7af7f8SEric Joyner ice_replay_vsi_all_fltr(struct ice_hw *hw, struct ice_port_info *pi,
43237d7af7f8SEric Joyner 			u16 vsi_handle)
432471d10453SEric Joyner {
43259c30461dSEric Joyner 	struct ice_switch_info *sw = NULL;
4326*f2635e84SEric Joyner 	int status = 0;
432771d10453SEric Joyner 	u8 i;
432871d10453SEric Joyner 
43298923de59SPiotr Kubaj 	sw = hw->switch_info;
43308923de59SPiotr Kubaj 
433171d10453SEric Joyner 	/* Update the recipes that were created */
433271d10453SEric Joyner 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
433371d10453SEric Joyner 		struct LIST_HEAD_TYPE *head;
433471d10453SEric Joyner 
433571d10453SEric Joyner 		head = &sw->recp_list[i].filt_replay_rules;
433671d10453SEric Joyner 		if (!sw->recp_list[i].adv_rule)
43377d7af7f8SEric Joyner 			status = ice_replay_vsi_fltr(hw, pi, sw, vsi_handle, i,
43387d7af7f8SEric Joyner 						     head);
4339*f2635e84SEric Joyner 		if (status)
434071d10453SEric Joyner 			return status;
434171d10453SEric Joyner 	}
434271d10453SEric Joyner 
4343*f2635e84SEric Joyner 	return 0;
434471d10453SEric Joyner }
434571d10453SEric Joyner 
434671d10453SEric Joyner /**
434756429daeSEric Joyner  * ice_rm_sw_replay_rule_info - helper function to delete filter replay rules
434871d10453SEric Joyner  * @hw: pointer to the HW struct
43497d7af7f8SEric Joyner  * @sw: pointer to switch info struct for which function removes filters
435071d10453SEric Joyner  *
43517d7af7f8SEric Joyner  * Deletes the filter replay rules for given switch
435271d10453SEric Joyner  */
43537d7af7f8SEric Joyner void ice_rm_sw_replay_rule_info(struct ice_hw *hw, struct ice_switch_info *sw)
435471d10453SEric Joyner {
435571d10453SEric Joyner 	u8 i;
435671d10453SEric Joyner 
435771d10453SEric Joyner 	if (!sw)
435871d10453SEric Joyner 		return;
435971d10453SEric Joyner 
436071d10453SEric Joyner 	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
436171d10453SEric Joyner 		if (!LIST_EMPTY(&sw->recp_list[i].filt_replay_rules)) {
436271d10453SEric Joyner 			struct LIST_HEAD_TYPE *l_head;
436371d10453SEric Joyner 
436471d10453SEric Joyner 			l_head = &sw->recp_list[i].filt_replay_rules;
436571d10453SEric Joyner 			if (!sw->recp_list[i].adv_rule)
436671d10453SEric Joyner 				ice_rem_sw_rule_info(hw, l_head);
436771d10453SEric Joyner 		}
436871d10453SEric Joyner 	}
436971d10453SEric Joyner }
43707d7af7f8SEric Joyner 
43717d7af7f8SEric Joyner /**
43727d7af7f8SEric Joyner  * ice_rm_all_sw_replay_rule_info - deletes filter replay rules
43737d7af7f8SEric Joyner  * @hw: pointer to the HW struct
43747d7af7f8SEric Joyner  *
43757d7af7f8SEric Joyner  * Deletes the filter replay rules.
43767d7af7f8SEric Joyner  */
43777d7af7f8SEric Joyner void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw)
43787d7af7f8SEric Joyner {
43797d7af7f8SEric Joyner 	ice_rm_sw_replay_rule_info(hw, hw->switch_info);
43807d7af7f8SEric Joyner }
43817d7af7f8SEric Joyner 
4382