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