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