18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "ice_switch.h"
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#define ICE_ETH_DA_OFFSET		0
78c2ecf20Sopenharmony_ci#define ICE_ETH_ETHTYPE_OFFSET		12
88c2ecf20Sopenharmony_ci#define ICE_ETH_VLAN_TCI_OFFSET		14
98c2ecf20Sopenharmony_ci#define ICE_MAX_VLAN_ID			0xFFF
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/* Dummy ethernet header needed in the ice_aqc_sw_rules_elem
128c2ecf20Sopenharmony_ci * struct to configure any switch filter rules.
138c2ecf20Sopenharmony_ci * {DA (6 bytes), SA(6 bytes),
148c2ecf20Sopenharmony_ci * Ether type (2 bytes for header without VLAN tag) OR
158c2ecf20Sopenharmony_ci * VLAN tag (4 bytes for header with VLAN tag) }
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * Word on Hardcoded values
188c2ecf20Sopenharmony_ci * byte 0 = 0x2: to identify it as locally administered DA MAC
198c2ecf20Sopenharmony_ci * byte 6 = 0x2: to identify it as locally administered SA MAC
208c2ecf20Sopenharmony_ci * byte 12 = 0x81 & byte 13 = 0x00:
218c2ecf20Sopenharmony_ci *	In case of VLAN filter first two bytes defines ether type (0x8100)
228c2ecf20Sopenharmony_ci *	and remaining two bytes are placeholder for programming a given VLAN ID
238c2ecf20Sopenharmony_ci *	In case of Ether type filter it is treated as header without VLAN tag
248c2ecf20Sopenharmony_ci *	and byte 12 and 13 is used to program a given Ether type instead
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci#define DUMMY_ETH_HDR_LEN		16
278c2ecf20Sopenharmony_cistatic const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
288c2ecf20Sopenharmony_ci							0x2, 0, 0, 0, 0, 0,
298c2ecf20Sopenharmony_ci							0x81, 0, 0, 0};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE \
328c2ecf20Sopenharmony_ci	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr) + \
338c2ecf20Sopenharmony_ci	 (DUMMY_ETH_HDR_LEN * \
348c2ecf20Sopenharmony_ci	  sizeof(((struct ice_sw_rule_lkup_rx_tx *)0)->hdr[0])))
358c2ecf20Sopenharmony_ci#define ICE_SW_RULE_RX_TX_NO_HDR_SIZE \
368c2ecf20Sopenharmony_ci	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lkup_tx_rx.hdr))
378c2ecf20Sopenharmony_ci#define ICE_SW_RULE_LG_ACT_SIZE(n) \
388c2ecf20Sopenharmony_ci	(offsetof(struct ice_aqc_sw_rules_elem, pdata.lg_act.act) + \
398c2ecf20Sopenharmony_ci	 ((n) * sizeof(((struct ice_sw_rule_lg_act *)0)->act[0])))
408c2ecf20Sopenharmony_ci#define ICE_SW_RULE_VSI_LIST_SIZE(n) \
418c2ecf20Sopenharmony_ci	(offsetof(struct ice_aqc_sw_rules_elem, pdata.vsi_list.vsi) + \
428c2ecf20Sopenharmony_ci	 ((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi[0])))
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/**
458c2ecf20Sopenharmony_ci * ice_init_def_sw_recp - initialize the recipe book keeping tables
468c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci * Allocate memory for the entire recipe table and initialize the structures/
498c2ecf20Sopenharmony_ci * entries corresponding to basic recipes.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cienum ice_status ice_init_def_sw_recp(struct ice_hw *hw)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	struct ice_sw_recipe *recps;
548c2ecf20Sopenharmony_ci	u8 i;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES,
578c2ecf20Sopenharmony_ci			     sizeof(*recps), GFP_KERNEL);
588c2ecf20Sopenharmony_ci	if (!recps)
598c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
628c2ecf20Sopenharmony_ci		recps[i].root_rid = i;
638c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&recps[i].filt_rules);
648c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&recps[i].filt_replay_rules);
658c2ecf20Sopenharmony_ci		mutex_init(&recps[i].filt_rule_lock);
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	hw->switch_info->recp_list = recps;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	return 0;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci * ice_aq_get_sw_cfg - get switch configuration
758c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
768c2ecf20Sopenharmony_ci * @buf: pointer to the result buffer
778c2ecf20Sopenharmony_ci * @buf_size: length of the buffer available for response
788c2ecf20Sopenharmony_ci * @req_desc: pointer to requested descriptor
798c2ecf20Sopenharmony_ci * @num_elems: pointer to number of elements
808c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * Get switch configuration (0x0200) to be placed in buf.
838c2ecf20Sopenharmony_ci * This admin command returns information such as initial VSI/port number
848c2ecf20Sopenharmony_ci * and switch ID it belongs to.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * NOTE: *req_desc is both an input/output parameter.
878c2ecf20Sopenharmony_ci * The caller of this function first calls this function with *request_desc set
888c2ecf20Sopenharmony_ci * to 0. If the response from f/w has *req_desc set to 0, all the switch
898c2ecf20Sopenharmony_ci * configuration information has been returned; if non-zero (meaning not all
908c2ecf20Sopenharmony_ci * the information was returned), the caller should call this function again
918c2ecf20Sopenharmony_ci * with *req_desc set to the previous value returned by f/w to get the
928c2ecf20Sopenharmony_ci * next block of switch configuration information.
938c2ecf20Sopenharmony_ci *
948c2ecf20Sopenharmony_ci * *num_elems is output only parameter. This reflects the number of elements
958c2ecf20Sopenharmony_ci * in response buffer. The caller of this function to use *num_elems while
968c2ecf20Sopenharmony_ci * parsing the response buffer.
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_cistatic enum ice_status
998c2ecf20Sopenharmony_ciice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf,
1008c2ecf20Sopenharmony_ci		  u16 buf_size, u16 *req_desc, u16 *num_elems,
1018c2ecf20Sopenharmony_ci		  struct ice_sq_cd *cd)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct ice_aqc_get_sw_cfg *cmd;
1048c2ecf20Sopenharmony_ci	struct ice_aq_desc desc;
1058c2ecf20Sopenharmony_ci	enum ice_status status;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg);
1088c2ecf20Sopenharmony_ci	cmd = &desc.params.get_sw_conf;
1098c2ecf20Sopenharmony_ci	cmd->element = cpu_to_le16(*req_desc);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
1128c2ecf20Sopenharmony_ci	if (!status) {
1138c2ecf20Sopenharmony_ci		*req_desc = le16_to_cpu(cmd->element);
1148c2ecf20Sopenharmony_ci		*num_elems = le16_to_cpu(cmd->num_elems);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return status;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/**
1218c2ecf20Sopenharmony_ci * ice_aq_add_vsi
1228c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
1238c2ecf20Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
1248c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci * Add a VSI context to the hardware (0x0210)
1278c2ecf20Sopenharmony_ci */
1288c2ecf20Sopenharmony_cistatic enum ice_status
1298c2ecf20Sopenharmony_ciice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
1308c2ecf20Sopenharmony_ci	       struct ice_sq_cd *cd)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct ice_aqc_add_update_free_vsi_resp *res;
1338c2ecf20Sopenharmony_ci	struct ice_aqc_add_get_update_free_vsi *cmd;
1348c2ecf20Sopenharmony_ci	struct ice_aq_desc desc;
1358c2ecf20Sopenharmony_ci	enum ice_status status;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	cmd = &desc.params.vsi_cmd;
1388c2ecf20Sopenharmony_ci	res = &desc.params.add_update_free_vsi_res;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (!vsi_ctx->alloc_from_pool)
1438c2ecf20Sopenharmony_ci		cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num |
1448c2ecf20Sopenharmony_ci					   ICE_AQ_VSI_IS_VALID);
1458c2ecf20Sopenharmony_ci	cmd->vf_id = vsi_ctx->vf_num;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
1528c2ecf20Sopenharmony_ci				 sizeof(vsi_ctx->info), cd);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (!status) {
1558c2ecf20Sopenharmony_ci		vsi_ctx->vsi_num = le16_to_cpu(res->vsi_num) & ICE_AQ_VSI_NUM_M;
1568c2ecf20Sopenharmony_ci		vsi_ctx->vsis_allocd = le16_to_cpu(res->vsi_used);
1578c2ecf20Sopenharmony_ci		vsi_ctx->vsis_unallocated = le16_to_cpu(res->vsi_free);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return status;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/**
1648c2ecf20Sopenharmony_ci * ice_aq_free_vsi
1658c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
1668c2ecf20Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
1678c2ecf20Sopenharmony_ci * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
1688c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * Free VSI context info from hardware (0x0213)
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_cistatic enum ice_status
1738c2ecf20Sopenharmony_ciice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
1748c2ecf20Sopenharmony_ci		bool keep_vsi_alloc, struct ice_sq_cd *cd)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct ice_aqc_add_update_free_vsi_resp *resp;
1778c2ecf20Sopenharmony_ci	struct ice_aqc_add_get_update_free_vsi *cmd;
1788c2ecf20Sopenharmony_ci	struct ice_aq_desc desc;
1798c2ecf20Sopenharmony_ci	enum ice_status status;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	cmd = &desc.params.vsi_cmd;
1828c2ecf20Sopenharmony_ci	resp = &desc.params.add_update_free_vsi_res;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
1878c2ecf20Sopenharmony_ci	if (keep_vsi_alloc)
1888c2ecf20Sopenharmony_ci		cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
1918c2ecf20Sopenharmony_ci	if (!status) {
1928c2ecf20Sopenharmony_ci		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
1938c2ecf20Sopenharmony_ci		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return status;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/**
2008c2ecf20Sopenharmony_ci * ice_aq_update_vsi
2018c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
2028c2ecf20Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
2038c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
2048c2ecf20Sopenharmony_ci *
2058c2ecf20Sopenharmony_ci * Update VSI context in the hardware (0x0211)
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_cistatic enum ice_status
2088c2ecf20Sopenharmony_ciice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
2098c2ecf20Sopenharmony_ci		  struct ice_sq_cd *cd)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct ice_aqc_add_update_free_vsi_resp *resp;
2128c2ecf20Sopenharmony_ci	struct ice_aqc_add_get_update_free_vsi *cmd;
2138c2ecf20Sopenharmony_ci	struct ice_aq_desc desc;
2148c2ecf20Sopenharmony_ci	enum ice_status status;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	cmd = &desc.params.vsi_cmd;
2178c2ecf20Sopenharmony_ci	resp = &desc.params.add_update_free_vsi_res;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info,
2268c2ecf20Sopenharmony_ci				 sizeof(vsi_ctx->info), cd);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (!status) {
2298c2ecf20Sopenharmony_ci		vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
2308c2ecf20Sopenharmony_ci		vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return status;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/**
2378c2ecf20Sopenharmony_ci * ice_is_vsi_valid - check whether the VSI is valid or not
2388c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
2398c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle
2408c2ecf20Sopenharmony_ci *
2418c2ecf20Sopenharmony_ci * check whether the VSI is valid or not
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_cibool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/**
2498c2ecf20Sopenharmony_ci * ice_get_hw_vsi_num - return the HW VSI number
2508c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
2518c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle
2528c2ecf20Sopenharmony_ci *
2538c2ecf20Sopenharmony_ci * return the HW VSI number
2548c2ecf20Sopenharmony_ci * Caution: call this function only if VSI is valid (ice_is_vsi_valid)
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_ciu16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	return hw->vsi_ctx[vsi_handle]->vsi_num;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/**
2628c2ecf20Sopenharmony_ci * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle
2638c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
2648c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle
2658c2ecf20Sopenharmony_ci *
2668c2ecf20Sopenharmony_ci * return the VSI context entry for a given VSI handle
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistruct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci/**
2748c2ecf20Sopenharmony_ci * ice_save_vsi_ctx - save the VSI context for a given VSI handle
2758c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
2768c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle
2778c2ecf20Sopenharmony_ci * @vsi: VSI context pointer
2788c2ecf20Sopenharmony_ci *
2798c2ecf20Sopenharmony_ci * save the VSI context entry for a given VSI handle
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic void
2828c2ecf20Sopenharmony_ciice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	hw->vsi_ctx[vsi_handle] = vsi;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/**
2888c2ecf20Sopenharmony_ci * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs
2898c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
2908c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle
2918c2ecf20Sopenharmony_ci */
2928c2ecf20Sopenharmony_cistatic void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct ice_vsi_ctx *vsi;
2958c2ecf20Sopenharmony_ci	u8 i;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	vsi = ice_get_vsi_ctx(hw, vsi_handle);
2988c2ecf20Sopenharmony_ci	if (!vsi)
2998c2ecf20Sopenharmony_ci		return;
3008c2ecf20Sopenharmony_ci	ice_for_each_traffic_class(i) {
3018c2ecf20Sopenharmony_ci		if (vsi->lan_q_ctx[i]) {
3028c2ecf20Sopenharmony_ci			devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]);
3038c2ecf20Sopenharmony_ci			vsi->lan_q_ctx[i] = NULL;
3048c2ecf20Sopenharmony_ci		}
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/**
3098c2ecf20Sopenharmony_ci * ice_clear_vsi_ctx - clear the VSI context entry
3108c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
3118c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle
3128c2ecf20Sopenharmony_ci *
3138c2ecf20Sopenharmony_ci * clear the VSI context entry
3148c2ecf20Sopenharmony_ci */
3158c2ecf20Sopenharmony_cistatic void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct ice_vsi_ctx *vsi;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	vsi = ice_get_vsi_ctx(hw, vsi_handle);
3208c2ecf20Sopenharmony_ci	if (vsi) {
3218c2ecf20Sopenharmony_ci		ice_clear_vsi_q_ctx(hw, vsi_handle);
3228c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), vsi);
3238c2ecf20Sopenharmony_ci		hw->vsi_ctx[vsi_handle] = NULL;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci/**
3288c2ecf20Sopenharmony_ci * ice_clear_all_vsi_ctx - clear all the VSI context entries
3298c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
3308c2ecf20Sopenharmony_ci */
3318c2ecf20Sopenharmony_civoid ice_clear_all_vsi_ctx(struct ice_hw *hw)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	u16 i;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	for (i = 0; i < ICE_MAX_VSI; i++)
3368c2ecf20Sopenharmony_ci		ice_clear_vsi_ctx(hw, i);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci/**
3408c2ecf20Sopenharmony_ci * ice_add_vsi - add VSI context to the hardware and VSI handle list
3418c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
3428c2ecf20Sopenharmony_ci * @vsi_handle: unique VSI handle provided by drivers
3438c2ecf20Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
3448c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
3458c2ecf20Sopenharmony_ci *
3468c2ecf20Sopenharmony_ci * Add a VSI context to the hardware also add it into the VSI handle list.
3478c2ecf20Sopenharmony_ci * If this function gets called after reset for existing VSIs then update
3488c2ecf20Sopenharmony_ci * with the new HW VSI number in the corresponding VSI handle list entry.
3498c2ecf20Sopenharmony_ci */
3508c2ecf20Sopenharmony_cienum ice_status
3518c2ecf20Sopenharmony_ciice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
3528c2ecf20Sopenharmony_ci	    struct ice_sq_cd *cd)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	struct ice_vsi_ctx *tmp_vsi_ctx;
3558c2ecf20Sopenharmony_ci	enum ice_status status;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (vsi_handle >= ICE_MAX_VSI)
3588c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
3598c2ecf20Sopenharmony_ci	status = ice_aq_add_vsi(hw, vsi_ctx, cd);
3608c2ecf20Sopenharmony_ci	if (status)
3618c2ecf20Sopenharmony_ci		return status;
3628c2ecf20Sopenharmony_ci	tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
3638c2ecf20Sopenharmony_ci	if (!tmp_vsi_ctx) {
3648c2ecf20Sopenharmony_ci		/* Create a new VSI context */
3658c2ecf20Sopenharmony_ci		tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw),
3668c2ecf20Sopenharmony_ci					   sizeof(*tmp_vsi_ctx), GFP_KERNEL);
3678c2ecf20Sopenharmony_ci		if (!tmp_vsi_ctx) {
3688c2ecf20Sopenharmony_ci			ice_aq_free_vsi(hw, vsi_ctx, false, cd);
3698c2ecf20Sopenharmony_ci			return ICE_ERR_NO_MEMORY;
3708c2ecf20Sopenharmony_ci		}
3718c2ecf20Sopenharmony_ci		*tmp_vsi_ctx = *vsi_ctx;
3728c2ecf20Sopenharmony_ci		ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);
3738c2ecf20Sopenharmony_ci	} else {
3748c2ecf20Sopenharmony_ci		/* update with new HW VSI num */
3758c2ecf20Sopenharmony_ci		tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return 0;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci/**
3828c2ecf20Sopenharmony_ci * ice_free_vsi- free VSI context from hardware and VSI handle list
3838c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
3848c2ecf20Sopenharmony_ci * @vsi_handle: unique VSI handle
3858c2ecf20Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
3868c2ecf20Sopenharmony_ci * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
3878c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
3888c2ecf20Sopenharmony_ci *
3898c2ecf20Sopenharmony_ci * Free VSI context info from hardware as well as from VSI handle list
3908c2ecf20Sopenharmony_ci */
3918c2ecf20Sopenharmony_cienum ice_status
3928c2ecf20Sopenharmony_ciice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
3938c2ecf20Sopenharmony_ci	     bool keep_vsi_alloc, struct ice_sq_cd *cd)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	enum ice_status status;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
3988c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
3998c2ecf20Sopenharmony_ci	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
4008c2ecf20Sopenharmony_ci	status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);
4018c2ecf20Sopenharmony_ci	if (!status)
4028c2ecf20Sopenharmony_ci		ice_clear_vsi_ctx(hw, vsi_handle);
4038c2ecf20Sopenharmony_ci	return status;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/**
4078c2ecf20Sopenharmony_ci * ice_update_vsi
4088c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
4098c2ecf20Sopenharmony_ci * @vsi_handle: unique VSI handle
4108c2ecf20Sopenharmony_ci * @vsi_ctx: pointer to a VSI context struct
4118c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
4128c2ecf20Sopenharmony_ci *
4138c2ecf20Sopenharmony_ci * Update VSI context in the hardware
4148c2ecf20Sopenharmony_ci */
4158c2ecf20Sopenharmony_cienum ice_status
4168c2ecf20Sopenharmony_ciice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
4178c2ecf20Sopenharmony_ci	       struct ice_sq_cd *cd)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
4208c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
4218c2ecf20Sopenharmony_ci	vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
4228c2ecf20Sopenharmony_ci	return ice_aq_update_vsi(hw, vsi_ctx, cd);
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci/**
4268c2ecf20Sopenharmony_ci * ice_aq_alloc_free_vsi_list
4278c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
4288c2ecf20Sopenharmony_ci * @vsi_list_id: VSI list ID returned or used for lookup
4298c2ecf20Sopenharmony_ci * @lkup_type: switch rule filter lookup type
4308c2ecf20Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
4318c2ecf20Sopenharmony_ci *
4328c2ecf20Sopenharmony_ci * allocates or free a VSI list resource
4338c2ecf20Sopenharmony_ci */
4348c2ecf20Sopenharmony_cistatic enum ice_status
4358c2ecf20Sopenharmony_ciice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
4368c2ecf20Sopenharmony_ci			   enum ice_sw_lkup_type lkup_type,
4378c2ecf20Sopenharmony_ci			   enum ice_adminq_opc opc)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *sw_buf;
4408c2ecf20Sopenharmony_ci	struct ice_aqc_res_elem *vsi_ele;
4418c2ecf20Sopenharmony_ci	enum ice_status status;
4428c2ecf20Sopenharmony_ci	u16 buf_len;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	buf_len = struct_size(sw_buf, elem, 1);
4458c2ecf20Sopenharmony_ci	sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL);
4468c2ecf20Sopenharmony_ci	if (!sw_buf)
4478c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
4488c2ecf20Sopenharmony_ci	sw_buf->num_elems = cpu_to_le16(1);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (lkup_type == ICE_SW_LKUP_MAC ||
4518c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
4528c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
4538c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
4548c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC ||
4558c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN) {
4568c2ecf20Sopenharmony_ci		sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP);
4578c2ecf20Sopenharmony_ci	} else if (lkup_type == ICE_SW_LKUP_VLAN) {
4588c2ecf20Sopenharmony_ci		sw_buf->res_type =
4598c2ecf20Sopenharmony_ci			cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
4608c2ecf20Sopenharmony_ci	} else {
4618c2ecf20Sopenharmony_ci		status = ICE_ERR_PARAM;
4628c2ecf20Sopenharmony_ci		goto ice_aq_alloc_free_vsi_list_exit;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (opc == ice_aqc_opc_free_res)
4668c2ecf20Sopenharmony_ci		sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL);
4698c2ecf20Sopenharmony_ci	if (status)
4708c2ecf20Sopenharmony_ci		goto ice_aq_alloc_free_vsi_list_exit;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (opc == ice_aqc_opc_alloc_res) {
4738c2ecf20Sopenharmony_ci		vsi_ele = &sw_buf->elem[0];
4748c2ecf20Sopenharmony_ci		*vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp);
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ciice_aq_alloc_free_vsi_list_exit:
4788c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), sw_buf);
4798c2ecf20Sopenharmony_ci	return status;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci/**
4838c2ecf20Sopenharmony_ci * ice_aq_sw_rules - add/update/remove switch rules
4848c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
4858c2ecf20Sopenharmony_ci * @rule_list: pointer to switch rule population list
4868c2ecf20Sopenharmony_ci * @rule_list_sz: total size of the rule list in bytes
4878c2ecf20Sopenharmony_ci * @num_rules: number of switch rules in the rule_list
4888c2ecf20Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
4898c2ecf20Sopenharmony_ci * @cd: pointer to command details structure or NULL
4908c2ecf20Sopenharmony_ci *
4918c2ecf20Sopenharmony_ci * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware
4928c2ecf20Sopenharmony_ci */
4938c2ecf20Sopenharmony_cistatic enum ice_status
4948c2ecf20Sopenharmony_ciice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
4958c2ecf20Sopenharmony_ci		u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct ice_aq_desc desc;
4988c2ecf20Sopenharmony_ci	enum ice_status status;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (opc != ice_aqc_opc_add_sw_rules &&
5018c2ecf20Sopenharmony_ci	    opc != ice_aqc_opc_update_sw_rules &&
5028c2ecf20Sopenharmony_ci	    opc != ice_aqc_opc_remove_sw_rules)
5038c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	ice_fill_dflt_direct_cmd_desc(&desc, opc);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
5088c2ecf20Sopenharmony_ci	desc.params.sw_rules.num_rules_fltr_entry_index =
5098c2ecf20Sopenharmony_ci		cpu_to_le16(num_rules);
5108c2ecf20Sopenharmony_ci	status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd);
5118c2ecf20Sopenharmony_ci	if (opc != ice_aqc_opc_add_sw_rules &&
5128c2ecf20Sopenharmony_ci	    hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
5138c2ecf20Sopenharmony_ci		status = ICE_ERR_DOES_NOT_EXIST;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	return status;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci/* ice_init_port_info - Initialize port_info with switch configuration data
5198c2ecf20Sopenharmony_ci * @pi: pointer to port_info
5208c2ecf20Sopenharmony_ci * @vsi_port_num: VSI number or port number
5218c2ecf20Sopenharmony_ci * @type: Type of switch element (port or VSI)
5228c2ecf20Sopenharmony_ci * @swid: switch ID of the switch the element is attached to
5238c2ecf20Sopenharmony_ci * @pf_vf_num: PF or VF number
5248c2ecf20Sopenharmony_ci * @is_vf: true if the element is a VF, false otherwise
5258c2ecf20Sopenharmony_ci */
5268c2ecf20Sopenharmony_cistatic void
5278c2ecf20Sopenharmony_ciice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type,
5288c2ecf20Sopenharmony_ci		   u16 swid, u16 pf_vf_num, bool is_vf)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	switch (type) {
5318c2ecf20Sopenharmony_ci	case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:
5328c2ecf20Sopenharmony_ci		pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK);
5338c2ecf20Sopenharmony_ci		pi->sw_id = swid;
5348c2ecf20Sopenharmony_ci		pi->pf_vf_num = pf_vf_num;
5358c2ecf20Sopenharmony_ci		pi->is_vf = is_vf;
5368c2ecf20Sopenharmony_ci		pi->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;
5378c2ecf20Sopenharmony_ci		pi->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;
5388c2ecf20Sopenharmony_ci		break;
5398c2ecf20Sopenharmony_ci	default:
5408c2ecf20Sopenharmony_ci		ice_debug(pi->hw, ICE_DBG_SW,
5418c2ecf20Sopenharmony_ci			  "incorrect VSI/port type received\n");
5428c2ecf20Sopenharmony_ci		break;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci/* ice_get_initial_sw_cfg - Get initial port and default VSI data
5478c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
5488c2ecf20Sopenharmony_ci */
5498c2ecf20Sopenharmony_cienum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct ice_aqc_get_sw_cfg_resp_elem *rbuf;
5528c2ecf20Sopenharmony_ci	enum ice_status status;
5538c2ecf20Sopenharmony_ci	u16 req_desc = 0;
5548c2ecf20Sopenharmony_ci	u16 num_elems;
5558c2ecf20Sopenharmony_ci	u16 i;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	rbuf = devm_kzalloc(ice_hw_to_dev(hw), ICE_SW_CFG_MAX_BUF_LEN,
5588c2ecf20Sopenharmony_ci			    GFP_KERNEL);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	if (!rbuf)
5618c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	/* Multiple calls to ice_aq_get_sw_cfg may be required
5648c2ecf20Sopenharmony_ci	 * to get all the switch configuration information. The need
5658c2ecf20Sopenharmony_ci	 * for additional calls is indicated by ice_aq_get_sw_cfg
5668c2ecf20Sopenharmony_ci	 * writing a non-zero value in req_desc
5678c2ecf20Sopenharmony_ci	 */
5688c2ecf20Sopenharmony_ci	do {
5698c2ecf20Sopenharmony_ci		struct ice_aqc_get_sw_cfg_resp_elem *ele;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN,
5728c2ecf20Sopenharmony_ci					   &req_desc, &num_elems, NULL);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		if (status)
5758c2ecf20Sopenharmony_ci			break;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci		for (i = 0, ele = rbuf; i < num_elems; i++, ele++) {
5788c2ecf20Sopenharmony_ci			u16 pf_vf_num, swid, vsi_port_num;
5798c2ecf20Sopenharmony_ci			bool is_vf = false;
5808c2ecf20Sopenharmony_ci			u8 res_type;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci			vsi_port_num = le16_to_cpu(ele->vsi_port_num) &
5838c2ecf20Sopenharmony_ci				ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci			pf_vf_num = le16_to_cpu(ele->pf_vf_num) &
5868c2ecf20Sopenharmony_ci				ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci			swid = le16_to_cpu(ele->swid);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci			if (le16_to_cpu(ele->pf_vf_num) &
5918c2ecf20Sopenharmony_ci			    ICE_AQC_GET_SW_CONF_RESP_IS_VF)
5928c2ecf20Sopenharmony_ci				is_vf = true;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci			res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >>
5958c2ecf20Sopenharmony_ci					ICE_AQC_GET_SW_CONF_RESP_TYPE_S);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci			if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) {
5988c2ecf20Sopenharmony_ci				/* FW VSI is not needed. Just continue. */
5998c2ecf20Sopenharmony_ci				continue;
6008c2ecf20Sopenharmony_ci			}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci			ice_init_port_info(hw->port_info, vsi_port_num,
6038c2ecf20Sopenharmony_ci					   res_type, swid, pf_vf_num, is_vf);
6048c2ecf20Sopenharmony_ci		}
6058c2ecf20Sopenharmony_ci	} while (req_desc && !status);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), (void *)rbuf);
6088c2ecf20Sopenharmony_ci	return status;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci/**
6128c2ecf20Sopenharmony_ci * ice_fill_sw_info - Helper function to populate lb_en and lan_en
6138c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
6148c2ecf20Sopenharmony_ci * @fi: filter info structure to fill/update
6158c2ecf20Sopenharmony_ci *
6168c2ecf20Sopenharmony_ci * This helper function populates the lb_en and lan_en elements of the provided
6178c2ecf20Sopenharmony_ci * ice_fltr_info struct using the switch's type and characteristics of the
6188c2ecf20Sopenharmony_ci * switch rule being configured.
6198c2ecf20Sopenharmony_ci */
6208c2ecf20Sopenharmony_cistatic void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	fi->lb_en = false;
6238c2ecf20Sopenharmony_ci	fi->lan_en = false;
6248c2ecf20Sopenharmony_ci	if ((fi->flag & ICE_FLTR_TX) &&
6258c2ecf20Sopenharmony_ci	    (fi->fltr_act == ICE_FWD_TO_VSI ||
6268c2ecf20Sopenharmony_ci	     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
6278c2ecf20Sopenharmony_ci	     fi->fltr_act == ICE_FWD_TO_Q ||
6288c2ecf20Sopenharmony_ci	     fi->fltr_act == ICE_FWD_TO_QGRP)) {
6298c2ecf20Sopenharmony_ci		/* Setting LB for prune actions will result in replicated
6308c2ecf20Sopenharmony_ci		 * packets to the internal switch that will be dropped.
6318c2ecf20Sopenharmony_ci		 */
6328c2ecf20Sopenharmony_ci		if (fi->lkup_type != ICE_SW_LKUP_VLAN)
6338c2ecf20Sopenharmony_ci			fi->lb_en = true;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		/* Set lan_en to TRUE if
6368c2ecf20Sopenharmony_ci		 * 1. The switch is a VEB AND
6378c2ecf20Sopenharmony_ci		 * 2
6388c2ecf20Sopenharmony_ci		 * 2.1 The lookup is a directional lookup like ethertype,
6398c2ecf20Sopenharmony_ci		 * promiscuous, ethertype-MAC, promiscuous-VLAN
6408c2ecf20Sopenharmony_ci		 * and default-port OR
6418c2ecf20Sopenharmony_ci		 * 2.2 The lookup is VLAN, OR
6428c2ecf20Sopenharmony_ci		 * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR
6438c2ecf20Sopenharmony_ci		 * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC.
6448c2ecf20Sopenharmony_ci		 *
6458c2ecf20Sopenharmony_ci		 * OR
6468c2ecf20Sopenharmony_ci		 *
6478c2ecf20Sopenharmony_ci		 * The switch is a VEPA.
6488c2ecf20Sopenharmony_ci		 *
6498c2ecf20Sopenharmony_ci		 * In all other cases, the LAN enable has to be set to false.
6508c2ecf20Sopenharmony_ci		 */
6518c2ecf20Sopenharmony_ci		if (hw->evb_veb) {
6528c2ecf20Sopenharmony_ci			if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE ||
6538c2ecf20Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_PROMISC ||
6548c2ecf20Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
6558c2ecf20Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN ||
6568c2ecf20Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_DFLT ||
6578c2ecf20Sopenharmony_ci			    fi->lkup_type == ICE_SW_LKUP_VLAN ||
6588c2ecf20Sopenharmony_ci			    (fi->lkup_type == ICE_SW_LKUP_MAC &&
6598c2ecf20Sopenharmony_ci			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)) ||
6608c2ecf20Sopenharmony_ci			    (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN &&
6618c2ecf20Sopenharmony_ci			     !is_unicast_ether_addr(fi->l_data.mac.mac_addr)))
6628c2ecf20Sopenharmony_ci				fi->lan_en = true;
6638c2ecf20Sopenharmony_ci		} else {
6648c2ecf20Sopenharmony_ci			fi->lan_en = true;
6658c2ecf20Sopenharmony_ci		}
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/**
6708c2ecf20Sopenharmony_ci * ice_fill_sw_rule - Helper function to fill switch rule structure
6718c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
6728c2ecf20Sopenharmony_ci * @f_info: entry containing packet forwarding information
6738c2ecf20Sopenharmony_ci * @s_rule: switch rule structure to be filled in based on mac_entry
6748c2ecf20Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
6758c2ecf20Sopenharmony_ci */
6768c2ecf20Sopenharmony_cistatic void
6778c2ecf20Sopenharmony_ciice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
6788c2ecf20Sopenharmony_ci		 struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	u16 vlan_id = ICE_MAX_VLAN_ID + 1;
6818c2ecf20Sopenharmony_ci	void *daddr = NULL;
6828c2ecf20Sopenharmony_ci	u16 eth_hdr_sz;
6838c2ecf20Sopenharmony_ci	u8 *eth_hdr;
6848c2ecf20Sopenharmony_ci	u32 act = 0;
6858c2ecf20Sopenharmony_ci	__be16 *off;
6868c2ecf20Sopenharmony_ci	u8 q_rgn;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (opc == ice_aqc_opc_remove_sw_rules) {
6898c2ecf20Sopenharmony_ci		s_rule->pdata.lkup_tx_rx.act = 0;
6908c2ecf20Sopenharmony_ci		s_rule->pdata.lkup_tx_rx.index =
6918c2ecf20Sopenharmony_ci			cpu_to_le16(f_info->fltr_rule_id);
6928c2ecf20Sopenharmony_ci		s_rule->pdata.lkup_tx_rx.hdr_len = 0;
6938c2ecf20Sopenharmony_ci		return;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	eth_hdr_sz = sizeof(dummy_eth_header);
6978c2ecf20Sopenharmony_ci	eth_hdr = s_rule->pdata.lkup_tx_rx.hdr;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	/* initialize the ether header with a dummy header */
7008c2ecf20Sopenharmony_ci	memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz);
7018c2ecf20Sopenharmony_ci	ice_fill_sw_info(hw, f_info);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	switch (f_info->fltr_act) {
7048c2ecf20Sopenharmony_ci	case ICE_FWD_TO_VSI:
7058c2ecf20Sopenharmony_ci		act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
7068c2ecf20Sopenharmony_ci			ICE_SINGLE_ACT_VSI_ID_M;
7078c2ecf20Sopenharmony_ci		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
7088c2ecf20Sopenharmony_ci			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
7098c2ecf20Sopenharmony_ci				ICE_SINGLE_ACT_VALID_BIT;
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci	case ICE_FWD_TO_VSI_LIST:
7128c2ecf20Sopenharmony_ci		act |= ICE_SINGLE_ACT_VSI_LIST;
7138c2ecf20Sopenharmony_ci		act |= (f_info->fwd_id.vsi_list_id <<
7148c2ecf20Sopenharmony_ci			ICE_SINGLE_ACT_VSI_LIST_ID_S) &
7158c2ecf20Sopenharmony_ci			ICE_SINGLE_ACT_VSI_LIST_ID_M;
7168c2ecf20Sopenharmony_ci		if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
7178c2ecf20Sopenharmony_ci			act |= ICE_SINGLE_ACT_VSI_FORWARDING |
7188c2ecf20Sopenharmony_ci				ICE_SINGLE_ACT_VALID_BIT;
7198c2ecf20Sopenharmony_ci		break;
7208c2ecf20Sopenharmony_ci	case ICE_FWD_TO_Q:
7218c2ecf20Sopenharmony_ci		act |= ICE_SINGLE_ACT_TO_Q;
7228c2ecf20Sopenharmony_ci		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
7238c2ecf20Sopenharmony_ci			ICE_SINGLE_ACT_Q_INDEX_M;
7248c2ecf20Sopenharmony_ci		break;
7258c2ecf20Sopenharmony_ci	case ICE_DROP_PACKET:
7268c2ecf20Sopenharmony_ci		act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
7278c2ecf20Sopenharmony_ci			ICE_SINGLE_ACT_VALID_BIT;
7288c2ecf20Sopenharmony_ci		break;
7298c2ecf20Sopenharmony_ci	case ICE_FWD_TO_QGRP:
7308c2ecf20Sopenharmony_ci		q_rgn = f_info->qgrp_size > 0 ?
7318c2ecf20Sopenharmony_ci			(u8)ilog2(f_info->qgrp_size) : 0;
7328c2ecf20Sopenharmony_ci		act |= ICE_SINGLE_ACT_TO_Q;
7338c2ecf20Sopenharmony_ci		act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
7348c2ecf20Sopenharmony_ci			ICE_SINGLE_ACT_Q_INDEX_M;
7358c2ecf20Sopenharmony_ci		act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
7368c2ecf20Sopenharmony_ci			ICE_SINGLE_ACT_Q_REGION_M;
7378c2ecf20Sopenharmony_ci		break;
7388c2ecf20Sopenharmony_ci	default:
7398c2ecf20Sopenharmony_ci		return;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (f_info->lb_en)
7438c2ecf20Sopenharmony_ci		act |= ICE_SINGLE_ACT_LB_ENABLE;
7448c2ecf20Sopenharmony_ci	if (f_info->lan_en)
7458c2ecf20Sopenharmony_ci		act |= ICE_SINGLE_ACT_LAN_ENABLE;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	switch (f_info->lkup_type) {
7488c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_MAC:
7498c2ecf20Sopenharmony_ci		daddr = f_info->l_data.mac.mac_addr;
7508c2ecf20Sopenharmony_ci		break;
7518c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_VLAN:
7528c2ecf20Sopenharmony_ci		vlan_id = f_info->l_data.vlan.vlan_id;
7538c2ecf20Sopenharmony_ci		if (f_info->fltr_act == ICE_FWD_TO_VSI ||
7548c2ecf20Sopenharmony_ci		    f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
7558c2ecf20Sopenharmony_ci			act |= ICE_SINGLE_ACT_PRUNE;
7568c2ecf20Sopenharmony_ci			act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS;
7578c2ecf20Sopenharmony_ci		}
7588c2ecf20Sopenharmony_ci		break;
7598c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE_MAC:
7608c2ecf20Sopenharmony_ci		daddr = f_info->l_data.ethertype_mac.mac_addr;
7618c2ecf20Sopenharmony_ci		fallthrough;
7628c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE:
7638c2ecf20Sopenharmony_ci		off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
7648c2ecf20Sopenharmony_ci		*off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype);
7658c2ecf20Sopenharmony_ci		break;
7668c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_MAC_VLAN:
7678c2ecf20Sopenharmony_ci		daddr = f_info->l_data.mac_vlan.mac_addr;
7688c2ecf20Sopenharmony_ci		vlan_id = f_info->l_data.mac_vlan.vlan_id;
7698c2ecf20Sopenharmony_ci		break;
7708c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_PROMISC_VLAN:
7718c2ecf20Sopenharmony_ci		vlan_id = f_info->l_data.mac_vlan.vlan_id;
7728c2ecf20Sopenharmony_ci		fallthrough;
7738c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_PROMISC:
7748c2ecf20Sopenharmony_ci		daddr = f_info->l_data.mac_vlan.mac_addr;
7758c2ecf20Sopenharmony_ci		break;
7768c2ecf20Sopenharmony_ci	default:
7778c2ecf20Sopenharmony_ci		break;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	s_rule->type = (f_info->flag & ICE_FLTR_RX) ?
7818c2ecf20Sopenharmony_ci		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) :
7828c2ecf20Sopenharmony_ci		cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	/* Recipe set depending on lookup type */
7858c2ecf20Sopenharmony_ci	s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(f_info->lkup_type);
7868c2ecf20Sopenharmony_ci	s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(f_info->src);
7878c2ecf20Sopenharmony_ci	s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	if (daddr)
7908c2ecf20Sopenharmony_ci		ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	if (!(vlan_id > ICE_MAX_VLAN_ID)) {
7938c2ecf20Sopenharmony_ci		off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
7948c2ecf20Sopenharmony_ci		*off = cpu_to_be16(vlan_id);
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	/* Create the switch rule with the final dummy Ethernet header */
7988c2ecf20Sopenharmony_ci	if (opc != ice_aqc_opc_update_sw_rules)
7998c2ecf20Sopenharmony_ci		s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(eth_hdr_sz);
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci/**
8038c2ecf20Sopenharmony_ci * ice_add_marker_act
8048c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
8058c2ecf20Sopenharmony_ci * @m_ent: the management entry for which sw marker needs to be added
8068c2ecf20Sopenharmony_ci * @sw_marker: sw marker to tag the Rx descriptor with
8078c2ecf20Sopenharmony_ci * @l_id: large action resource ID
8088c2ecf20Sopenharmony_ci *
8098c2ecf20Sopenharmony_ci * Create a large action to hold software marker and update the switch rule
8108c2ecf20Sopenharmony_ci * entry pointed by m_ent with newly created large action
8118c2ecf20Sopenharmony_ci */
8128c2ecf20Sopenharmony_cistatic enum ice_status
8138c2ecf20Sopenharmony_ciice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
8148c2ecf20Sopenharmony_ci		   u16 sw_marker, u16 l_id)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	struct ice_aqc_sw_rules_elem *lg_act, *rx_tx;
8178c2ecf20Sopenharmony_ci	/* For software marker we need 3 large actions
8188c2ecf20Sopenharmony_ci	 * 1. FWD action: FWD TO VSI or VSI LIST
8198c2ecf20Sopenharmony_ci	 * 2. GENERIC VALUE action to hold the profile ID
8208c2ecf20Sopenharmony_ci	 * 3. GENERIC VALUE action to hold the software marker ID
8218c2ecf20Sopenharmony_ci	 */
8228c2ecf20Sopenharmony_ci	const u16 num_lg_acts = 3;
8238c2ecf20Sopenharmony_ci	enum ice_status status;
8248c2ecf20Sopenharmony_ci	u16 lg_act_size;
8258c2ecf20Sopenharmony_ci	u16 rules_size;
8268c2ecf20Sopenharmony_ci	u32 act;
8278c2ecf20Sopenharmony_ci	u16 id;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
8308c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	/* Create two back-to-back switch rules and submit them to the HW using
8338c2ecf20Sopenharmony_ci	 * one memory buffer:
8348c2ecf20Sopenharmony_ci	 *    1. Large Action
8358c2ecf20Sopenharmony_ci	 *    2. Look up Tx Rx
8368c2ecf20Sopenharmony_ci	 */
8378c2ecf20Sopenharmony_ci	lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(num_lg_acts);
8388c2ecf20Sopenharmony_ci	rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;
8398c2ecf20Sopenharmony_ci	lg_act = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL);
8408c2ecf20Sopenharmony_ci	if (!lg_act)
8418c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	rx_tx = (struct ice_aqc_sw_rules_elem *)((u8 *)lg_act + lg_act_size);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	/* Fill in the first switch rule i.e. large action */
8468c2ecf20Sopenharmony_ci	lg_act->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT);
8478c2ecf20Sopenharmony_ci	lg_act->pdata.lg_act.index = cpu_to_le16(l_id);
8488c2ecf20Sopenharmony_ci	lg_act->pdata.lg_act.size = cpu_to_le16(num_lg_acts);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	/* First action VSI forwarding or VSI list forwarding depending on how
8518c2ecf20Sopenharmony_ci	 * many VSIs
8528c2ecf20Sopenharmony_ci	 */
8538c2ecf20Sopenharmony_ci	id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id :
8548c2ecf20Sopenharmony_ci		m_ent->fltr_info.fwd_id.hw_vsi_id;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
8578c2ecf20Sopenharmony_ci	act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M;
8588c2ecf20Sopenharmony_ci	if (m_ent->vsi_count > 1)
8598c2ecf20Sopenharmony_ci		act |= ICE_LG_ACT_VSI_LIST;
8608c2ecf20Sopenharmony_ci	lg_act->pdata.lg_act.act[0] = cpu_to_le32(act);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	/* Second action descriptor type */
8638c2ecf20Sopenharmony_ci	act = ICE_LG_ACT_GENERIC;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;
8668c2ecf20Sopenharmony_ci	lg_act->pdata.lg_act.act[1] = cpu_to_le32(act);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<
8698c2ecf20Sopenharmony_ci	       ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* Third action Marker value */
8728c2ecf20Sopenharmony_ci	act |= ICE_LG_ACT_GENERIC;
8738c2ecf20Sopenharmony_ci	act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &
8748c2ecf20Sopenharmony_ci		ICE_LG_ACT_GENERIC_VALUE_M;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	lg_act->pdata.lg_act.act[2] = cpu_to_le32(act);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* call the fill switch rule to fill the lookup Tx Rx structure */
8798c2ecf20Sopenharmony_ci	ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx,
8808c2ecf20Sopenharmony_ci			 ice_aqc_opc_update_sw_rules);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* Update the action to point to the large action ID */
8838c2ecf20Sopenharmony_ci	rx_tx->pdata.lkup_tx_rx.act =
8848c2ecf20Sopenharmony_ci		cpu_to_le32(ICE_SINGLE_ACT_PTR |
8858c2ecf20Sopenharmony_ci			    ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &
8868c2ecf20Sopenharmony_ci			     ICE_SINGLE_ACT_PTR_VAL_M));
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	/* Use the filter rule ID of the previously created rule with single
8898c2ecf20Sopenharmony_ci	 * act. Once the update happens, hardware will treat this as large
8908c2ecf20Sopenharmony_ci	 * action
8918c2ecf20Sopenharmony_ci	 */
8928c2ecf20Sopenharmony_ci	rx_tx->pdata.lkup_tx_rx.index =
8938c2ecf20Sopenharmony_ci		cpu_to_le16(m_ent->fltr_info.fltr_rule_id);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	status = ice_aq_sw_rules(hw, lg_act, rules_size, 2,
8968c2ecf20Sopenharmony_ci				 ice_aqc_opc_update_sw_rules, NULL);
8978c2ecf20Sopenharmony_ci	if (!status) {
8988c2ecf20Sopenharmony_ci		m_ent->lg_act_idx = l_id;
8998c2ecf20Sopenharmony_ci		m_ent->sw_marker_id = sw_marker;
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), lg_act);
9038c2ecf20Sopenharmony_ci	return status;
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci/**
9078c2ecf20Sopenharmony_ci * ice_create_vsi_list_map
9088c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
9098c2ecf20Sopenharmony_ci * @vsi_handle_arr: array of VSI handles to set in the VSI mapping
9108c2ecf20Sopenharmony_ci * @num_vsi: number of VSI handles in the array
9118c2ecf20Sopenharmony_ci * @vsi_list_id: VSI list ID generated as part of allocate resource
9128c2ecf20Sopenharmony_ci *
9138c2ecf20Sopenharmony_ci * Helper function to create a new entry of VSI list ID to VSI mapping
9148c2ecf20Sopenharmony_ci * using the given VSI list ID
9158c2ecf20Sopenharmony_ci */
9168c2ecf20Sopenharmony_cistatic struct ice_vsi_list_map_info *
9178c2ecf20Sopenharmony_ciice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
9188c2ecf20Sopenharmony_ci			u16 vsi_list_id)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
9218c2ecf20Sopenharmony_ci	struct ice_vsi_list_map_info *v_map;
9228c2ecf20Sopenharmony_ci	int i;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	v_map = devm_kcalloc(ice_hw_to_dev(hw), 1, sizeof(*v_map), GFP_KERNEL);
9258c2ecf20Sopenharmony_ci	if (!v_map)
9268c2ecf20Sopenharmony_ci		return NULL;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	v_map->vsi_list_id = vsi_list_id;
9298c2ecf20Sopenharmony_ci	v_map->ref_cnt = 1;
9308c2ecf20Sopenharmony_ci	for (i = 0; i < num_vsi; i++)
9318c2ecf20Sopenharmony_ci		set_bit(vsi_handle_arr[i], v_map->vsi_map);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	list_add(&v_map->list_entry, &sw->vsi_list_map_head);
9348c2ecf20Sopenharmony_ci	return v_map;
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci/**
9388c2ecf20Sopenharmony_ci * ice_update_vsi_list_rule
9398c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
9408c2ecf20Sopenharmony_ci * @vsi_handle_arr: array of VSI handles to form a VSI list
9418c2ecf20Sopenharmony_ci * @num_vsi: number of VSI handles in the array
9428c2ecf20Sopenharmony_ci * @vsi_list_id: VSI list ID generated as part of allocate resource
9438c2ecf20Sopenharmony_ci * @remove: Boolean value to indicate if this is a remove action
9448c2ecf20Sopenharmony_ci * @opc: switch rules population command type - pass in the command opcode
9458c2ecf20Sopenharmony_ci * @lkup_type: lookup type of the filter
9468c2ecf20Sopenharmony_ci *
9478c2ecf20Sopenharmony_ci * Call AQ command to add a new switch rule or update existing switch rule
9488c2ecf20Sopenharmony_ci * using the given VSI list ID
9498c2ecf20Sopenharmony_ci */
9508c2ecf20Sopenharmony_cistatic enum ice_status
9518c2ecf20Sopenharmony_ciice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
9528c2ecf20Sopenharmony_ci			 u16 vsi_list_id, bool remove, enum ice_adminq_opc opc,
9538c2ecf20Sopenharmony_ci			 enum ice_sw_lkup_type lkup_type)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	struct ice_aqc_sw_rules_elem *s_rule;
9568c2ecf20Sopenharmony_ci	enum ice_status status;
9578c2ecf20Sopenharmony_ci	u16 s_rule_size;
9588c2ecf20Sopenharmony_ci	u16 rule_type;
9598c2ecf20Sopenharmony_ci	int i;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (!num_vsi)
9628c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (lkup_type == ICE_SW_LKUP_MAC ||
9658c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_MAC_VLAN ||
9668c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE ||
9678c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC ||
9688c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC ||
9698c2ecf20Sopenharmony_ci	    lkup_type == ICE_SW_LKUP_PROMISC_VLAN)
9708c2ecf20Sopenharmony_ci		rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR :
9718c2ecf20Sopenharmony_ci			ICE_AQC_SW_RULES_T_VSI_LIST_SET;
9728c2ecf20Sopenharmony_ci	else if (lkup_type == ICE_SW_LKUP_VLAN)
9738c2ecf20Sopenharmony_ci		rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR :
9748c2ecf20Sopenharmony_ci			ICE_AQC_SW_RULES_T_PRUNE_LIST_SET;
9758c2ecf20Sopenharmony_ci	else
9768c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(num_vsi);
9798c2ecf20Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
9808c2ecf20Sopenharmony_ci	if (!s_rule)
9818c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
9828c2ecf20Sopenharmony_ci	for (i = 0; i < num_vsi; i++) {
9838c2ecf20Sopenharmony_ci		if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) {
9848c2ecf20Sopenharmony_ci			status = ICE_ERR_PARAM;
9858c2ecf20Sopenharmony_ci			goto exit;
9868c2ecf20Sopenharmony_ci		}
9878c2ecf20Sopenharmony_ci		/* AQ call requires hw_vsi_id(s) */
9888c2ecf20Sopenharmony_ci		s_rule->pdata.vsi_list.vsi[i] =
9898c2ecf20Sopenharmony_ci			cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i]));
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	s_rule->type = cpu_to_le16(rule_type);
9938c2ecf20Sopenharmony_ci	s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi);
9948c2ecf20Sopenharmony_ci	s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ciexit:
9998c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
10008c2ecf20Sopenharmony_ci	return status;
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci/**
10048c2ecf20Sopenharmony_ci * ice_create_vsi_list_rule - Creates and populates a VSI list rule
10058c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
10068c2ecf20Sopenharmony_ci * @vsi_handle_arr: array of VSI handles to form a VSI list
10078c2ecf20Sopenharmony_ci * @num_vsi: number of VSI handles in the array
10088c2ecf20Sopenharmony_ci * @vsi_list_id: stores the ID of the VSI list to be created
10098c2ecf20Sopenharmony_ci * @lkup_type: switch rule filter's lookup type
10108c2ecf20Sopenharmony_ci */
10118c2ecf20Sopenharmony_cistatic enum ice_status
10128c2ecf20Sopenharmony_ciice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
10138c2ecf20Sopenharmony_ci			 u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	enum ice_status status;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type,
10188c2ecf20Sopenharmony_ci					    ice_aqc_opc_alloc_res);
10198c2ecf20Sopenharmony_ci	if (status)
10208c2ecf20Sopenharmony_ci		return status;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	/* Update the newly created VSI list to include the specified VSIs */
10238c2ecf20Sopenharmony_ci	return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi,
10248c2ecf20Sopenharmony_ci					*vsi_list_id, false,
10258c2ecf20Sopenharmony_ci					ice_aqc_opc_add_sw_rules, lkup_type);
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci/**
10298c2ecf20Sopenharmony_ci * ice_create_pkt_fwd_rule
10308c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
10318c2ecf20Sopenharmony_ci * @f_entry: entry containing packet forwarding information
10328c2ecf20Sopenharmony_ci *
10338c2ecf20Sopenharmony_ci * Create switch rule with given filter information and add an entry
10348c2ecf20Sopenharmony_ci * to the corresponding filter management list to track this switch rule
10358c2ecf20Sopenharmony_ci * and VSI mapping
10368c2ecf20Sopenharmony_ci */
10378c2ecf20Sopenharmony_cistatic enum ice_status
10388c2ecf20Sopenharmony_ciice_create_pkt_fwd_rule(struct ice_hw *hw,
10398c2ecf20Sopenharmony_ci			struct ice_fltr_list_entry *f_entry)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *fm_entry;
10428c2ecf20Sopenharmony_ci	struct ice_aqc_sw_rules_elem *s_rule;
10438c2ecf20Sopenharmony_ci	enum ice_sw_lkup_type l_type;
10448c2ecf20Sopenharmony_ci	struct ice_sw_recipe *recp;
10458c2ecf20Sopenharmony_ci	enum ice_status status;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
10488c2ecf20Sopenharmony_ci			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);
10498c2ecf20Sopenharmony_ci	if (!s_rule)
10508c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
10518c2ecf20Sopenharmony_ci	fm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry),
10528c2ecf20Sopenharmony_ci				GFP_KERNEL);
10538c2ecf20Sopenharmony_ci	if (!fm_entry) {
10548c2ecf20Sopenharmony_ci		status = ICE_ERR_NO_MEMORY;
10558c2ecf20Sopenharmony_ci		goto ice_create_pkt_fwd_rule_exit;
10568c2ecf20Sopenharmony_ci	}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	fm_entry->fltr_info = f_entry->fltr_info;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	/* Initialize all the fields for the management entry */
10618c2ecf20Sopenharmony_ci	fm_entry->vsi_count = 1;
10628c2ecf20Sopenharmony_ci	fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX;
10638c2ecf20Sopenharmony_ci	fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID;
10648c2ecf20Sopenharmony_ci	fm_entry->counter_index = ICE_INVAL_COUNTER_ID;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule,
10678c2ecf20Sopenharmony_ci			 ice_aqc_opc_add_sw_rules);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
10708c2ecf20Sopenharmony_ci				 ice_aqc_opc_add_sw_rules, NULL);
10718c2ecf20Sopenharmony_ci	if (status) {
10728c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), fm_entry);
10738c2ecf20Sopenharmony_ci		goto ice_create_pkt_fwd_rule_exit;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	f_entry->fltr_info.fltr_rule_id =
10778c2ecf20Sopenharmony_ci		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
10788c2ecf20Sopenharmony_ci	fm_entry->fltr_info.fltr_rule_id =
10798c2ecf20Sopenharmony_ci		le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	/* The book keeping entries will get removed when base driver
10828c2ecf20Sopenharmony_ci	 * calls remove filter AQ command
10838c2ecf20Sopenharmony_ci	 */
10848c2ecf20Sopenharmony_ci	l_type = fm_entry->fltr_info.lkup_type;
10858c2ecf20Sopenharmony_ci	recp = &hw->switch_info->recp_list[l_type];
10868c2ecf20Sopenharmony_ci	list_add(&fm_entry->list_entry, &recp->filt_rules);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ciice_create_pkt_fwd_rule_exit:
10898c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
10908c2ecf20Sopenharmony_ci	return status;
10918c2ecf20Sopenharmony_ci}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci/**
10948c2ecf20Sopenharmony_ci * ice_update_pkt_fwd_rule
10958c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
10968c2ecf20Sopenharmony_ci * @f_info: filter information for switch rule
10978c2ecf20Sopenharmony_ci *
10988c2ecf20Sopenharmony_ci * Call AQ command to update a previously created switch rule with a
10998c2ecf20Sopenharmony_ci * VSI list ID
11008c2ecf20Sopenharmony_ci */
11018c2ecf20Sopenharmony_cistatic enum ice_status
11028c2ecf20Sopenharmony_ciice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	struct ice_aqc_sw_rules_elem *s_rule;
11058c2ecf20Sopenharmony_ci	enum ice_status status;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw),
11088c2ecf20Sopenharmony_ci			      ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL);
11098c2ecf20Sopenharmony_ci	if (!s_rule)
11108c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(f_info->fltr_rule_id);
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	/* Update switch rule with new rule set to forward VSI list */
11178c2ecf20Sopenharmony_ci	status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
11188c2ecf20Sopenharmony_ci				 ice_aqc_opc_update_sw_rules, NULL);
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
11218c2ecf20Sopenharmony_ci	return status;
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci/**
11258c2ecf20Sopenharmony_ci * ice_update_sw_rule_bridge_mode
11268c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
11278c2ecf20Sopenharmony_ci *
11288c2ecf20Sopenharmony_ci * Updates unicast switch filter rules based on VEB/VEPA mode
11298c2ecf20Sopenharmony_ci */
11308c2ecf20Sopenharmony_cienum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
11338c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *fm_entry;
11348c2ecf20Sopenharmony_ci	enum ice_status status = 0;
11358c2ecf20Sopenharmony_ci	struct list_head *rule_head;
11368c2ecf20Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
11398c2ecf20Sopenharmony_ci	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	mutex_lock(rule_lock);
11428c2ecf20Sopenharmony_ci	list_for_each_entry(fm_entry, rule_head, list_entry) {
11438c2ecf20Sopenharmony_ci		struct ice_fltr_info *fi = &fm_entry->fltr_info;
11448c2ecf20Sopenharmony_ci		u8 *addr = fi->l_data.mac.mac_addr;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci		/* Update unicast Tx rules to reflect the selected
11478c2ecf20Sopenharmony_ci		 * VEB/VEPA mode
11488c2ecf20Sopenharmony_ci		 */
11498c2ecf20Sopenharmony_ci		if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) &&
11508c2ecf20Sopenharmony_ci		    (fi->fltr_act == ICE_FWD_TO_VSI ||
11518c2ecf20Sopenharmony_ci		     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
11528c2ecf20Sopenharmony_ci		     fi->fltr_act == ICE_FWD_TO_Q ||
11538c2ecf20Sopenharmony_ci		     fi->fltr_act == ICE_FWD_TO_QGRP)) {
11548c2ecf20Sopenharmony_ci			status = ice_update_pkt_fwd_rule(hw, fi);
11558c2ecf20Sopenharmony_ci			if (status)
11568c2ecf20Sopenharmony_ci				break;
11578c2ecf20Sopenharmony_ci		}
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	mutex_unlock(rule_lock);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	return status;
11638c2ecf20Sopenharmony_ci}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci/**
11668c2ecf20Sopenharmony_ci * ice_add_update_vsi_list
11678c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
11688c2ecf20Sopenharmony_ci * @m_entry: pointer to current filter management list entry
11698c2ecf20Sopenharmony_ci * @cur_fltr: filter information from the book keeping entry
11708c2ecf20Sopenharmony_ci * @new_fltr: filter information with the new VSI to be added
11718c2ecf20Sopenharmony_ci *
11728c2ecf20Sopenharmony_ci * Call AQ command to add or update previously created VSI list with new VSI.
11738c2ecf20Sopenharmony_ci *
11748c2ecf20Sopenharmony_ci * Helper function to do book keeping associated with adding filter information
11758c2ecf20Sopenharmony_ci * The algorithm to do the book keeping is described below :
11768c2ecf20Sopenharmony_ci * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.)
11778c2ecf20Sopenharmony_ci *	if only one VSI has been added till now
11788c2ecf20Sopenharmony_ci *		Allocate a new VSI list and add two VSIs
11798c2ecf20Sopenharmony_ci *		to this list using switch rule command
11808c2ecf20Sopenharmony_ci *		Update the previously created switch rule with the
11818c2ecf20Sopenharmony_ci *		newly created VSI list ID
11828c2ecf20Sopenharmony_ci *	if a VSI list was previously created
11838c2ecf20Sopenharmony_ci *		Add the new VSI to the previously created VSI list set
11848c2ecf20Sopenharmony_ci *		using the update switch rule command
11858c2ecf20Sopenharmony_ci */
11868c2ecf20Sopenharmony_cistatic enum ice_status
11878c2ecf20Sopenharmony_ciice_add_update_vsi_list(struct ice_hw *hw,
11888c2ecf20Sopenharmony_ci			struct ice_fltr_mgmt_list_entry *m_entry,
11898c2ecf20Sopenharmony_ci			struct ice_fltr_info *cur_fltr,
11908c2ecf20Sopenharmony_ci			struct ice_fltr_info *new_fltr)
11918c2ecf20Sopenharmony_ci{
11928c2ecf20Sopenharmony_ci	enum ice_status status = 0;
11938c2ecf20Sopenharmony_ci	u16 vsi_list_id = 0;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if ((cur_fltr->fltr_act == ICE_FWD_TO_Q ||
11968c2ecf20Sopenharmony_ci	     cur_fltr->fltr_act == ICE_FWD_TO_QGRP))
11978c2ecf20Sopenharmony_ci		return ICE_ERR_NOT_IMPL;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	if ((new_fltr->fltr_act == ICE_FWD_TO_Q ||
12008c2ecf20Sopenharmony_ci	     new_fltr->fltr_act == ICE_FWD_TO_QGRP) &&
12018c2ecf20Sopenharmony_ci	    (cur_fltr->fltr_act == ICE_FWD_TO_VSI ||
12028c2ecf20Sopenharmony_ci	     cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST))
12038c2ecf20Sopenharmony_ci		return ICE_ERR_NOT_IMPL;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) {
12068c2ecf20Sopenharmony_ci		/* Only one entry existed in the mapping and it was not already
12078c2ecf20Sopenharmony_ci		 * a part of a VSI list. So, create a VSI list with the old and
12088c2ecf20Sopenharmony_ci		 * new VSIs.
12098c2ecf20Sopenharmony_ci		 */
12108c2ecf20Sopenharmony_ci		struct ice_fltr_info tmp_fltr;
12118c2ecf20Sopenharmony_ci		u16 vsi_handle_arr[2];
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci		/* A rule already exists with the new VSI being added */
12148c2ecf20Sopenharmony_ci		if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id)
12158c2ecf20Sopenharmony_ci			return ICE_ERR_ALREADY_EXISTS;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci		vsi_handle_arr[0] = cur_fltr->vsi_handle;
12188c2ecf20Sopenharmony_ci		vsi_handle_arr[1] = new_fltr->vsi_handle;
12198c2ecf20Sopenharmony_ci		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
12208c2ecf20Sopenharmony_ci						  &vsi_list_id,
12218c2ecf20Sopenharmony_ci						  new_fltr->lkup_type);
12228c2ecf20Sopenharmony_ci		if (status)
12238c2ecf20Sopenharmony_ci			return status;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		tmp_fltr = *new_fltr;
12268c2ecf20Sopenharmony_ci		tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
12278c2ecf20Sopenharmony_ci		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
12288c2ecf20Sopenharmony_ci		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
12298c2ecf20Sopenharmony_ci		/* Update the previous switch rule of "MAC forward to VSI" to
12308c2ecf20Sopenharmony_ci		 * "MAC fwd to VSI list"
12318c2ecf20Sopenharmony_ci		 */
12328c2ecf20Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
12338c2ecf20Sopenharmony_ci		if (status)
12348c2ecf20Sopenharmony_ci			return status;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci		cur_fltr->fwd_id.vsi_list_id = vsi_list_id;
12378c2ecf20Sopenharmony_ci		cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
12388c2ecf20Sopenharmony_ci		m_entry->vsi_list_info =
12398c2ecf20Sopenharmony_ci			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
12408c2ecf20Sopenharmony_ci						vsi_list_id);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci		if (!m_entry->vsi_list_info)
12438c2ecf20Sopenharmony_ci			return ICE_ERR_NO_MEMORY;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci		/* If this entry was large action then the large action needs
12468c2ecf20Sopenharmony_ci		 * to be updated to point to FWD to VSI list
12478c2ecf20Sopenharmony_ci		 */
12488c2ecf20Sopenharmony_ci		if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID)
12498c2ecf20Sopenharmony_ci			status =
12508c2ecf20Sopenharmony_ci			    ice_add_marker_act(hw, m_entry,
12518c2ecf20Sopenharmony_ci					       m_entry->sw_marker_id,
12528c2ecf20Sopenharmony_ci					       m_entry->lg_act_idx);
12538c2ecf20Sopenharmony_ci	} else {
12548c2ecf20Sopenharmony_ci		u16 vsi_handle = new_fltr->vsi_handle;
12558c2ecf20Sopenharmony_ci		enum ice_adminq_opc opcode;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci		if (!m_entry->vsi_list_info)
12588c2ecf20Sopenharmony_ci			return ICE_ERR_CFG;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci		/* A rule already exists with the new VSI being added */
12618c2ecf20Sopenharmony_ci		if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
12628c2ecf20Sopenharmony_ci			return 0;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci		/* Update the previously created VSI list set with
12658c2ecf20Sopenharmony_ci		 * the new VSI ID passed in
12668c2ecf20Sopenharmony_ci		 */
12678c2ecf20Sopenharmony_ci		vsi_list_id = cur_fltr->fwd_id.vsi_list_id;
12688c2ecf20Sopenharmony_ci		opcode = ice_aqc_opc_update_sw_rules;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
12718c2ecf20Sopenharmony_ci						  vsi_list_id, false, opcode,
12728c2ecf20Sopenharmony_ci						  new_fltr->lkup_type);
12738c2ecf20Sopenharmony_ci		/* update VSI list mapping info with new VSI ID */
12748c2ecf20Sopenharmony_ci		if (!status)
12758c2ecf20Sopenharmony_ci			set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci	if (!status)
12788c2ecf20Sopenharmony_ci		m_entry->vsi_count++;
12798c2ecf20Sopenharmony_ci	return status;
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci/**
12838c2ecf20Sopenharmony_ci * ice_find_rule_entry - Search a rule entry
12848c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
12858c2ecf20Sopenharmony_ci * @recp_id: lookup type for which the specified rule needs to be searched
12868c2ecf20Sopenharmony_ci * @f_info: rule information
12878c2ecf20Sopenharmony_ci *
12888c2ecf20Sopenharmony_ci * Helper function to search for a given rule entry
12898c2ecf20Sopenharmony_ci * Returns pointer to entry storing the rule if found
12908c2ecf20Sopenharmony_ci */
12918c2ecf20Sopenharmony_cistatic struct ice_fltr_mgmt_list_entry *
12928c2ecf20Sopenharmony_ciice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL;
12958c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
12968c2ecf20Sopenharmony_ci	struct list_head *list_head;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	list_head = &sw->recp_list[recp_id].filt_rules;
12998c2ecf20Sopenharmony_ci	list_for_each_entry(list_itr, list_head, list_entry) {
13008c2ecf20Sopenharmony_ci		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
13018c2ecf20Sopenharmony_ci			    sizeof(f_info->l_data)) &&
13028c2ecf20Sopenharmony_ci		    f_info->flag == list_itr->fltr_info.flag) {
13038c2ecf20Sopenharmony_ci			ret = list_itr;
13048c2ecf20Sopenharmony_ci			break;
13058c2ecf20Sopenharmony_ci		}
13068c2ecf20Sopenharmony_ci	}
13078c2ecf20Sopenharmony_ci	return ret;
13088c2ecf20Sopenharmony_ci}
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci/**
13118c2ecf20Sopenharmony_ci * ice_find_vsi_list_entry - Search VSI list map with VSI count 1
13128c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
13138c2ecf20Sopenharmony_ci * @recp_id: lookup type for which VSI lists needs to be searched
13148c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to be found in VSI list
13158c2ecf20Sopenharmony_ci * @vsi_list_id: VSI list ID found containing vsi_handle
13168c2ecf20Sopenharmony_ci *
13178c2ecf20Sopenharmony_ci * Helper function to search a VSI list with single entry containing given VSI
13188c2ecf20Sopenharmony_ci * handle element. This can be extended further to search VSI list with more
13198c2ecf20Sopenharmony_ci * than 1 vsi_count. Returns pointer to VSI list entry if found.
13208c2ecf20Sopenharmony_ci */
13218c2ecf20Sopenharmony_cistatic struct ice_vsi_list_map_info *
13228c2ecf20Sopenharmony_ciice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
13238c2ecf20Sopenharmony_ci			u16 *vsi_list_id)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	struct ice_vsi_list_map_info *map_info = NULL;
13268c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
13278c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *list_itr;
13288c2ecf20Sopenharmony_ci	struct list_head *list_head;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	list_head = &sw->recp_list[recp_id].filt_rules;
13318c2ecf20Sopenharmony_ci	list_for_each_entry(list_itr, list_head, list_entry) {
13328c2ecf20Sopenharmony_ci		if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) {
13338c2ecf20Sopenharmony_ci			map_info = list_itr->vsi_list_info;
13348c2ecf20Sopenharmony_ci			if (test_bit(vsi_handle, map_info->vsi_map)) {
13358c2ecf20Sopenharmony_ci				*vsi_list_id = map_info->vsi_list_id;
13368c2ecf20Sopenharmony_ci				return map_info;
13378c2ecf20Sopenharmony_ci			}
13388c2ecf20Sopenharmony_ci		}
13398c2ecf20Sopenharmony_ci	}
13408c2ecf20Sopenharmony_ci	return NULL;
13418c2ecf20Sopenharmony_ci}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci/**
13448c2ecf20Sopenharmony_ci * ice_add_rule_internal - add rule for a given lookup type
13458c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
13468c2ecf20Sopenharmony_ci * @recp_id: lookup type (recipe ID) for which rule has to be added
13478c2ecf20Sopenharmony_ci * @f_entry: structure containing MAC forwarding information
13488c2ecf20Sopenharmony_ci *
13498c2ecf20Sopenharmony_ci * Adds or updates the rule lists for a given recipe
13508c2ecf20Sopenharmony_ci */
13518c2ecf20Sopenharmony_cistatic enum ice_status
13528c2ecf20Sopenharmony_ciice_add_rule_internal(struct ice_hw *hw, u8 recp_id,
13538c2ecf20Sopenharmony_ci		      struct ice_fltr_list_entry *f_entry)
13548c2ecf20Sopenharmony_ci{
13558c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
13568c2ecf20Sopenharmony_ci	struct ice_fltr_info *new_fltr, *cur_fltr;
13578c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *m_entry;
13588c2ecf20Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
13598c2ecf20Sopenharmony_ci	enum ice_status status = 0;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
13628c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
13638c2ecf20Sopenharmony_ci	f_entry->fltr_info.fwd_id.hw_vsi_id =
13648c2ecf20Sopenharmony_ci		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	mutex_lock(rule_lock);
13698c2ecf20Sopenharmony_ci	new_fltr = &f_entry->fltr_info;
13708c2ecf20Sopenharmony_ci	if (new_fltr->flag & ICE_FLTR_RX)
13718c2ecf20Sopenharmony_ci		new_fltr->src = hw->port_info->lport;
13728c2ecf20Sopenharmony_ci	else if (new_fltr->flag & ICE_FLTR_TX)
13738c2ecf20Sopenharmony_ci		new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	m_entry = ice_find_rule_entry(hw, recp_id, new_fltr);
13768c2ecf20Sopenharmony_ci	if (!m_entry) {
13778c2ecf20Sopenharmony_ci		mutex_unlock(rule_lock);
13788c2ecf20Sopenharmony_ci		return ice_create_pkt_fwd_rule(hw, f_entry);
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	cur_fltr = &m_entry->fltr_info;
13828c2ecf20Sopenharmony_ci	status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr);
13838c2ecf20Sopenharmony_ci	mutex_unlock(rule_lock);
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	return status;
13868c2ecf20Sopenharmony_ci}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci/**
13898c2ecf20Sopenharmony_ci * ice_remove_vsi_list_rule
13908c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
13918c2ecf20Sopenharmony_ci * @vsi_list_id: VSI list ID generated as part of allocate resource
13928c2ecf20Sopenharmony_ci * @lkup_type: switch rule filter lookup type
13938c2ecf20Sopenharmony_ci *
13948c2ecf20Sopenharmony_ci * The VSI list should be emptied before this function is called to remove the
13958c2ecf20Sopenharmony_ci * VSI list.
13968c2ecf20Sopenharmony_ci */
13978c2ecf20Sopenharmony_cistatic enum ice_status
13988c2ecf20Sopenharmony_ciice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,
13998c2ecf20Sopenharmony_ci			 enum ice_sw_lkup_type lkup_type)
14008c2ecf20Sopenharmony_ci{
14018c2ecf20Sopenharmony_ci	struct ice_aqc_sw_rules_elem *s_rule;
14028c2ecf20Sopenharmony_ci	enum ice_status status;
14038c2ecf20Sopenharmony_ci	u16 s_rule_size;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0);
14068c2ecf20Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
14078c2ecf20Sopenharmony_ci	if (!s_rule)
14088c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR);
14118c2ecf20Sopenharmony_ci	s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	/* Free the vsi_list resource that we allocated. It is assumed that the
14148c2ecf20Sopenharmony_ci	 * list is empty at this point.
14158c2ecf20Sopenharmony_ci	 */
14168c2ecf20Sopenharmony_ci	status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,
14178c2ecf20Sopenharmony_ci					    ice_aqc_opc_free_res);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
14208c2ecf20Sopenharmony_ci	return status;
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci/**
14248c2ecf20Sopenharmony_ci * ice_rem_update_vsi_list
14258c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
14268c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle of the VSI to remove
14278c2ecf20Sopenharmony_ci * @fm_list: filter management entry for which the VSI list management needs to
14288c2ecf20Sopenharmony_ci *           be done
14298c2ecf20Sopenharmony_ci */
14308c2ecf20Sopenharmony_cistatic enum ice_status
14318c2ecf20Sopenharmony_ciice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
14328c2ecf20Sopenharmony_ci			struct ice_fltr_mgmt_list_entry *fm_list)
14338c2ecf20Sopenharmony_ci{
14348c2ecf20Sopenharmony_ci	enum ice_sw_lkup_type lkup_type;
14358c2ecf20Sopenharmony_ci	enum ice_status status = 0;
14368c2ecf20Sopenharmony_ci	u16 vsi_list_id;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST ||
14398c2ecf20Sopenharmony_ci	    fm_list->vsi_count == 0)
14408c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	/* A rule with the VSI being removed does not exist */
14438c2ecf20Sopenharmony_ci	if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
14448c2ecf20Sopenharmony_ci		return ICE_ERR_DOES_NOT_EXIST;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	lkup_type = fm_list->fltr_info.lkup_type;
14478c2ecf20Sopenharmony_ci	vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id;
14488c2ecf20Sopenharmony_ci	status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
14498c2ecf20Sopenharmony_ci					  ice_aqc_opc_update_sw_rules,
14508c2ecf20Sopenharmony_ci					  lkup_type);
14518c2ecf20Sopenharmony_ci	if (status)
14528c2ecf20Sopenharmony_ci		return status;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	fm_list->vsi_count--;
14558c2ecf20Sopenharmony_ci	clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) {
14588c2ecf20Sopenharmony_ci		struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info;
14598c2ecf20Sopenharmony_ci		struct ice_vsi_list_map_info *vsi_list_info =
14608c2ecf20Sopenharmony_ci			fm_list->vsi_list_info;
14618c2ecf20Sopenharmony_ci		u16 rem_vsi_handle;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci		rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
14648c2ecf20Sopenharmony_ci						ICE_MAX_VSI);
14658c2ecf20Sopenharmony_ci		if (!ice_is_vsi_valid(hw, rem_vsi_handle))
14668c2ecf20Sopenharmony_ci			return ICE_ERR_OUT_OF_RANGE;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci		/* Make sure VSI list is empty before removing it below */
14698c2ecf20Sopenharmony_ci		status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
14708c2ecf20Sopenharmony_ci						  vsi_list_id, true,
14718c2ecf20Sopenharmony_ci						  ice_aqc_opc_update_sw_rules,
14728c2ecf20Sopenharmony_ci						  lkup_type);
14738c2ecf20Sopenharmony_ci		if (status)
14748c2ecf20Sopenharmony_ci			return status;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci		tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI;
14778c2ecf20Sopenharmony_ci		tmp_fltr_info.fwd_id.hw_vsi_id =
14788c2ecf20Sopenharmony_ci			ice_get_hw_vsi_num(hw, rem_vsi_handle);
14798c2ecf20Sopenharmony_ci		tmp_fltr_info.vsi_handle = rem_vsi_handle;
14808c2ecf20Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info);
14818c2ecf20Sopenharmony_ci		if (status) {
14828c2ecf20Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW,
14838c2ecf20Sopenharmony_ci				  "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
14848c2ecf20Sopenharmony_ci				  tmp_fltr_info.fwd_id.hw_vsi_id, status);
14858c2ecf20Sopenharmony_ci			return status;
14868c2ecf20Sopenharmony_ci		}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci		fm_list->fltr_info = tmp_fltr_info;
14898c2ecf20Sopenharmony_ci	}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) ||
14928c2ecf20Sopenharmony_ci	    (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) {
14938c2ecf20Sopenharmony_ci		struct ice_vsi_list_map_info *vsi_list_info =
14948c2ecf20Sopenharmony_ci			fm_list->vsi_list_info;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci		/* Remove the VSI list since it is no longer used */
14978c2ecf20Sopenharmony_ci		status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
14988c2ecf20Sopenharmony_ci		if (status) {
14998c2ecf20Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW,
15008c2ecf20Sopenharmony_ci				  "Failed to remove VSI list %d, error %d\n",
15018c2ecf20Sopenharmony_ci				  vsi_list_id, status);
15028c2ecf20Sopenharmony_ci			return status;
15038c2ecf20Sopenharmony_ci		}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci		list_del(&vsi_list_info->list_entry);
15068c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
15078c2ecf20Sopenharmony_ci		fm_list->vsi_list_info = NULL;
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	return status;
15118c2ecf20Sopenharmony_ci}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci/**
15148c2ecf20Sopenharmony_ci * ice_remove_rule_internal - Remove a filter rule of a given type
15158c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
15168c2ecf20Sopenharmony_ci * @recp_id: recipe ID for which the rule needs to removed
15178c2ecf20Sopenharmony_ci * @f_entry: rule entry containing filter information
15188c2ecf20Sopenharmony_ci */
15198c2ecf20Sopenharmony_cistatic enum ice_status
15208c2ecf20Sopenharmony_ciice_remove_rule_internal(struct ice_hw *hw, u8 recp_id,
15218c2ecf20Sopenharmony_ci			 struct ice_fltr_list_entry *f_entry)
15228c2ecf20Sopenharmony_ci{
15238c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
15248c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *list_elem;
15258c2ecf20Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
15268c2ecf20Sopenharmony_ci	enum ice_status status = 0;
15278c2ecf20Sopenharmony_ci	bool remove_rule = false;
15288c2ecf20Sopenharmony_ci	u16 vsi_handle;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
15318c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
15328c2ecf20Sopenharmony_ci	f_entry->fltr_info.fwd_id.hw_vsi_id =
15338c2ecf20Sopenharmony_ci		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
15368c2ecf20Sopenharmony_ci	mutex_lock(rule_lock);
15378c2ecf20Sopenharmony_ci	list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info);
15388c2ecf20Sopenharmony_ci	if (!list_elem) {
15398c2ecf20Sopenharmony_ci		status = ICE_ERR_DOES_NOT_EXIST;
15408c2ecf20Sopenharmony_ci		goto exit;
15418c2ecf20Sopenharmony_ci	}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {
15448c2ecf20Sopenharmony_ci		remove_rule = true;
15458c2ecf20Sopenharmony_ci	} else if (!list_elem->vsi_list_info) {
15468c2ecf20Sopenharmony_ci		status = ICE_ERR_DOES_NOT_EXIST;
15478c2ecf20Sopenharmony_ci		goto exit;
15488c2ecf20Sopenharmony_ci	} else if (list_elem->vsi_list_info->ref_cnt > 1) {
15498c2ecf20Sopenharmony_ci		/* a ref_cnt > 1 indicates that the vsi_list is being
15508c2ecf20Sopenharmony_ci		 * shared by multiple rules. Decrement the ref_cnt and
15518c2ecf20Sopenharmony_ci		 * remove this rule, but do not modify the list, as it
15528c2ecf20Sopenharmony_ci		 * is in-use by other rules.
15538c2ecf20Sopenharmony_ci		 */
15548c2ecf20Sopenharmony_ci		list_elem->vsi_list_info->ref_cnt--;
15558c2ecf20Sopenharmony_ci		remove_rule = true;
15568c2ecf20Sopenharmony_ci	} else {
15578c2ecf20Sopenharmony_ci		/* a ref_cnt of 1 indicates the vsi_list is only used
15588c2ecf20Sopenharmony_ci		 * by one rule. However, the original removal request is only
15598c2ecf20Sopenharmony_ci		 * for a single VSI. Update the vsi_list first, and only
15608c2ecf20Sopenharmony_ci		 * remove the rule if there are no further VSIs in this list.
15618c2ecf20Sopenharmony_ci		 */
15628c2ecf20Sopenharmony_ci		vsi_handle = f_entry->fltr_info.vsi_handle;
15638c2ecf20Sopenharmony_ci		status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem);
15648c2ecf20Sopenharmony_ci		if (status)
15658c2ecf20Sopenharmony_ci			goto exit;
15668c2ecf20Sopenharmony_ci		/* if VSI count goes to zero after updating the VSI list */
15678c2ecf20Sopenharmony_ci		if (list_elem->vsi_count == 0)
15688c2ecf20Sopenharmony_ci			remove_rule = true;
15698c2ecf20Sopenharmony_ci	}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	if (remove_rule) {
15728c2ecf20Sopenharmony_ci		/* Remove the lookup rule */
15738c2ecf20Sopenharmony_ci		struct ice_aqc_sw_rules_elem *s_rule;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci		s_rule = devm_kzalloc(ice_hw_to_dev(hw),
15768c2ecf20Sopenharmony_ci				      ICE_SW_RULE_RX_TX_NO_HDR_SIZE,
15778c2ecf20Sopenharmony_ci				      GFP_KERNEL);
15788c2ecf20Sopenharmony_ci		if (!s_rule) {
15798c2ecf20Sopenharmony_ci			status = ICE_ERR_NO_MEMORY;
15808c2ecf20Sopenharmony_ci			goto exit;
15818c2ecf20Sopenharmony_ci		}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci		ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule,
15848c2ecf20Sopenharmony_ci				 ice_aqc_opc_remove_sw_rules);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci		status = ice_aq_sw_rules(hw, s_rule,
15878c2ecf20Sopenharmony_ci					 ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1,
15888c2ecf20Sopenharmony_ci					 ice_aqc_opc_remove_sw_rules, NULL);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci		/* Remove a book keeping from the list */
15918c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), s_rule);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci		if (status)
15948c2ecf20Sopenharmony_ci			goto exit;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		list_del(&list_elem->list_entry);
15978c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), list_elem);
15988c2ecf20Sopenharmony_ci	}
15998c2ecf20Sopenharmony_ciexit:
16008c2ecf20Sopenharmony_ci	mutex_unlock(rule_lock);
16018c2ecf20Sopenharmony_ci	return status;
16028c2ecf20Sopenharmony_ci}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci/**
16058c2ecf20Sopenharmony_ci * ice_add_mac - Add a MAC address based filter rule
16068c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
16078c2ecf20Sopenharmony_ci * @m_list: list of MAC addresses and forwarding information
16088c2ecf20Sopenharmony_ci *
16098c2ecf20Sopenharmony_ci * IMPORTANT: When the ucast_shared flag is set to false and m_list has
16108c2ecf20Sopenharmony_ci * multiple unicast addresses, the function assumes that all the
16118c2ecf20Sopenharmony_ci * addresses are unique in a given add_mac call. It doesn't
16128c2ecf20Sopenharmony_ci * check for duplicates in this case, removing duplicates from a given
16138c2ecf20Sopenharmony_ci * list should be taken care of in the caller of this function.
16148c2ecf20Sopenharmony_ci */
16158c2ecf20Sopenharmony_cienum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
16168c2ecf20Sopenharmony_ci{
16178c2ecf20Sopenharmony_ci	struct ice_aqc_sw_rules_elem *s_rule, *r_iter;
16188c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *m_list_itr;
16198c2ecf20Sopenharmony_ci	struct list_head *rule_head;
16208c2ecf20Sopenharmony_ci	u16 total_elem_left, s_rule_size;
16218c2ecf20Sopenharmony_ci	struct ice_switch_info *sw;
16228c2ecf20Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
16238c2ecf20Sopenharmony_ci	enum ice_status status = 0;
16248c2ecf20Sopenharmony_ci	u16 num_unicast = 0;
16258c2ecf20Sopenharmony_ci	u8 elem_sent;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	if (!m_list || !hw)
16288c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	s_rule = NULL;
16318c2ecf20Sopenharmony_ci	sw = hw->switch_info;
16328c2ecf20Sopenharmony_ci	rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
16338c2ecf20Sopenharmony_ci	list_for_each_entry(m_list_itr, m_list, list_entry) {
16348c2ecf20Sopenharmony_ci		u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
16358c2ecf20Sopenharmony_ci		u16 vsi_handle;
16368c2ecf20Sopenharmony_ci		u16 hw_vsi_id;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci		m_list_itr->fltr_info.flag = ICE_FLTR_TX;
16398c2ecf20Sopenharmony_ci		vsi_handle = m_list_itr->fltr_info.vsi_handle;
16408c2ecf20Sopenharmony_ci		if (!ice_is_vsi_valid(hw, vsi_handle))
16418c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
16428c2ecf20Sopenharmony_ci		hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
16438c2ecf20Sopenharmony_ci		m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id;
16448c2ecf20Sopenharmony_ci		/* update the src in case it is VSI num */
16458c2ecf20Sopenharmony_ci		if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI)
16468c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
16478c2ecf20Sopenharmony_ci		m_list_itr->fltr_info.src = hw_vsi_id;
16488c2ecf20Sopenharmony_ci		if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||
16498c2ecf20Sopenharmony_ci		    is_zero_ether_addr(add))
16508c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
16518c2ecf20Sopenharmony_ci		if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
16528c2ecf20Sopenharmony_ci			/* Don't overwrite the unicast address */
16538c2ecf20Sopenharmony_ci			mutex_lock(rule_lock);
16548c2ecf20Sopenharmony_ci			if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC,
16558c2ecf20Sopenharmony_ci						&m_list_itr->fltr_info)) {
16568c2ecf20Sopenharmony_ci				mutex_unlock(rule_lock);
16578c2ecf20Sopenharmony_ci				return ICE_ERR_ALREADY_EXISTS;
16588c2ecf20Sopenharmony_ci			}
16598c2ecf20Sopenharmony_ci			mutex_unlock(rule_lock);
16608c2ecf20Sopenharmony_ci			num_unicast++;
16618c2ecf20Sopenharmony_ci		} else if (is_multicast_ether_addr(add) ||
16628c2ecf20Sopenharmony_ci			   (is_unicast_ether_addr(add) && hw->ucast_shared)) {
16638c2ecf20Sopenharmony_ci			m_list_itr->status =
16648c2ecf20Sopenharmony_ci				ice_add_rule_internal(hw, ICE_SW_LKUP_MAC,
16658c2ecf20Sopenharmony_ci						      m_list_itr);
16668c2ecf20Sopenharmony_ci			if (m_list_itr->status)
16678c2ecf20Sopenharmony_ci				return m_list_itr->status;
16688c2ecf20Sopenharmony_ci		}
16698c2ecf20Sopenharmony_ci	}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	mutex_lock(rule_lock);
16728c2ecf20Sopenharmony_ci	/* Exit if no suitable entries were found for adding bulk switch rule */
16738c2ecf20Sopenharmony_ci	if (!num_unicast) {
16748c2ecf20Sopenharmony_ci		status = 0;
16758c2ecf20Sopenharmony_ci		goto ice_add_mac_exit;
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	/* Allocate switch rule buffer for the bulk update for unicast */
16818c2ecf20Sopenharmony_ci	s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;
16828c2ecf20Sopenharmony_ci	s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,
16838c2ecf20Sopenharmony_ci			      GFP_KERNEL);
16848c2ecf20Sopenharmony_ci	if (!s_rule) {
16858c2ecf20Sopenharmony_ci		status = ICE_ERR_NO_MEMORY;
16868c2ecf20Sopenharmony_ci		goto ice_add_mac_exit;
16878c2ecf20Sopenharmony_ci	}
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	r_iter = s_rule;
16908c2ecf20Sopenharmony_ci	list_for_each_entry(m_list_itr, m_list, list_entry) {
16918c2ecf20Sopenharmony_ci		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
16928c2ecf20Sopenharmony_ci		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci		if (is_unicast_ether_addr(mac_addr)) {
16958c2ecf20Sopenharmony_ci			ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter,
16968c2ecf20Sopenharmony_ci					 ice_aqc_opc_add_sw_rules);
16978c2ecf20Sopenharmony_ci			r_iter = (struct ice_aqc_sw_rules_elem *)
16988c2ecf20Sopenharmony_ci				((u8 *)r_iter + s_rule_size);
16998c2ecf20Sopenharmony_ci		}
17008c2ecf20Sopenharmony_ci	}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	/* Call AQ bulk switch rule update for all unicast addresses */
17038c2ecf20Sopenharmony_ci	r_iter = s_rule;
17048c2ecf20Sopenharmony_ci	/* Call AQ switch rule in AQ_MAX chunk */
17058c2ecf20Sopenharmony_ci	for (total_elem_left = num_unicast; total_elem_left > 0;
17068c2ecf20Sopenharmony_ci	     total_elem_left -= elem_sent) {
17078c2ecf20Sopenharmony_ci		struct ice_aqc_sw_rules_elem *entry = r_iter;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci		elem_sent = min_t(u8, total_elem_left,
17108c2ecf20Sopenharmony_ci				  (ICE_AQ_MAX_BUF_LEN / s_rule_size));
17118c2ecf20Sopenharmony_ci		status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size,
17128c2ecf20Sopenharmony_ci					 elem_sent, ice_aqc_opc_add_sw_rules,
17138c2ecf20Sopenharmony_ci					 NULL);
17148c2ecf20Sopenharmony_ci		if (status)
17158c2ecf20Sopenharmony_ci			goto ice_add_mac_exit;
17168c2ecf20Sopenharmony_ci		r_iter = (struct ice_aqc_sw_rules_elem *)
17178c2ecf20Sopenharmony_ci			((u8 *)r_iter + (elem_sent * s_rule_size));
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	/* Fill up rule ID based on the value returned from FW */
17218c2ecf20Sopenharmony_ci	r_iter = s_rule;
17228c2ecf20Sopenharmony_ci	list_for_each_entry(m_list_itr, m_list, list_entry) {
17238c2ecf20Sopenharmony_ci		struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
17248c2ecf20Sopenharmony_ci		u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
17258c2ecf20Sopenharmony_ci		struct ice_fltr_mgmt_list_entry *fm_entry;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci		if (is_unicast_ether_addr(mac_addr)) {
17288c2ecf20Sopenharmony_ci			f_info->fltr_rule_id =
17298c2ecf20Sopenharmony_ci				le16_to_cpu(r_iter->pdata.lkup_tx_rx.index);
17308c2ecf20Sopenharmony_ci			f_info->fltr_act = ICE_FWD_TO_VSI;
17318c2ecf20Sopenharmony_ci			/* Create an entry to track this MAC address */
17328c2ecf20Sopenharmony_ci			fm_entry = devm_kzalloc(ice_hw_to_dev(hw),
17338c2ecf20Sopenharmony_ci						sizeof(*fm_entry), GFP_KERNEL);
17348c2ecf20Sopenharmony_ci			if (!fm_entry) {
17358c2ecf20Sopenharmony_ci				status = ICE_ERR_NO_MEMORY;
17368c2ecf20Sopenharmony_ci				goto ice_add_mac_exit;
17378c2ecf20Sopenharmony_ci			}
17388c2ecf20Sopenharmony_ci			fm_entry->fltr_info = *f_info;
17398c2ecf20Sopenharmony_ci			fm_entry->vsi_count = 1;
17408c2ecf20Sopenharmony_ci			/* The book keeping entries will get removed when
17418c2ecf20Sopenharmony_ci			 * base driver calls remove filter AQ command
17428c2ecf20Sopenharmony_ci			 */
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci			list_add(&fm_entry->list_entry, rule_head);
17458c2ecf20Sopenharmony_ci			r_iter = (struct ice_aqc_sw_rules_elem *)
17468c2ecf20Sopenharmony_ci				((u8 *)r_iter + s_rule_size);
17478c2ecf20Sopenharmony_ci		}
17488c2ecf20Sopenharmony_ci	}
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ciice_add_mac_exit:
17518c2ecf20Sopenharmony_ci	mutex_unlock(rule_lock);
17528c2ecf20Sopenharmony_ci	if (s_rule)
17538c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), s_rule);
17548c2ecf20Sopenharmony_ci	return status;
17558c2ecf20Sopenharmony_ci}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci/**
17588c2ecf20Sopenharmony_ci * ice_add_vlan_internal - Add one VLAN based filter rule
17598c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
17608c2ecf20Sopenharmony_ci * @f_entry: filter entry containing one VLAN information
17618c2ecf20Sopenharmony_ci */
17628c2ecf20Sopenharmony_cistatic enum ice_status
17638c2ecf20Sopenharmony_ciice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
17648c2ecf20Sopenharmony_ci{
17658c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
17668c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *v_list_itr;
17678c2ecf20Sopenharmony_ci	struct ice_fltr_info *new_fltr, *cur_fltr;
17688c2ecf20Sopenharmony_ci	enum ice_sw_lkup_type lkup_type;
17698c2ecf20Sopenharmony_ci	u16 vsi_list_id = 0, vsi_handle;
17708c2ecf20Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
17718c2ecf20Sopenharmony_ci	enum ice_status status = 0;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
17748c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	f_entry->fltr_info.fwd_id.hw_vsi_id =
17778c2ecf20Sopenharmony_ci		ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
17788c2ecf20Sopenharmony_ci	new_fltr = &f_entry->fltr_info;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	/* VLAN ID should only be 12 bits */
17818c2ecf20Sopenharmony_ci	if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)
17828c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	if (new_fltr->src_id != ICE_SRC_ID_VSI)
17858c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	new_fltr->src = new_fltr->fwd_id.hw_vsi_id;
17888c2ecf20Sopenharmony_ci	lkup_type = new_fltr->lkup_type;
17898c2ecf20Sopenharmony_ci	vsi_handle = new_fltr->vsi_handle;
17908c2ecf20Sopenharmony_ci	rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
17918c2ecf20Sopenharmony_ci	mutex_lock(rule_lock);
17928c2ecf20Sopenharmony_ci	v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr);
17938c2ecf20Sopenharmony_ci	if (!v_list_itr) {
17948c2ecf20Sopenharmony_ci		struct ice_vsi_list_map_info *map_info = NULL;
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci		if (new_fltr->fltr_act == ICE_FWD_TO_VSI) {
17978c2ecf20Sopenharmony_ci			/* All VLAN pruning rules use a VSI list. Check if
17988c2ecf20Sopenharmony_ci			 * there is already a VSI list containing VSI that we
17998c2ecf20Sopenharmony_ci			 * want to add. If found, use the same vsi_list_id for
18008c2ecf20Sopenharmony_ci			 * this new VLAN rule or else create a new list.
18018c2ecf20Sopenharmony_ci			 */
18028c2ecf20Sopenharmony_ci			map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN,
18038c2ecf20Sopenharmony_ci							   vsi_handle,
18048c2ecf20Sopenharmony_ci							   &vsi_list_id);
18058c2ecf20Sopenharmony_ci			if (!map_info) {
18068c2ecf20Sopenharmony_ci				status = ice_create_vsi_list_rule(hw,
18078c2ecf20Sopenharmony_ci								  &vsi_handle,
18088c2ecf20Sopenharmony_ci								  1,
18098c2ecf20Sopenharmony_ci								  &vsi_list_id,
18108c2ecf20Sopenharmony_ci								  lkup_type);
18118c2ecf20Sopenharmony_ci				if (status)
18128c2ecf20Sopenharmony_ci					goto exit;
18138c2ecf20Sopenharmony_ci			}
18148c2ecf20Sopenharmony_ci			/* Convert the action to forwarding to a VSI list. */
18158c2ecf20Sopenharmony_ci			new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
18168c2ecf20Sopenharmony_ci			new_fltr->fwd_id.vsi_list_id = vsi_list_id;
18178c2ecf20Sopenharmony_ci		}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci		status = ice_create_pkt_fwd_rule(hw, f_entry);
18208c2ecf20Sopenharmony_ci		if (!status) {
18218c2ecf20Sopenharmony_ci			v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN,
18228c2ecf20Sopenharmony_ci							 new_fltr);
18238c2ecf20Sopenharmony_ci			if (!v_list_itr) {
18248c2ecf20Sopenharmony_ci				status = ICE_ERR_DOES_NOT_EXIST;
18258c2ecf20Sopenharmony_ci				goto exit;
18268c2ecf20Sopenharmony_ci			}
18278c2ecf20Sopenharmony_ci			/* reuse VSI list for new rule and increment ref_cnt */
18288c2ecf20Sopenharmony_ci			if (map_info) {
18298c2ecf20Sopenharmony_ci				v_list_itr->vsi_list_info = map_info;
18308c2ecf20Sopenharmony_ci				map_info->ref_cnt++;
18318c2ecf20Sopenharmony_ci			} else {
18328c2ecf20Sopenharmony_ci				v_list_itr->vsi_list_info =
18338c2ecf20Sopenharmony_ci					ice_create_vsi_list_map(hw, &vsi_handle,
18348c2ecf20Sopenharmony_ci								1, vsi_list_id);
18358c2ecf20Sopenharmony_ci			}
18368c2ecf20Sopenharmony_ci		}
18378c2ecf20Sopenharmony_ci	} else if (v_list_itr->vsi_list_info->ref_cnt == 1) {
18388c2ecf20Sopenharmony_ci		/* Update existing VSI list to add new VSI ID only if it used
18398c2ecf20Sopenharmony_ci		 * by one VLAN rule.
18408c2ecf20Sopenharmony_ci		 */
18418c2ecf20Sopenharmony_ci		cur_fltr = &v_list_itr->fltr_info;
18428c2ecf20Sopenharmony_ci		status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr,
18438c2ecf20Sopenharmony_ci						 new_fltr);
18448c2ecf20Sopenharmony_ci	} else {
18458c2ecf20Sopenharmony_ci		/* If VLAN rule exists and VSI list being used by this rule is
18468c2ecf20Sopenharmony_ci		 * referenced by more than 1 VLAN rule. Then create a new VSI
18478c2ecf20Sopenharmony_ci		 * list appending previous VSI with new VSI and update existing
18488c2ecf20Sopenharmony_ci		 * VLAN rule to point to new VSI list ID
18498c2ecf20Sopenharmony_ci		 */
18508c2ecf20Sopenharmony_ci		struct ice_fltr_info tmp_fltr;
18518c2ecf20Sopenharmony_ci		u16 vsi_handle_arr[2];
18528c2ecf20Sopenharmony_ci		u16 cur_handle;
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci		/* Current implementation only supports reusing VSI list with
18558c2ecf20Sopenharmony_ci		 * one VSI count. We should never hit below condition
18568c2ecf20Sopenharmony_ci		 */
18578c2ecf20Sopenharmony_ci		if (v_list_itr->vsi_count > 1 &&
18588c2ecf20Sopenharmony_ci		    v_list_itr->vsi_list_info->ref_cnt > 1) {
18598c2ecf20Sopenharmony_ci			ice_debug(hw, ICE_DBG_SW,
18608c2ecf20Sopenharmony_ci				  "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n");
18618c2ecf20Sopenharmony_ci			status = ICE_ERR_CFG;
18628c2ecf20Sopenharmony_ci			goto exit;
18638c2ecf20Sopenharmony_ci		}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci		cur_handle =
18668c2ecf20Sopenharmony_ci			find_first_bit(v_list_itr->vsi_list_info->vsi_map,
18678c2ecf20Sopenharmony_ci				       ICE_MAX_VSI);
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci		/* A rule already exists with the new VSI being added */
18708c2ecf20Sopenharmony_ci		if (cur_handle == vsi_handle) {
18718c2ecf20Sopenharmony_ci			status = ICE_ERR_ALREADY_EXISTS;
18728c2ecf20Sopenharmony_ci			goto exit;
18738c2ecf20Sopenharmony_ci		}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci		vsi_handle_arr[0] = cur_handle;
18768c2ecf20Sopenharmony_ci		vsi_handle_arr[1] = vsi_handle;
18778c2ecf20Sopenharmony_ci		status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
18788c2ecf20Sopenharmony_ci						  &vsi_list_id, lkup_type);
18798c2ecf20Sopenharmony_ci		if (status)
18808c2ecf20Sopenharmony_ci			goto exit;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci		tmp_fltr = v_list_itr->fltr_info;
18838c2ecf20Sopenharmony_ci		tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id;
18848c2ecf20Sopenharmony_ci		tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
18858c2ecf20Sopenharmony_ci		tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
18868c2ecf20Sopenharmony_ci		/* Update the previous switch rule to a new VSI list which
18878c2ecf20Sopenharmony_ci		 * includes current VSI that is requested
18888c2ecf20Sopenharmony_ci		 */
18898c2ecf20Sopenharmony_ci		status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
18908c2ecf20Sopenharmony_ci		if (status)
18918c2ecf20Sopenharmony_ci			goto exit;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci		/* before overriding VSI list map info. decrement ref_cnt of
18948c2ecf20Sopenharmony_ci		 * previous VSI list
18958c2ecf20Sopenharmony_ci		 */
18968c2ecf20Sopenharmony_ci		v_list_itr->vsi_list_info->ref_cnt--;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci		/* now update to newly created list */
18998c2ecf20Sopenharmony_ci		v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id;
19008c2ecf20Sopenharmony_ci		v_list_itr->vsi_list_info =
19018c2ecf20Sopenharmony_ci			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
19028c2ecf20Sopenharmony_ci						vsi_list_id);
19038c2ecf20Sopenharmony_ci		v_list_itr->vsi_count++;
19048c2ecf20Sopenharmony_ci	}
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ciexit:
19078c2ecf20Sopenharmony_ci	mutex_unlock(rule_lock);
19088c2ecf20Sopenharmony_ci	return status;
19098c2ecf20Sopenharmony_ci}
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci/**
19128c2ecf20Sopenharmony_ci * ice_add_vlan - Add VLAN based filter rule
19138c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
19148c2ecf20Sopenharmony_ci * @v_list: list of VLAN entries and forwarding information
19158c2ecf20Sopenharmony_ci */
19168c2ecf20Sopenharmony_cienum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
19178c2ecf20Sopenharmony_ci{
19188c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *v_list_itr;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	if (!v_list || !hw)
19218c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	list_for_each_entry(v_list_itr, v_list, list_entry) {
19248c2ecf20Sopenharmony_ci		if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)
19258c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
19268c2ecf20Sopenharmony_ci		v_list_itr->fltr_info.flag = ICE_FLTR_TX;
19278c2ecf20Sopenharmony_ci		v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr);
19288c2ecf20Sopenharmony_ci		if (v_list_itr->status)
19298c2ecf20Sopenharmony_ci			return v_list_itr->status;
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci	return 0;
19328c2ecf20Sopenharmony_ci}
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci/**
19358c2ecf20Sopenharmony_ci * ice_add_eth_mac - Add ethertype and MAC based filter rule
19368c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
19378c2ecf20Sopenharmony_ci * @em_list: list of ether type MAC filter, MAC is optional
19388c2ecf20Sopenharmony_ci *
19398c2ecf20Sopenharmony_ci * This function requires the caller to populate the entries in
19408c2ecf20Sopenharmony_ci * the filter list with the necessary fields (including flags to
19418c2ecf20Sopenharmony_ci * indicate Tx or Rx rules).
19428c2ecf20Sopenharmony_ci */
19438c2ecf20Sopenharmony_cienum ice_status
19448c2ecf20Sopenharmony_ciice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list)
19458c2ecf20Sopenharmony_ci{
19468c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *em_list_itr;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	if (!em_list || !hw)
19498c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci	list_for_each_entry(em_list_itr, em_list, list_entry) {
19528c2ecf20Sopenharmony_ci		enum ice_sw_lkup_type l_type =
19538c2ecf20Sopenharmony_ci			em_list_itr->fltr_info.lkup_type;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
19568c2ecf20Sopenharmony_ci		    l_type != ICE_SW_LKUP_ETHERTYPE)
19578c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci		em_list_itr->status = ice_add_rule_internal(hw, l_type,
19608c2ecf20Sopenharmony_ci							    em_list_itr);
19618c2ecf20Sopenharmony_ci		if (em_list_itr->status)
19628c2ecf20Sopenharmony_ci			return em_list_itr->status;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci	return 0;
19658c2ecf20Sopenharmony_ci}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci/**
19688c2ecf20Sopenharmony_ci * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule
19698c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
19708c2ecf20Sopenharmony_ci * @em_list: list of ethertype or ethertype MAC entries
19718c2ecf20Sopenharmony_ci */
19728c2ecf20Sopenharmony_cienum ice_status
19738c2ecf20Sopenharmony_ciice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *em_list_itr, *tmp;
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci	if (!em_list || !hw)
19788c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) {
19818c2ecf20Sopenharmony_ci		enum ice_sw_lkup_type l_type =
19828c2ecf20Sopenharmony_ci			em_list_itr->fltr_info.lkup_type;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci		if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
19858c2ecf20Sopenharmony_ci		    l_type != ICE_SW_LKUP_ETHERTYPE)
19868c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci		em_list_itr->status = ice_remove_rule_internal(hw, l_type,
19898c2ecf20Sopenharmony_ci							       em_list_itr);
19908c2ecf20Sopenharmony_ci		if (em_list_itr->status)
19918c2ecf20Sopenharmony_ci			return em_list_itr->status;
19928c2ecf20Sopenharmony_ci	}
19938c2ecf20Sopenharmony_ci	return 0;
19948c2ecf20Sopenharmony_ci}
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci/**
19978c2ecf20Sopenharmony_ci * ice_rem_sw_rule_info
19988c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
19998c2ecf20Sopenharmony_ci * @rule_head: pointer to the switch list structure that we want to delete
20008c2ecf20Sopenharmony_ci */
20018c2ecf20Sopenharmony_cistatic void
20028c2ecf20Sopenharmony_ciice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head)
20038c2ecf20Sopenharmony_ci{
20048c2ecf20Sopenharmony_ci	if (!list_empty(rule_head)) {
20058c2ecf20Sopenharmony_ci		struct ice_fltr_mgmt_list_entry *entry;
20068c2ecf20Sopenharmony_ci		struct ice_fltr_mgmt_list_entry *tmp;
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci		list_for_each_entry_safe(entry, tmp, rule_head, list_entry) {
20098c2ecf20Sopenharmony_ci			list_del(&entry->list_entry);
20108c2ecf20Sopenharmony_ci			devm_kfree(ice_hw_to_dev(hw), entry);
20118c2ecf20Sopenharmony_ci		}
20128c2ecf20Sopenharmony_ci	}
20138c2ecf20Sopenharmony_ci}
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci/**
20168c2ecf20Sopenharmony_ci * ice_cfg_dflt_vsi - change state of VSI to set/clear default
20178c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
20188c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to set as default
20198c2ecf20Sopenharmony_ci * @set: true to add the above mentioned switch rule, false to remove it
20208c2ecf20Sopenharmony_ci * @direction: ICE_FLTR_RX or ICE_FLTR_TX
20218c2ecf20Sopenharmony_ci *
20228c2ecf20Sopenharmony_ci * add filter rule to set/unset given VSI as default VSI for the switch
20238c2ecf20Sopenharmony_ci * (represented by swid)
20248c2ecf20Sopenharmony_ci */
20258c2ecf20Sopenharmony_cienum ice_status
20268c2ecf20Sopenharmony_ciice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction)
20278c2ecf20Sopenharmony_ci{
20288c2ecf20Sopenharmony_ci	struct ice_aqc_sw_rules_elem *s_rule;
20298c2ecf20Sopenharmony_ci	struct ice_fltr_info f_info;
20308c2ecf20Sopenharmony_ci	enum ice_adminq_opc opcode;
20318c2ecf20Sopenharmony_ci	enum ice_status status;
20328c2ecf20Sopenharmony_ci	u16 s_rule_size;
20338c2ecf20Sopenharmony_ci	u16 hw_vsi_id;
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
20368c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
20378c2ecf20Sopenharmony_ci	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE :
20408c2ecf20Sopenharmony_ci		ICE_SW_RULE_RX_TX_NO_HDR_SIZE;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
20438c2ecf20Sopenharmony_ci	if (!s_rule)
20448c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	memset(&f_info, 0, sizeof(f_info));
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	f_info.lkup_type = ICE_SW_LKUP_DFLT;
20498c2ecf20Sopenharmony_ci	f_info.flag = direction;
20508c2ecf20Sopenharmony_ci	f_info.fltr_act = ICE_FWD_TO_VSI;
20518c2ecf20Sopenharmony_ci	f_info.fwd_id.hw_vsi_id = hw_vsi_id;
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	if (f_info.flag & ICE_FLTR_RX) {
20548c2ecf20Sopenharmony_ci		f_info.src = hw->port_info->lport;
20558c2ecf20Sopenharmony_ci		f_info.src_id = ICE_SRC_ID_LPORT;
20568c2ecf20Sopenharmony_ci		if (!set)
20578c2ecf20Sopenharmony_ci			f_info.fltr_rule_id =
20588c2ecf20Sopenharmony_ci				hw->port_info->dflt_rx_vsi_rule_id;
20598c2ecf20Sopenharmony_ci	} else if (f_info.flag & ICE_FLTR_TX) {
20608c2ecf20Sopenharmony_ci		f_info.src_id = ICE_SRC_ID_VSI;
20618c2ecf20Sopenharmony_ci		f_info.src = hw_vsi_id;
20628c2ecf20Sopenharmony_ci		if (!set)
20638c2ecf20Sopenharmony_ci			f_info.fltr_rule_id =
20648c2ecf20Sopenharmony_ci				hw->port_info->dflt_tx_vsi_rule_id;
20658c2ecf20Sopenharmony_ci	}
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	if (set)
20688c2ecf20Sopenharmony_ci		opcode = ice_aqc_opc_add_sw_rules;
20698c2ecf20Sopenharmony_ci	else
20708c2ecf20Sopenharmony_ci		opcode = ice_aqc_opc_remove_sw_rules;
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	ice_fill_sw_rule(hw, &f_info, s_rule, opcode);
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opcode, NULL);
20758c2ecf20Sopenharmony_ci	if (status || !(f_info.flag & ICE_FLTR_TX_RX))
20768c2ecf20Sopenharmony_ci		goto out;
20778c2ecf20Sopenharmony_ci	if (set) {
20788c2ecf20Sopenharmony_ci		u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci		if (f_info.flag & ICE_FLTR_TX) {
20818c2ecf20Sopenharmony_ci			hw->port_info->dflt_tx_vsi_num = hw_vsi_id;
20828c2ecf20Sopenharmony_ci			hw->port_info->dflt_tx_vsi_rule_id = index;
20838c2ecf20Sopenharmony_ci		} else if (f_info.flag & ICE_FLTR_RX) {
20848c2ecf20Sopenharmony_ci			hw->port_info->dflt_rx_vsi_num = hw_vsi_id;
20858c2ecf20Sopenharmony_ci			hw->port_info->dflt_rx_vsi_rule_id = index;
20868c2ecf20Sopenharmony_ci		}
20878c2ecf20Sopenharmony_ci	} else {
20888c2ecf20Sopenharmony_ci		if (f_info.flag & ICE_FLTR_TX) {
20898c2ecf20Sopenharmony_ci			hw->port_info->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;
20908c2ecf20Sopenharmony_ci			hw->port_info->dflt_tx_vsi_rule_id = ICE_INVAL_ACT;
20918c2ecf20Sopenharmony_ci		} else if (f_info.flag & ICE_FLTR_RX) {
20928c2ecf20Sopenharmony_ci			hw->port_info->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;
20938c2ecf20Sopenharmony_ci			hw->port_info->dflt_rx_vsi_rule_id = ICE_INVAL_ACT;
20948c2ecf20Sopenharmony_ci		}
20958c2ecf20Sopenharmony_ci	}
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ciout:
20988c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), s_rule);
20998c2ecf20Sopenharmony_ci	return status;
21008c2ecf20Sopenharmony_ci}
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci/**
21038c2ecf20Sopenharmony_ci * ice_find_ucast_rule_entry - Search for a unicast MAC filter rule entry
21048c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
21058c2ecf20Sopenharmony_ci * @recp_id: lookup type for which the specified rule needs to be searched
21068c2ecf20Sopenharmony_ci * @f_info: rule information
21078c2ecf20Sopenharmony_ci *
21088c2ecf20Sopenharmony_ci * Helper function to search for a unicast rule entry - this is to be used
21098c2ecf20Sopenharmony_ci * to remove unicast MAC filter that is not shared with other VSIs on the
21108c2ecf20Sopenharmony_ci * PF switch.
21118c2ecf20Sopenharmony_ci *
21128c2ecf20Sopenharmony_ci * Returns pointer to entry storing the rule if found
21138c2ecf20Sopenharmony_ci */
21148c2ecf20Sopenharmony_cistatic struct ice_fltr_mgmt_list_entry *
21158c2ecf20Sopenharmony_ciice_find_ucast_rule_entry(struct ice_hw *hw, u8 recp_id,
21168c2ecf20Sopenharmony_ci			  struct ice_fltr_info *f_info)
21178c2ecf20Sopenharmony_ci{
21188c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
21198c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *list_itr;
21208c2ecf20Sopenharmony_ci	struct list_head *list_head;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	list_head = &sw->recp_list[recp_id].filt_rules;
21238c2ecf20Sopenharmony_ci	list_for_each_entry(list_itr, list_head, list_entry) {
21248c2ecf20Sopenharmony_ci		if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
21258c2ecf20Sopenharmony_ci			    sizeof(f_info->l_data)) &&
21268c2ecf20Sopenharmony_ci		    f_info->fwd_id.hw_vsi_id ==
21278c2ecf20Sopenharmony_ci		    list_itr->fltr_info.fwd_id.hw_vsi_id &&
21288c2ecf20Sopenharmony_ci		    f_info->flag == list_itr->fltr_info.flag)
21298c2ecf20Sopenharmony_ci			return list_itr;
21308c2ecf20Sopenharmony_ci	}
21318c2ecf20Sopenharmony_ci	return NULL;
21328c2ecf20Sopenharmony_ci}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci/**
21358c2ecf20Sopenharmony_ci * ice_remove_mac - remove a MAC address based filter rule
21368c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
21378c2ecf20Sopenharmony_ci * @m_list: list of MAC addresses and forwarding information
21388c2ecf20Sopenharmony_ci *
21398c2ecf20Sopenharmony_ci * This function removes either a MAC filter rule or a specific VSI from a
21408c2ecf20Sopenharmony_ci * VSI list for a multicast MAC address.
21418c2ecf20Sopenharmony_ci *
21428c2ecf20Sopenharmony_ci * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by
21438c2ecf20Sopenharmony_ci * ice_add_mac. Caller should be aware that this call will only work if all
21448c2ecf20Sopenharmony_ci * the entries passed into m_list were added previously. It will not attempt to
21458c2ecf20Sopenharmony_ci * do a partial remove of entries that were found.
21468c2ecf20Sopenharmony_ci */
21478c2ecf20Sopenharmony_cienum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
21488c2ecf20Sopenharmony_ci{
21498c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *list_itr, *tmp;
21508c2ecf20Sopenharmony_ci	struct mutex *rule_lock; /* Lock to protect filter rule list */
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	if (!m_list)
21538c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	rule_lock = &hw->switch_info->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
21568c2ecf20Sopenharmony_ci	list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) {
21578c2ecf20Sopenharmony_ci		enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;
21588c2ecf20Sopenharmony_ci		u8 *add = &list_itr->fltr_info.l_data.mac.mac_addr[0];
21598c2ecf20Sopenharmony_ci		u16 vsi_handle;
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci		if (l_type != ICE_SW_LKUP_MAC)
21628c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci		vsi_handle = list_itr->fltr_info.vsi_handle;
21658c2ecf20Sopenharmony_ci		if (!ice_is_vsi_valid(hw, vsi_handle))
21668c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci		list_itr->fltr_info.fwd_id.hw_vsi_id =
21698c2ecf20Sopenharmony_ci					ice_get_hw_vsi_num(hw, vsi_handle);
21708c2ecf20Sopenharmony_ci		if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
21718c2ecf20Sopenharmony_ci			/* Don't remove the unicast address that belongs to
21728c2ecf20Sopenharmony_ci			 * another VSI on the switch, since it is not being
21738c2ecf20Sopenharmony_ci			 * shared...
21748c2ecf20Sopenharmony_ci			 */
21758c2ecf20Sopenharmony_ci			mutex_lock(rule_lock);
21768c2ecf20Sopenharmony_ci			if (!ice_find_ucast_rule_entry(hw, ICE_SW_LKUP_MAC,
21778c2ecf20Sopenharmony_ci						       &list_itr->fltr_info)) {
21788c2ecf20Sopenharmony_ci				mutex_unlock(rule_lock);
21798c2ecf20Sopenharmony_ci				return ICE_ERR_DOES_NOT_EXIST;
21808c2ecf20Sopenharmony_ci			}
21818c2ecf20Sopenharmony_ci			mutex_unlock(rule_lock);
21828c2ecf20Sopenharmony_ci		}
21838c2ecf20Sopenharmony_ci		list_itr->status = ice_remove_rule_internal(hw,
21848c2ecf20Sopenharmony_ci							    ICE_SW_LKUP_MAC,
21858c2ecf20Sopenharmony_ci							    list_itr);
21868c2ecf20Sopenharmony_ci		if (list_itr->status)
21878c2ecf20Sopenharmony_ci			return list_itr->status;
21888c2ecf20Sopenharmony_ci	}
21898c2ecf20Sopenharmony_ci	return 0;
21908c2ecf20Sopenharmony_ci}
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci/**
21938c2ecf20Sopenharmony_ci * ice_remove_vlan - Remove VLAN based filter rule
21948c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
21958c2ecf20Sopenharmony_ci * @v_list: list of VLAN entries and forwarding information
21968c2ecf20Sopenharmony_ci */
21978c2ecf20Sopenharmony_cienum ice_status
21988c2ecf20Sopenharmony_ciice_remove_vlan(struct ice_hw *hw, struct list_head *v_list)
21998c2ecf20Sopenharmony_ci{
22008c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *v_list_itr, *tmp;
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	if (!v_list || !hw)
22038c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
22068c2ecf20Sopenharmony_ci		enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci		if (l_type != ICE_SW_LKUP_VLAN)
22098c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
22108c2ecf20Sopenharmony_ci		v_list_itr->status = ice_remove_rule_internal(hw,
22118c2ecf20Sopenharmony_ci							      ICE_SW_LKUP_VLAN,
22128c2ecf20Sopenharmony_ci							      v_list_itr);
22138c2ecf20Sopenharmony_ci		if (v_list_itr->status)
22148c2ecf20Sopenharmony_ci			return v_list_itr->status;
22158c2ecf20Sopenharmony_ci	}
22168c2ecf20Sopenharmony_ci	return 0;
22178c2ecf20Sopenharmony_ci}
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci/**
22208c2ecf20Sopenharmony_ci * ice_vsi_uses_fltr - Determine if given VSI uses specified filter
22218c2ecf20Sopenharmony_ci * @fm_entry: filter entry to inspect
22228c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to compare with filter info
22238c2ecf20Sopenharmony_ci */
22248c2ecf20Sopenharmony_cistatic bool
22258c2ecf20Sopenharmony_ciice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle)
22268c2ecf20Sopenharmony_ci{
22278c2ecf20Sopenharmony_ci	return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&
22288c2ecf20Sopenharmony_ci		 fm_entry->fltr_info.vsi_handle == vsi_handle) ||
22298c2ecf20Sopenharmony_ci		(fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&
22308c2ecf20Sopenharmony_ci		 fm_entry->vsi_list_info &&
22318c2ecf20Sopenharmony_ci		 (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map))));
22328c2ecf20Sopenharmony_ci}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci/**
22358c2ecf20Sopenharmony_ci * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list
22368c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
22378c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
22388c2ecf20Sopenharmony_ci * @vsi_list_head: pointer to the list to add entry to
22398c2ecf20Sopenharmony_ci * @fi: pointer to fltr_info of filter entry to copy & add
22408c2ecf20Sopenharmony_ci *
22418c2ecf20Sopenharmony_ci * Helper function, used when creating a list of filters to remove from
22428c2ecf20Sopenharmony_ci * a specific VSI. The entry added to vsi_list_head is a COPY of the
22438c2ecf20Sopenharmony_ci * original filter entry, with the exception of fltr_info.fltr_act and
22448c2ecf20Sopenharmony_ci * fltr_info.fwd_id fields. These are set such that later logic can
22458c2ecf20Sopenharmony_ci * extract which VSI to remove the fltr from, and pass on that information.
22468c2ecf20Sopenharmony_ci */
22478c2ecf20Sopenharmony_cistatic enum ice_status
22488c2ecf20Sopenharmony_ciice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
22498c2ecf20Sopenharmony_ci			       struct list_head *vsi_list_head,
22508c2ecf20Sopenharmony_ci			       struct ice_fltr_info *fi)
22518c2ecf20Sopenharmony_ci{
22528c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *tmp;
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	/* this memory is freed up in the caller function
22558c2ecf20Sopenharmony_ci	 * once filters for this VSI are removed
22568c2ecf20Sopenharmony_ci	 */
22578c2ecf20Sopenharmony_ci	tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL);
22588c2ecf20Sopenharmony_ci	if (!tmp)
22598c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	tmp->fltr_info = *fi;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	/* Overwrite these fields to indicate which VSI to remove filter from,
22648c2ecf20Sopenharmony_ci	 * so find and remove logic can extract the information from the
22658c2ecf20Sopenharmony_ci	 * list entries. Note that original entries will still have proper
22668c2ecf20Sopenharmony_ci	 * values.
22678c2ecf20Sopenharmony_ci	 */
22688c2ecf20Sopenharmony_ci	tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
22698c2ecf20Sopenharmony_ci	tmp->fltr_info.vsi_handle = vsi_handle;
22708c2ecf20Sopenharmony_ci	tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci	list_add(&tmp->list_entry, vsi_list_head);
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci	return 0;
22758c2ecf20Sopenharmony_ci}
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci/**
22788c2ecf20Sopenharmony_ci * ice_add_to_vsi_fltr_list - Add VSI filters to the list
22798c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
22808c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
22818c2ecf20Sopenharmony_ci * @lkup_list_head: pointer to the list that has certain lookup type filters
22828c2ecf20Sopenharmony_ci * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle
22838c2ecf20Sopenharmony_ci *
22848c2ecf20Sopenharmony_ci * Locates all filters in lkup_list_head that are used by the given VSI,
22858c2ecf20Sopenharmony_ci * and adds COPIES of those entries to vsi_list_head (intended to be used
22868c2ecf20Sopenharmony_ci * to remove the listed filters).
22878c2ecf20Sopenharmony_ci * Note that this means all entries in vsi_list_head must be explicitly
22888c2ecf20Sopenharmony_ci * deallocated by the caller when done with list.
22898c2ecf20Sopenharmony_ci */
22908c2ecf20Sopenharmony_cistatic enum ice_status
22918c2ecf20Sopenharmony_ciice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
22928c2ecf20Sopenharmony_ci			 struct list_head *lkup_list_head,
22938c2ecf20Sopenharmony_ci			 struct list_head *vsi_list_head)
22948c2ecf20Sopenharmony_ci{
22958c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *fm_entry;
22968c2ecf20Sopenharmony_ci	enum ice_status status = 0;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	/* check to make sure VSI ID is valid and within boundary */
22998c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
23008c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	list_for_each_entry(fm_entry, lkup_list_head, list_entry) {
23038c2ecf20Sopenharmony_ci		if (!ice_vsi_uses_fltr(fm_entry, vsi_handle))
23048c2ecf20Sopenharmony_ci			continue;
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
23078c2ecf20Sopenharmony_ci							vsi_list_head,
23088c2ecf20Sopenharmony_ci							&fm_entry->fltr_info);
23098c2ecf20Sopenharmony_ci		if (status)
23108c2ecf20Sopenharmony_ci			return status;
23118c2ecf20Sopenharmony_ci	}
23128c2ecf20Sopenharmony_ci	return status;
23138c2ecf20Sopenharmony_ci}
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci/**
23168c2ecf20Sopenharmony_ci * ice_determine_promisc_mask
23178c2ecf20Sopenharmony_ci * @fi: filter info to parse
23188c2ecf20Sopenharmony_ci *
23198c2ecf20Sopenharmony_ci * Helper function to determine which ICE_PROMISC_ mask corresponds
23208c2ecf20Sopenharmony_ci * to given filter into.
23218c2ecf20Sopenharmony_ci */
23228c2ecf20Sopenharmony_cistatic u8 ice_determine_promisc_mask(struct ice_fltr_info *fi)
23238c2ecf20Sopenharmony_ci{
23248c2ecf20Sopenharmony_ci	u16 vid = fi->l_data.mac_vlan.vlan_id;
23258c2ecf20Sopenharmony_ci	u8 *macaddr = fi->l_data.mac.mac_addr;
23268c2ecf20Sopenharmony_ci	bool is_tx_fltr = false;
23278c2ecf20Sopenharmony_ci	u8 promisc_mask = 0;
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci	if (fi->flag == ICE_FLTR_TX)
23308c2ecf20Sopenharmony_ci		is_tx_fltr = true;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	if (is_broadcast_ether_addr(macaddr))
23338c2ecf20Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
23348c2ecf20Sopenharmony_ci			ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX;
23358c2ecf20Sopenharmony_ci	else if (is_multicast_ether_addr(macaddr))
23368c2ecf20Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
23378c2ecf20Sopenharmony_ci			ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX;
23388c2ecf20Sopenharmony_ci	else if (is_unicast_ether_addr(macaddr))
23398c2ecf20Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
23408c2ecf20Sopenharmony_ci			ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX;
23418c2ecf20Sopenharmony_ci	if (vid)
23428c2ecf20Sopenharmony_ci		promisc_mask |= is_tx_fltr ?
23438c2ecf20Sopenharmony_ci			ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	return promisc_mask;
23468c2ecf20Sopenharmony_ci}
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci/**
23498c2ecf20Sopenharmony_ci * ice_remove_promisc - Remove promisc based filter rules
23508c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
23518c2ecf20Sopenharmony_ci * @recp_id: recipe ID for which the rule needs to removed
23528c2ecf20Sopenharmony_ci * @v_list: list of promisc entries
23538c2ecf20Sopenharmony_ci */
23548c2ecf20Sopenharmony_cistatic enum ice_status
23558c2ecf20Sopenharmony_ciice_remove_promisc(struct ice_hw *hw, u8 recp_id,
23568c2ecf20Sopenharmony_ci		   struct list_head *v_list)
23578c2ecf20Sopenharmony_ci{
23588c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *v_list_itr, *tmp;
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
23618c2ecf20Sopenharmony_ci		v_list_itr->status =
23628c2ecf20Sopenharmony_ci			ice_remove_rule_internal(hw, recp_id, v_list_itr);
23638c2ecf20Sopenharmony_ci		if (v_list_itr->status)
23648c2ecf20Sopenharmony_ci			return v_list_itr->status;
23658c2ecf20Sopenharmony_ci	}
23668c2ecf20Sopenharmony_ci	return 0;
23678c2ecf20Sopenharmony_ci}
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci/**
23708c2ecf20Sopenharmony_ci * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI
23718c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
23728c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to clear mode
23738c2ecf20Sopenharmony_ci * @promisc_mask: mask of promiscuous config bits to clear
23748c2ecf20Sopenharmony_ci * @vid: VLAN ID to clear VLAN promiscuous
23758c2ecf20Sopenharmony_ci */
23768c2ecf20Sopenharmony_cienum ice_status
23778c2ecf20Sopenharmony_ciice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
23788c2ecf20Sopenharmony_ci		      u16 vid)
23798c2ecf20Sopenharmony_ci{
23808c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
23818c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *fm_entry, *tmp;
23828c2ecf20Sopenharmony_ci	struct list_head remove_list_head;
23838c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *itr;
23848c2ecf20Sopenharmony_ci	struct list_head *rule_head;
23858c2ecf20Sopenharmony_ci	struct mutex *rule_lock;	/* Lock to protect filter rule list */
23868c2ecf20Sopenharmony_ci	enum ice_status status = 0;
23878c2ecf20Sopenharmony_ci	u8 recipe_id;
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
23908c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX))
23938c2ecf20Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
23948c2ecf20Sopenharmony_ci	else
23958c2ecf20Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC;
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci	rule_head = &sw->recp_list[recipe_id].filt_rules;
23988c2ecf20Sopenharmony_ci	rule_lock = &sw->recp_list[recipe_id].filt_rule_lock;
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&remove_list_head);
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	mutex_lock(rule_lock);
24038c2ecf20Sopenharmony_ci	list_for_each_entry(itr, rule_head, list_entry) {
24048c2ecf20Sopenharmony_ci		struct ice_fltr_info *fltr_info;
24058c2ecf20Sopenharmony_ci		u8 fltr_promisc_mask = 0;
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci		if (!ice_vsi_uses_fltr(itr, vsi_handle))
24088c2ecf20Sopenharmony_ci			continue;
24098c2ecf20Sopenharmony_ci		fltr_info = &itr->fltr_info;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci		if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN &&
24128c2ecf20Sopenharmony_ci		    vid != fltr_info->l_data.mac_vlan.vlan_id)
24138c2ecf20Sopenharmony_ci			continue;
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci		fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info);
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci		/* Skip if filter is not completely specified by given mask */
24188c2ecf20Sopenharmony_ci		if (fltr_promisc_mask & ~promisc_mask)
24198c2ecf20Sopenharmony_ci			continue;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
24228c2ecf20Sopenharmony_ci							&remove_list_head,
24238c2ecf20Sopenharmony_ci							fltr_info);
24248c2ecf20Sopenharmony_ci		if (status) {
24258c2ecf20Sopenharmony_ci			mutex_unlock(rule_lock);
24268c2ecf20Sopenharmony_ci			goto free_fltr_list;
24278c2ecf20Sopenharmony_ci		}
24288c2ecf20Sopenharmony_ci	}
24298c2ecf20Sopenharmony_ci	mutex_unlock(rule_lock);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	status = ice_remove_promisc(hw, recipe_id, &remove_list_head);
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_cifree_fltr_list:
24348c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
24358c2ecf20Sopenharmony_ci		list_del(&fm_entry->list_entry);
24368c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), fm_entry);
24378c2ecf20Sopenharmony_ci	}
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	return status;
24408c2ecf20Sopenharmony_ci}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci/**
24438c2ecf20Sopenharmony_ci * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)
24448c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
24458c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to configure
24468c2ecf20Sopenharmony_ci * @promisc_mask: mask of promiscuous config bits
24478c2ecf20Sopenharmony_ci * @vid: VLAN ID to set VLAN promiscuous
24488c2ecf20Sopenharmony_ci */
24498c2ecf20Sopenharmony_cienum ice_status
24508c2ecf20Sopenharmony_ciice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid)
24518c2ecf20Sopenharmony_ci{
24528c2ecf20Sopenharmony_ci	enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR };
24538c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry f_list_entry;
24548c2ecf20Sopenharmony_ci	struct ice_fltr_info new_fltr;
24558c2ecf20Sopenharmony_ci	enum ice_status status = 0;
24568c2ecf20Sopenharmony_ci	bool is_tx_fltr;
24578c2ecf20Sopenharmony_ci	u16 hw_vsi_id;
24588c2ecf20Sopenharmony_ci	int pkt_type;
24598c2ecf20Sopenharmony_ci	u8 recipe_id;
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
24628c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
24638c2ecf20Sopenharmony_ci	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	memset(&new_fltr, 0, sizeof(new_fltr));
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) {
24688c2ecf20Sopenharmony_ci		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN;
24698c2ecf20Sopenharmony_ci		new_fltr.l_data.mac_vlan.vlan_id = vid;
24708c2ecf20Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
24718c2ecf20Sopenharmony_ci	} else {
24728c2ecf20Sopenharmony_ci		new_fltr.lkup_type = ICE_SW_LKUP_PROMISC;
24738c2ecf20Sopenharmony_ci		recipe_id = ICE_SW_LKUP_PROMISC;
24748c2ecf20Sopenharmony_ci	}
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	/* Separate filters must be set for each direction/packet type
24778c2ecf20Sopenharmony_ci	 * combination, so we will loop over the mask value, store the
24788c2ecf20Sopenharmony_ci	 * individual type, and clear it out in the input mask as it
24798c2ecf20Sopenharmony_ci	 * is found.
24808c2ecf20Sopenharmony_ci	 */
24818c2ecf20Sopenharmony_ci	while (promisc_mask) {
24828c2ecf20Sopenharmony_ci		u8 *mac_addr;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci		pkt_type = 0;
24858c2ecf20Sopenharmony_ci		is_tx_fltr = false;
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci		if (promisc_mask & ICE_PROMISC_UCAST_RX) {
24888c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_UCAST_RX;
24898c2ecf20Sopenharmony_ci			pkt_type = UCAST_FLTR;
24908c2ecf20Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_UCAST_TX) {
24918c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_UCAST_TX;
24928c2ecf20Sopenharmony_ci			pkt_type = UCAST_FLTR;
24938c2ecf20Sopenharmony_ci			is_tx_fltr = true;
24948c2ecf20Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_MCAST_RX) {
24958c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_MCAST_RX;
24968c2ecf20Sopenharmony_ci			pkt_type = MCAST_FLTR;
24978c2ecf20Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_MCAST_TX) {
24988c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_MCAST_TX;
24998c2ecf20Sopenharmony_ci			pkt_type = MCAST_FLTR;
25008c2ecf20Sopenharmony_ci			is_tx_fltr = true;
25018c2ecf20Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_BCAST_RX) {
25028c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_BCAST_RX;
25038c2ecf20Sopenharmony_ci			pkt_type = BCAST_FLTR;
25048c2ecf20Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_BCAST_TX) {
25058c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_BCAST_TX;
25068c2ecf20Sopenharmony_ci			pkt_type = BCAST_FLTR;
25078c2ecf20Sopenharmony_ci			is_tx_fltr = true;
25088c2ecf20Sopenharmony_ci		}
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci		/* Check for VLAN promiscuous flag */
25118c2ecf20Sopenharmony_ci		if (promisc_mask & ICE_PROMISC_VLAN_RX) {
25128c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_VLAN_RX;
25138c2ecf20Sopenharmony_ci		} else if (promisc_mask & ICE_PROMISC_VLAN_TX) {
25148c2ecf20Sopenharmony_ci			promisc_mask &= ~ICE_PROMISC_VLAN_TX;
25158c2ecf20Sopenharmony_ci			is_tx_fltr = true;
25168c2ecf20Sopenharmony_ci		}
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci		/* Set filter DA based on packet type */
25198c2ecf20Sopenharmony_ci		mac_addr = new_fltr.l_data.mac.mac_addr;
25208c2ecf20Sopenharmony_ci		if (pkt_type == BCAST_FLTR) {
25218c2ecf20Sopenharmony_ci			eth_broadcast_addr(mac_addr);
25228c2ecf20Sopenharmony_ci		} else if (pkt_type == MCAST_FLTR ||
25238c2ecf20Sopenharmony_ci			   pkt_type == UCAST_FLTR) {
25248c2ecf20Sopenharmony_ci			/* Use the dummy ether header DA */
25258c2ecf20Sopenharmony_ci			ether_addr_copy(mac_addr, dummy_eth_header);
25268c2ecf20Sopenharmony_ci			if (pkt_type == MCAST_FLTR)
25278c2ecf20Sopenharmony_ci				mac_addr[0] |= 0x1;	/* Set multicast bit */
25288c2ecf20Sopenharmony_ci		}
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci		/* Need to reset this to zero for all iterations */
25318c2ecf20Sopenharmony_ci		new_fltr.flag = 0;
25328c2ecf20Sopenharmony_ci		if (is_tx_fltr) {
25338c2ecf20Sopenharmony_ci			new_fltr.flag |= ICE_FLTR_TX;
25348c2ecf20Sopenharmony_ci			new_fltr.src = hw_vsi_id;
25358c2ecf20Sopenharmony_ci		} else {
25368c2ecf20Sopenharmony_ci			new_fltr.flag |= ICE_FLTR_RX;
25378c2ecf20Sopenharmony_ci			new_fltr.src = hw->port_info->lport;
25388c2ecf20Sopenharmony_ci		}
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci		new_fltr.fltr_act = ICE_FWD_TO_VSI;
25418c2ecf20Sopenharmony_ci		new_fltr.vsi_handle = vsi_handle;
25428c2ecf20Sopenharmony_ci		new_fltr.fwd_id.hw_vsi_id = hw_vsi_id;
25438c2ecf20Sopenharmony_ci		f_list_entry.fltr_info = new_fltr;
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci		status = ice_add_rule_internal(hw, recipe_id, &f_list_entry);
25468c2ecf20Sopenharmony_ci		if (status)
25478c2ecf20Sopenharmony_ci			goto set_promisc_exit;
25488c2ecf20Sopenharmony_ci	}
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ciset_promisc_exit:
25518c2ecf20Sopenharmony_ci	return status;
25528c2ecf20Sopenharmony_ci}
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci/**
25558c2ecf20Sopenharmony_ci * ice_set_vlan_vsi_promisc
25568c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
25578c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to configure
25588c2ecf20Sopenharmony_ci * @promisc_mask: mask of promiscuous config bits
25598c2ecf20Sopenharmony_ci * @rm_vlan_promisc: Clear VLANs VSI promisc mode
25608c2ecf20Sopenharmony_ci *
25618c2ecf20Sopenharmony_ci * Configure VSI with all associated VLANs to given promiscuous mode(s)
25628c2ecf20Sopenharmony_ci */
25638c2ecf20Sopenharmony_cienum ice_status
25648c2ecf20Sopenharmony_ciice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
25658c2ecf20Sopenharmony_ci			 bool rm_vlan_promisc)
25668c2ecf20Sopenharmony_ci{
25678c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
25688c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *list_itr, *tmp;
25698c2ecf20Sopenharmony_ci	struct list_head vsi_list_head;
25708c2ecf20Sopenharmony_ci	struct list_head *vlan_head;
25718c2ecf20Sopenharmony_ci	struct mutex *vlan_lock; /* Lock to protect filter rule list */
25728c2ecf20Sopenharmony_ci	enum ice_status status;
25738c2ecf20Sopenharmony_ci	u16 vlan_id;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vsi_list_head);
25768c2ecf20Sopenharmony_ci	vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
25778c2ecf20Sopenharmony_ci	vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
25788c2ecf20Sopenharmony_ci	mutex_lock(vlan_lock);
25798c2ecf20Sopenharmony_ci	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head,
25808c2ecf20Sopenharmony_ci					  &vsi_list_head);
25818c2ecf20Sopenharmony_ci	mutex_unlock(vlan_lock);
25828c2ecf20Sopenharmony_ci	if (status)
25838c2ecf20Sopenharmony_ci		goto free_fltr_list;
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	list_for_each_entry(list_itr, &vsi_list_head, list_entry) {
25868c2ecf20Sopenharmony_ci		vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
25878c2ecf20Sopenharmony_ci		if (rm_vlan_promisc)
25888c2ecf20Sopenharmony_ci			status = ice_clear_vsi_promisc(hw, vsi_handle,
25898c2ecf20Sopenharmony_ci						       promisc_mask, vlan_id);
25908c2ecf20Sopenharmony_ci		else
25918c2ecf20Sopenharmony_ci			status = ice_set_vsi_promisc(hw, vsi_handle,
25928c2ecf20Sopenharmony_ci						     promisc_mask, vlan_id);
25938c2ecf20Sopenharmony_ci		if (status && status != -EEXIST)
25948c2ecf20Sopenharmony_ci			break;
25958c2ecf20Sopenharmony_ci	}
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_cifree_fltr_list:
25988c2ecf20Sopenharmony_ci	list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) {
25998c2ecf20Sopenharmony_ci		list_del(&list_itr->list_entry);
26008c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), list_itr);
26018c2ecf20Sopenharmony_ci	}
26028c2ecf20Sopenharmony_ci	return status;
26038c2ecf20Sopenharmony_ci}
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci/**
26068c2ecf20Sopenharmony_ci * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI
26078c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
26088c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
26098c2ecf20Sopenharmony_ci * @lkup: switch rule filter lookup type
26108c2ecf20Sopenharmony_ci */
26118c2ecf20Sopenharmony_cistatic void
26128c2ecf20Sopenharmony_ciice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,
26138c2ecf20Sopenharmony_ci			 enum ice_sw_lkup_type lkup)
26148c2ecf20Sopenharmony_ci{
26158c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
26168c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *fm_entry;
26178c2ecf20Sopenharmony_ci	struct list_head remove_list_head;
26188c2ecf20Sopenharmony_ci	struct list_head *rule_head;
26198c2ecf20Sopenharmony_ci	struct ice_fltr_list_entry *tmp;
26208c2ecf20Sopenharmony_ci	struct mutex *rule_lock;	/* Lock to protect filter rule list */
26218c2ecf20Sopenharmony_ci	enum ice_status status;
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&remove_list_head);
26248c2ecf20Sopenharmony_ci	rule_lock = &sw->recp_list[lkup].filt_rule_lock;
26258c2ecf20Sopenharmony_ci	rule_head = &sw->recp_list[lkup].filt_rules;
26268c2ecf20Sopenharmony_ci	mutex_lock(rule_lock);
26278c2ecf20Sopenharmony_ci	status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head,
26288c2ecf20Sopenharmony_ci					  &remove_list_head);
26298c2ecf20Sopenharmony_ci	mutex_unlock(rule_lock);
26308c2ecf20Sopenharmony_ci	if (status)
26318c2ecf20Sopenharmony_ci		goto free_fltr_list;
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	switch (lkup) {
26348c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_MAC:
26358c2ecf20Sopenharmony_ci		ice_remove_mac(hw, &remove_list_head);
26368c2ecf20Sopenharmony_ci		break;
26378c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_VLAN:
26388c2ecf20Sopenharmony_ci		ice_remove_vlan(hw, &remove_list_head);
26398c2ecf20Sopenharmony_ci		break;
26408c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_PROMISC:
26418c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_PROMISC_VLAN:
26428c2ecf20Sopenharmony_ci		ice_remove_promisc(hw, lkup, &remove_list_head);
26438c2ecf20Sopenharmony_ci		break;
26448c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_MAC_VLAN:
26458c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE:
26468c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_ETHERTYPE_MAC:
26478c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_DFLT:
26488c2ecf20Sopenharmony_ci	case ICE_SW_LKUP_LAST:
26498c2ecf20Sopenharmony_ci	default:
26508c2ecf20Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup);
26518c2ecf20Sopenharmony_ci		break;
26528c2ecf20Sopenharmony_ci	}
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_cifree_fltr_list:
26558c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
26568c2ecf20Sopenharmony_ci		list_del(&fm_entry->list_entry);
26578c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), fm_entry);
26588c2ecf20Sopenharmony_ci	}
26598c2ecf20Sopenharmony_ci}
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_ci/**
26628c2ecf20Sopenharmony_ci * ice_remove_vsi_fltr - Remove all filters for a VSI
26638c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
26648c2ecf20Sopenharmony_ci * @vsi_handle: VSI handle to remove filters from
26658c2ecf20Sopenharmony_ci */
26668c2ecf20Sopenharmony_civoid ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)
26678c2ecf20Sopenharmony_ci{
26688c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC);
26698c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN);
26708c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC);
26718c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN);
26728c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT);
26738c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE);
26748c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC);
26758c2ecf20Sopenharmony_ci	ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN);
26768c2ecf20Sopenharmony_ci}
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci/**
26798c2ecf20Sopenharmony_ci * ice_alloc_res_cntr - allocating resource counter
26808c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
26818c2ecf20Sopenharmony_ci * @type: type of resource
26828c2ecf20Sopenharmony_ci * @alloc_shared: if set it is shared else dedicated
26838c2ecf20Sopenharmony_ci * @num_items: number of entries requested for FD resource type
26848c2ecf20Sopenharmony_ci * @counter_id: counter index returned by AQ call
26858c2ecf20Sopenharmony_ci */
26868c2ecf20Sopenharmony_cienum ice_status
26878c2ecf20Sopenharmony_ciice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
26888c2ecf20Sopenharmony_ci		   u16 *counter_id)
26898c2ecf20Sopenharmony_ci{
26908c2ecf20Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *buf;
26918c2ecf20Sopenharmony_ci	enum ice_status status;
26928c2ecf20Sopenharmony_ci	u16 buf_len;
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	/* Allocate resource */
26958c2ecf20Sopenharmony_ci	buf_len = struct_size(buf, elem, 1);
26968c2ecf20Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
26978c2ecf20Sopenharmony_ci	if (!buf)
26988c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci	buf->num_elems = cpu_to_le16(num_items);
27018c2ecf20Sopenharmony_ci	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
27028c2ecf20Sopenharmony_ci				      ICE_AQC_RES_TYPE_M) | alloc_shared);
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
27058c2ecf20Sopenharmony_ci				       ice_aqc_opc_alloc_res, NULL);
27068c2ecf20Sopenharmony_ci	if (status)
27078c2ecf20Sopenharmony_ci		goto exit;
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	*counter_id = le16_to_cpu(buf->elem[0].e.sw_resp);
27108c2ecf20Sopenharmony_ci
27118c2ecf20Sopenharmony_ciexit:
27128c2ecf20Sopenharmony_ci	kfree(buf);
27138c2ecf20Sopenharmony_ci	return status;
27148c2ecf20Sopenharmony_ci}
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci/**
27178c2ecf20Sopenharmony_ci * ice_free_res_cntr - free resource counter
27188c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
27198c2ecf20Sopenharmony_ci * @type: type of resource
27208c2ecf20Sopenharmony_ci * @alloc_shared: if set it is shared else dedicated
27218c2ecf20Sopenharmony_ci * @num_items: number of entries to be freed for FD resource type
27228c2ecf20Sopenharmony_ci * @counter_id: counter ID resource which needs to be freed
27238c2ecf20Sopenharmony_ci */
27248c2ecf20Sopenharmony_cienum ice_status
27258c2ecf20Sopenharmony_ciice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
27268c2ecf20Sopenharmony_ci		  u16 counter_id)
27278c2ecf20Sopenharmony_ci{
27288c2ecf20Sopenharmony_ci	struct ice_aqc_alloc_free_res_elem *buf;
27298c2ecf20Sopenharmony_ci	enum ice_status status;
27308c2ecf20Sopenharmony_ci	u16 buf_len;
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci	/* Free resource */
27338c2ecf20Sopenharmony_ci	buf_len = struct_size(buf, elem, 1);
27348c2ecf20Sopenharmony_ci	buf = kzalloc(buf_len, GFP_KERNEL);
27358c2ecf20Sopenharmony_ci	if (!buf)
27368c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	buf->num_elems = cpu_to_le16(num_items);
27398c2ecf20Sopenharmony_ci	buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
27408c2ecf20Sopenharmony_ci				      ICE_AQC_RES_TYPE_M) | alloc_shared);
27418c2ecf20Sopenharmony_ci	buf->elem[0].e.sw_resp = cpu_to_le16(counter_id);
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_ci	status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
27448c2ecf20Sopenharmony_ci				       ice_aqc_opc_free_res, NULL);
27458c2ecf20Sopenharmony_ci	if (status)
27468c2ecf20Sopenharmony_ci		ice_debug(hw, ICE_DBG_SW,
27478c2ecf20Sopenharmony_ci			  "counter resource could not be freed\n");
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	kfree(buf);
27508c2ecf20Sopenharmony_ci	return status;
27518c2ecf20Sopenharmony_ci}
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci/**
27548c2ecf20Sopenharmony_ci * ice_replay_vsi_fltr - Replay filters for requested VSI
27558c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
27568c2ecf20Sopenharmony_ci * @vsi_handle: driver VSI handle
27578c2ecf20Sopenharmony_ci * @recp_id: Recipe ID for which rules need to be replayed
27588c2ecf20Sopenharmony_ci * @list_head: list for which filters need to be replayed
27598c2ecf20Sopenharmony_ci *
27608c2ecf20Sopenharmony_ci * Replays the filter of recipe recp_id for a VSI represented via vsi_handle.
27618c2ecf20Sopenharmony_ci * It is required to pass valid VSI handle.
27628c2ecf20Sopenharmony_ci */
27638c2ecf20Sopenharmony_cistatic enum ice_status
27648c2ecf20Sopenharmony_ciice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id,
27658c2ecf20Sopenharmony_ci		    struct list_head *list_head)
27668c2ecf20Sopenharmony_ci{
27678c2ecf20Sopenharmony_ci	struct ice_fltr_mgmt_list_entry *itr;
27688c2ecf20Sopenharmony_ci	enum ice_status status = 0;
27698c2ecf20Sopenharmony_ci	u16 hw_vsi_id;
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	if (list_empty(list_head))
27728c2ecf20Sopenharmony_ci		return status;
27738c2ecf20Sopenharmony_ci	hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	list_for_each_entry(itr, list_head, list_entry) {
27768c2ecf20Sopenharmony_ci		struct ice_fltr_list_entry f_entry;
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci		f_entry.fltr_info = itr->fltr_info;
27798c2ecf20Sopenharmony_ci		if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN &&
27808c2ecf20Sopenharmony_ci		    itr->fltr_info.vsi_handle == vsi_handle) {
27818c2ecf20Sopenharmony_ci			/* update the src in case it is VSI num */
27828c2ecf20Sopenharmony_ci			if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
27838c2ecf20Sopenharmony_ci				f_entry.fltr_info.src = hw_vsi_id;
27848c2ecf20Sopenharmony_ci			status = ice_add_rule_internal(hw, recp_id, &f_entry);
27858c2ecf20Sopenharmony_ci			if (status)
27868c2ecf20Sopenharmony_ci				goto end;
27878c2ecf20Sopenharmony_ci			continue;
27888c2ecf20Sopenharmony_ci		}
27898c2ecf20Sopenharmony_ci		if (!itr->vsi_list_info ||
27908c2ecf20Sopenharmony_ci		    !test_bit(vsi_handle, itr->vsi_list_info->vsi_map))
27918c2ecf20Sopenharmony_ci			continue;
27928c2ecf20Sopenharmony_ci		/* Clearing it so that the logic can add it back */
27938c2ecf20Sopenharmony_ci		clear_bit(vsi_handle, itr->vsi_list_info->vsi_map);
27948c2ecf20Sopenharmony_ci		f_entry.fltr_info.vsi_handle = vsi_handle;
27958c2ecf20Sopenharmony_ci		f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;
27968c2ecf20Sopenharmony_ci		/* update the src in case it is VSI num */
27978c2ecf20Sopenharmony_ci		if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
27988c2ecf20Sopenharmony_ci			f_entry.fltr_info.src = hw_vsi_id;
27998c2ecf20Sopenharmony_ci		if (recp_id == ICE_SW_LKUP_VLAN)
28008c2ecf20Sopenharmony_ci			status = ice_add_vlan_internal(hw, &f_entry);
28018c2ecf20Sopenharmony_ci		else
28028c2ecf20Sopenharmony_ci			status = ice_add_rule_internal(hw, recp_id, &f_entry);
28038c2ecf20Sopenharmony_ci		if (status)
28048c2ecf20Sopenharmony_ci			goto end;
28058c2ecf20Sopenharmony_ci	}
28068c2ecf20Sopenharmony_ciend:
28078c2ecf20Sopenharmony_ci	return status;
28088c2ecf20Sopenharmony_ci}
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci/**
28118c2ecf20Sopenharmony_ci * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists
28128c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
28138c2ecf20Sopenharmony_ci * @vsi_handle: driver VSI handle
28148c2ecf20Sopenharmony_ci *
28158c2ecf20Sopenharmony_ci * Replays filters for requested VSI via vsi_handle.
28168c2ecf20Sopenharmony_ci */
28178c2ecf20Sopenharmony_cienum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle)
28188c2ecf20Sopenharmony_ci{
28198c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
28208c2ecf20Sopenharmony_ci	enum ice_status status = 0;
28218c2ecf20Sopenharmony_ci	u8 i;
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
28248c2ecf20Sopenharmony_ci		struct list_head *head;
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci		head = &sw->recp_list[i].filt_replay_rules;
28278c2ecf20Sopenharmony_ci		status = ice_replay_vsi_fltr(hw, vsi_handle, i, head);
28288c2ecf20Sopenharmony_ci		if (status)
28298c2ecf20Sopenharmony_ci			return status;
28308c2ecf20Sopenharmony_ci	}
28318c2ecf20Sopenharmony_ci	return status;
28328c2ecf20Sopenharmony_ci}
28338c2ecf20Sopenharmony_ci
28348c2ecf20Sopenharmony_ci/**
28358c2ecf20Sopenharmony_ci * ice_rm_all_sw_replay_rule_info - deletes filter replay rules
28368c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
28378c2ecf20Sopenharmony_ci *
28388c2ecf20Sopenharmony_ci * Deletes the filter replay rules.
28398c2ecf20Sopenharmony_ci */
28408c2ecf20Sopenharmony_civoid ice_rm_all_sw_replay_rule_info(struct ice_hw *hw)
28418c2ecf20Sopenharmony_ci{
28428c2ecf20Sopenharmony_ci	struct ice_switch_info *sw = hw->switch_info;
28438c2ecf20Sopenharmony_ci	u8 i;
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci	if (!sw)
28468c2ecf20Sopenharmony_ci		return;
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
28498c2ecf20Sopenharmony_ci		if (!list_empty(&sw->recp_list[i].filt_replay_rules)) {
28508c2ecf20Sopenharmony_ci			struct list_head *l_head;
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci			l_head = &sw->recp_list[i].filt_replay_rules;
28538c2ecf20Sopenharmony_ci			ice_rem_sw_rule_info(hw, l_head);
28548c2ecf20Sopenharmony_ci		}
28558c2ecf20Sopenharmony_ci	}
28568c2ecf20Sopenharmony_ci}
2857