18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "ice.h" 58c2ecf20Sopenharmony_ci#include "ice_base.h" 68c2ecf20Sopenharmony_ci#include "ice_flow.h" 78c2ecf20Sopenharmony_ci#include "ice_lib.h" 88c2ecf20Sopenharmony_ci#include "ice_fltr.h" 98c2ecf20Sopenharmony_ci#include "ice_dcb_lib.h" 108c2ecf20Sopenharmony_ci#include "ice_devlink.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/** 138c2ecf20Sopenharmony_ci * ice_vsi_type_str - maps VSI type enum to string equivalents 148c2ecf20Sopenharmony_ci * @vsi_type: VSI type enum 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ciconst char *ice_vsi_type_str(enum ice_vsi_type vsi_type) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci switch (vsi_type) { 198c2ecf20Sopenharmony_ci case ICE_VSI_PF: 208c2ecf20Sopenharmony_ci return "ICE_VSI_PF"; 218c2ecf20Sopenharmony_ci case ICE_VSI_VF: 228c2ecf20Sopenharmony_ci return "ICE_VSI_VF"; 238c2ecf20Sopenharmony_ci case ICE_VSI_CTRL: 248c2ecf20Sopenharmony_ci return "ICE_VSI_CTRL"; 258c2ecf20Sopenharmony_ci case ICE_VSI_LB: 268c2ecf20Sopenharmony_ci return "ICE_VSI_LB"; 278c2ecf20Sopenharmony_ci default: 288c2ecf20Sopenharmony_ci return "unknown"; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/** 338c2ecf20Sopenharmony_ci * ice_vsi_ctrl_all_rx_rings - Start or stop a VSI's Rx rings 348c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 358c2ecf20Sopenharmony_ci * @ena: start or stop the Rx rings 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * First enable/disable all of the Rx rings, flush any remaining writes, and 388c2ecf20Sopenharmony_ci * then verify that they have all been enabled/disabled successfully. This will 398c2ecf20Sopenharmony_ci * let all of the register writes complete when enabling/disabling the Rx rings 408c2ecf20Sopenharmony_ci * before waiting for the change in hardware to complete. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistatic int ice_vsi_ctrl_all_rx_rings(struct ice_vsi *vsi, bool ena) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int ret = 0; 458c2ecf20Sopenharmony_ci u16 i; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_rxq; i++) 488c2ecf20Sopenharmony_ci ice_vsi_ctrl_one_rx_ring(vsi, ena, i, false); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci ice_flush(&vsi->back->hw); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_rxq; i++) { 538c2ecf20Sopenharmony_ci ret = ice_vsi_wait_one_rx_ring(vsi, ena, i); 548c2ecf20Sopenharmony_ci if (ret) 558c2ecf20Sopenharmony_ci break; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/** 628c2ecf20Sopenharmony_ci * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the VSI 638c2ecf20Sopenharmony_ci * @vsi: VSI pointer 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * On error: returns error code (negative) 668c2ecf20Sopenharmony_ci * On success: returns 0 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_cistatic int ice_vsi_alloc_arrays(struct ice_vsi *vsi) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 718c2ecf20Sopenharmony_ci struct device *dev; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* allocate memory for both Tx and Rx ring pointers */ 768c2ecf20Sopenharmony_ci vsi->tx_rings = devm_kcalloc(dev, vsi->alloc_txq, 778c2ecf20Sopenharmony_ci sizeof(*vsi->tx_rings), GFP_KERNEL); 788c2ecf20Sopenharmony_ci if (!vsi->tx_rings) 798c2ecf20Sopenharmony_ci return -ENOMEM; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci vsi->rx_rings = devm_kcalloc(dev, vsi->alloc_rxq, 828c2ecf20Sopenharmony_ci sizeof(*vsi->rx_rings), GFP_KERNEL); 838c2ecf20Sopenharmony_ci if (!vsi->rx_rings) 848c2ecf20Sopenharmony_ci goto err_rings; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* txq_map needs to have enough space to track both Tx (stack) rings 878c2ecf20Sopenharmony_ci * and XDP rings; at this point vsi->num_xdp_txq might not be set, 888c2ecf20Sopenharmony_ci * so use num_possible_cpus() as we want to always provide XDP ring 898c2ecf20Sopenharmony_ci * per CPU, regardless of queue count settings from user that might 908c2ecf20Sopenharmony_ci * have come from ethtool's set_channels() callback; 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci vsi->txq_map = devm_kcalloc(dev, (vsi->alloc_txq + num_possible_cpus()), 938c2ecf20Sopenharmony_ci sizeof(*vsi->txq_map), GFP_KERNEL); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!vsi->txq_map) 968c2ecf20Sopenharmony_ci goto err_txq_map; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci vsi->rxq_map = devm_kcalloc(dev, vsi->alloc_rxq, 998c2ecf20Sopenharmony_ci sizeof(*vsi->rxq_map), GFP_KERNEL); 1008c2ecf20Sopenharmony_ci if (!vsi->rxq_map) 1018c2ecf20Sopenharmony_ci goto err_rxq_map; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* There is no need to allocate q_vectors for a loopback VSI. */ 1048c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_LB) 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* allocate memory for q_vector pointers */ 1088c2ecf20Sopenharmony_ci vsi->q_vectors = devm_kcalloc(dev, vsi->num_q_vectors, 1098c2ecf20Sopenharmony_ci sizeof(*vsi->q_vectors), GFP_KERNEL); 1108c2ecf20Sopenharmony_ci if (!vsi->q_vectors) 1118c2ecf20Sopenharmony_ci goto err_vectors; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cierr_vectors: 1168c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->rxq_map); 1178c2ecf20Sopenharmony_cierr_rxq_map: 1188c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->txq_map); 1198c2ecf20Sopenharmony_cierr_txq_map: 1208c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->rx_rings); 1218c2ecf20Sopenharmony_cierr_rings: 1228c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->tx_rings); 1238c2ecf20Sopenharmony_ci return -ENOMEM; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/** 1278c2ecf20Sopenharmony_ci * ice_vsi_set_num_desc - Set number of descriptors for queues on this VSI 1288c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cistatic void ice_vsi_set_num_desc(struct ice_vsi *vsi) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci switch (vsi->type) { 1338c2ecf20Sopenharmony_ci case ICE_VSI_PF: 1348c2ecf20Sopenharmony_ci case ICE_VSI_CTRL: 1358c2ecf20Sopenharmony_ci case ICE_VSI_LB: 1368c2ecf20Sopenharmony_ci /* a user could change the values of num_[tr]x_desc using 1378c2ecf20Sopenharmony_ci * ethtool -G so we should keep those values instead of 1388c2ecf20Sopenharmony_ci * overwriting them with the defaults. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci if (!vsi->num_rx_desc) 1418c2ecf20Sopenharmony_ci vsi->num_rx_desc = ICE_DFLT_NUM_RX_DESC; 1428c2ecf20Sopenharmony_ci if (!vsi->num_tx_desc) 1438c2ecf20Sopenharmony_ci vsi->num_tx_desc = ICE_DFLT_NUM_TX_DESC; 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci default: 1468c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(vsi->back), "Not setting number of Tx/Rx descriptors for VSI type %d\n", 1478c2ecf20Sopenharmony_ci vsi->type); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/** 1538c2ecf20Sopenharmony_ci * ice_vsi_set_num_qs - Set number of queues, descriptors and vectors for a VSI 1548c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 1558c2ecf20Sopenharmony_ci * @vf_id: ID of the VF being configured 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * Return 0 on success and a negative value on error 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_cistatic void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 1628c2ecf20Sopenharmony_ci struct ice_vf *vf = NULL; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 1658c2ecf20Sopenharmony_ci vsi->vf_id = vf_id; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci switch (vsi->type) { 1688c2ecf20Sopenharmony_ci case ICE_VSI_PF: 1698c2ecf20Sopenharmony_ci vsi->alloc_txq = min3(pf->num_lan_msix, 1708c2ecf20Sopenharmony_ci ice_get_avail_txq_count(pf), 1718c2ecf20Sopenharmony_ci (u16)num_online_cpus()); 1728c2ecf20Sopenharmony_ci if (vsi->req_txq) { 1738c2ecf20Sopenharmony_ci vsi->alloc_txq = vsi->req_txq; 1748c2ecf20Sopenharmony_ci vsi->num_txq = vsi->req_txq; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci pf->num_lan_tx = vsi->alloc_txq; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* only 1 Rx queue unless RSS is enabled */ 1808c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 1818c2ecf20Sopenharmony_ci vsi->alloc_rxq = 1; 1828c2ecf20Sopenharmony_ci } else { 1838c2ecf20Sopenharmony_ci vsi->alloc_rxq = min3(pf->num_lan_msix, 1848c2ecf20Sopenharmony_ci ice_get_avail_rxq_count(pf), 1858c2ecf20Sopenharmony_ci (u16)num_online_cpus()); 1868c2ecf20Sopenharmony_ci if (vsi->req_rxq) { 1878c2ecf20Sopenharmony_ci vsi->alloc_rxq = vsi->req_rxq; 1888c2ecf20Sopenharmony_ci vsi->num_rxq = vsi->req_rxq; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci pf->num_lan_rx = vsi->alloc_rxq; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci vsi->num_q_vectors = min_t(int, pf->num_lan_msix, 1958c2ecf20Sopenharmony_ci max_t(int, vsi->alloc_rxq, 1968c2ecf20Sopenharmony_ci vsi->alloc_txq)); 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case ICE_VSI_VF: 1998c2ecf20Sopenharmony_ci vf = &pf->vf[vsi->vf_id]; 2008c2ecf20Sopenharmony_ci if (vf->num_req_qs) 2018c2ecf20Sopenharmony_ci vf->num_vf_qs = vf->num_req_qs; 2028c2ecf20Sopenharmony_ci vsi->alloc_txq = vf->num_vf_qs; 2038c2ecf20Sopenharmony_ci vsi->alloc_rxq = vf->num_vf_qs; 2048c2ecf20Sopenharmony_ci /* pf->num_msix_per_vf includes (VF miscellaneous vector + 2058c2ecf20Sopenharmony_ci * data queue interrupts). Since vsi->num_q_vectors is number 2068c2ecf20Sopenharmony_ci * of queues vectors, subtract 1 (ICE_NONQ_VECS_VF) from the 2078c2ecf20Sopenharmony_ci * original vector count 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci vsi->num_q_vectors = pf->num_msix_per_vf - ICE_NONQ_VECS_VF; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci case ICE_VSI_CTRL: 2128c2ecf20Sopenharmony_ci vsi->alloc_txq = 1; 2138c2ecf20Sopenharmony_ci vsi->alloc_rxq = 1; 2148c2ecf20Sopenharmony_ci vsi->num_q_vectors = 1; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case ICE_VSI_LB: 2178c2ecf20Sopenharmony_ci vsi->alloc_txq = 1; 2188c2ecf20Sopenharmony_ci vsi->alloc_rxq = 1; 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci default: 2218c2ecf20Sopenharmony_ci dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi->type); 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ice_vsi_set_num_desc(vsi); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/** 2298c2ecf20Sopenharmony_ci * ice_get_free_slot - get the next non-NULL location index in array 2308c2ecf20Sopenharmony_ci * @array: array to search 2318c2ecf20Sopenharmony_ci * @size: size of the array 2328c2ecf20Sopenharmony_ci * @curr: last known occupied index to be used as a search hint 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * void * is being used to keep the functionality generic. This lets us use this 2358c2ecf20Sopenharmony_ci * function on any array of pointers. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_cistatic int ice_get_free_slot(void *array, int size, int curr) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci int **tmp_array = (int **)array; 2408c2ecf20Sopenharmony_ci int next; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (curr < (size - 1) && !tmp_array[curr + 1]) { 2438c2ecf20Sopenharmony_ci next = curr + 1; 2448c2ecf20Sopenharmony_ci } else { 2458c2ecf20Sopenharmony_ci int i = 0; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci while ((i < size) && (tmp_array[i])) 2488c2ecf20Sopenharmony_ci i++; 2498c2ecf20Sopenharmony_ci if (i == size) 2508c2ecf20Sopenharmony_ci next = ICE_NO_VSI; 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci next = i; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci return next; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/** 2588c2ecf20Sopenharmony_ci * ice_vsi_delete - delete a VSI from the switch 2598c2ecf20Sopenharmony_ci * @vsi: pointer to VSI being removed 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic void ice_vsi_delete(struct ice_vsi *vsi) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 2648c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctxt; 2658c2ecf20Sopenharmony_ci enum ice_status status; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 2688c2ecf20Sopenharmony_ci if (!ctxt) 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 2728c2ecf20Sopenharmony_ci ctxt->vf_num = vsi->vf_id; 2738c2ecf20Sopenharmony_ci ctxt->vsi_num = vsi->vsi_num; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci memcpy(&ctxt->info, &vsi->info, sizeof(ctxt->info)); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci status = ice_free_vsi(&pf->hw, vsi->idx, ctxt, false, NULL); 2788c2ecf20Sopenharmony_ci if (status) 2798c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Failed to delete VSI %i in FW - error: %s\n", 2808c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci kfree(ctxt); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/** 2868c2ecf20Sopenharmony_ci * ice_vsi_free_arrays - De-allocate queue and vector pointer arrays for the VSI 2878c2ecf20Sopenharmony_ci * @vsi: pointer to VSI being cleared 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_cistatic void ice_vsi_free_arrays(struct ice_vsi *vsi) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 2928c2ecf20Sopenharmony_ci struct device *dev; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* free the ring and vector containers */ 2978c2ecf20Sopenharmony_ci if (vsi->q_vectors) { 2988c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->q_vectors); 2998c2ecf20Sopenharmony_ci vsi->q_vectors = NULL; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci if (vsi->tx_rings) { 3028c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->tx_rings); 3038c2ecf20Sopenharmony_ci vsi->tx_rings = NULL; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci if (vsi->rx_rings) { 3068c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->rx_rings); 3078c2ecf20Sopenharmony_ci vsi->rx_rings = NULL; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci if (vsi->txq_map) { 3108c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->txq_map); 3118c2ecf20Sopenharmony_ci vsi->txq_map = NULL; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci if (vsi->rxq_map) { 3148c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->rxq_map); 3158c2ecf20Sopenharmony_ci vsi->rxq_map = NULL; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/** 3208c2ecf20Sopenharmony_ci * ice_vsi_clear - clean up and deallocate the provided VSI 3218c2ecf20Sopenharmony_ci * @vsi: pointer to VSI being cleared 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * This deallocates the VSI's queue resources, removes it from the PF's 3248c2ecf20Sopenharmony_ci * VSI array if necessary, and deallocates the VSI 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_cistatic int ice_vsi_clear(struct ice_vsi *vsi) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct ice_pf *pf = NULL; 3318c2ecf20Sopenharmony_ci struct device *dev; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (!vsi) 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (!vsi->back) 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci pf = vsi->back; 3408c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) { 3438c2ecf20Sopenharmony_ci dev_dbg(dev, "vsi does not exist at pf->vsi[%d]\n", vsi->idx); 3448c2ecf20Sopenharmony_ci return -EINVAL; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci mutex_lock(&pf->sw_mutex); 3488c2ecf20Sopenharmony_ci /* updates the PF for this cleared VSI */ 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci pf->vsi[vsi->idx] = NULL; 3518c2ecf20Sopenharmony_ci if (vsi->idx < pf->next_vsi && vsi->type != ICE_VSI_CTRL) 3528c2ecf20Sopenharmony_ci pf->next_vsi = vsi->idx; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ice_vsi_free_arrays(vsi); 3558c2ecf20Sopenharmony_ci mutex_unlock(&pf->sw_mutex); 3568c2ecf20Sopenharmony_ci devm_kfree(dev, vsi); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/** 3628c2ecf20Sopenharmony_ci * ice_msix_clean_ctrl_vsi - MSIX mode interrupt handler for ctrl VSI 3638c2ecf20Sopenharmony_ci * @irq: interrupt number 3648c2ecf20Sopenharmony_ci * @data: pointer to a q_vector 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_cistatic irqreturn_t ice_msix_clean_ctrl_vsi(int __always_unused irq, void *data) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = (struct ice_q_vector *)data; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (!q_vector->tx.ring) 3718c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci#define FDIR_RX_DESC_CLEAN_BUDGET 64 3748c2ecf20Sopenharmony_ci ice_clean_rx_irq(q_vector->rx.ring, FDIR_RX_DESC_CLEAN_BUDGET); 3758c2ecf20Sopenharmony_ci ice_clean_ctrl_tx_irq(q_vector->tx.ring); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/** 3818c2ecf20Sopenharmony_ci * ice_msix_clean_rings - MSIX mode Interrupt Handler 3828c2ecf20Sopenharmony_ci * @irq: interrupt number 3838c2ecf20Sopenharmony_ci * @data: pointer to a q_vector 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_cistatic irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = (struct ice_q_vector *)data; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (!q_vector->tx.ring && !q_vector->rx.ring) 3908c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci napi_schedule(&q_vector->napi); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * ice_vsi_alloc - Allocates the next available struct VSI in the PF 3998c2ecf20Sopenharmony_ci * @pf: board private structure 4008c2ecf20Sopenharmony_ci * @vsi_type: type of VSI 4018c2ecf20Sopenharmony_ci * @vf_id: ID of the VF being configured 4028c2ecf20Sopenharmony_ci * 4038c2ecf20Sopenharmony_ci * returns a pointer to a VSI on success, NULL on failure. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_cistatic struct ice_vsi * 4068c2ecf20Sopenharmony_ciice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 4098c2ecf20Sopenharmony_ci struct ice_vsi *vsi = NULL; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Need to protect the allocation of the VSIs at the PF level */ 4128c2ecf20Sopenharmony_ci mutex_lock(&pf->sw_mutex); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* If we have already allocated our maximum number of VSIs, 4158c2ecf20Sopenharmony_ci * pf->next_vsi will be ICE_NO_VSI. If not, pf->next_vsi index 4168c2ecf20Sopenharmony_ci * is available to be populated 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci if (pf->next_vsi == ICE_NO_VSI) { 4198c2ecf20Sopenharmony_ci dev_dbg(dev, "out of VSI slots!\n"); 4208c2ecf20Sopenharmony_ci goto unlock_pf; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci vsi = devm_kzalloc(dev, sizeof(*vsi), GFP_KERNEL); 4248c2ecf20Sopenharmony_ci if (!vsi) 4258c2ecf20Sopenharmony_ci goto unlock_pf; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci vsi->type = vsi_type; 4288c2ecf20Sopenharmony_ci vsi->back = pf; 4298c2ecf20Sopenharmony_ci set_bit(__ICE_DOWN, vsi->state); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (vsi_type == ICE_VSI_VF) 4328c2ecf20Sopenharmony_ci ice_vsi_set_num_qs(vsi, vf_id); 4338c2ecf20Sopenharmony_ci else 4348c2ecf20Sopenharmony_ci ice_vsi_set_num_qs(vsi, ICE_INVAL_VFID); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci switch (vsi->type) { 4378c2ecf20Sopenharmony_ci case ICE_VSI_PF: 4388c2ecf20Sopenharmony_ci if (ice_vsi_alloc_arrays(vsi)) 4398c2ecf20Sopenharmony_ci goto err_rings; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Setup default MSIX irq handler for VSI */ 4428c2ecf20Sopenharmony_ci vsi->irq_handler = ice_msix_clean_rings; 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci case ICE_VSI_CTRL: 4458c2ecf20Sopenharmony_ci if (ice_vsi_alloc_arrays(vsi)) 4468c2ecf20Sopenharmony_ci goto err_rings; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Setup ctrl VSI MSIX irq handler */ 4498c2ecf20Sopenharmony_ci vsi->irq_handler = ice_msix_clean_ctrl_vsi; 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci case ICE_VSI_VF: 4528c2ecf20Sopenharmony_ci if (ice_vsi_alloc_arrays(vsi)) 4538c2ecf20Sopenharmony_ci goto err_rings; 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci case ICE_VSI_LB: 4568c2ecf20Sopenharmony_ci if (ice_vsi_alloc_arrays(vsi)) 4578c2ecf20Sopenharmony_ci goto err_rings; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci default: 4608c2ecf20Sopenharmony_ci dev_warn(dev, "Unknown VSI type %d\n", vsi->type); 4618c2ecf20Sopenharmony_ci goto unlock_pf; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_CTRL) { 4658c2ecf20Sopenharmony_ci /* Use the last VSI slot as the index for the control VSI */ 4668c2ecf20Sopenharmony_ci vsi->idx = pf->num_alloc_vsi - 1; 4678c2ecf20Sopenharmony_ci pf->ctrl_vsi_idx = vsi->idx; 4688c2ecf20Sopenharmony_ci pf->vsi[vsi->idx] = vsi; 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci /* fill slot and make note of the index */ 4718c2ecf20Sopenharmony_ci vsi->idx = pf->next_vsi; 4728c2ecf20Sopenharmony_ci pf->vsi[pf->next_vsi] = vsi; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* prepare pf->next_vsi for next use */ 4758c2ecf20Sopenharmony_ci pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi, 4768c2ecf20Sopenharmony_ci pf->next_vsi); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci goto unlock_pf; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cierr_rings: 4818c2ecf20Sopenharmony_ci devm_kfree(dev, vsi); 4828c2ecf20Sopenharmony_ci vsi = NULL; 4838c2ecf20Sopenharmony_ciunlock_pf: 4848c2ecf20Sopenharmony_ci mutex_unlock(&pf->sw_mutex); 4858c2ecf20Sopenharmony_ci return vsi; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci/** 4898c2ecf20Sopenharmony_ci * ice_alloc_fd_res - Allocate FD resource for a VSI 4908c2ecf20Sopenharmony_ci * @vsi: pointer to the ice_vsi 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * This allocates the FD resources 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * Returns 0 on success, -EPERM on no-op or -EIO on failure 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_cistatic int ice_alloc_fd_res(struct ice_vsi *vsi) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 4998c2ecf20Sopenharmony_ci u32 g_val, b_val; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Flow Director filters are only allocated/assigned to the PF VSI which 5028c2ecf20Sopenharmony_ci * passes the traffic. The CTRL VSI is only used to add/delete filters 5038c2ecf20Sopenharmony_ci * so we don't allocate resources to it 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* FD filters from guaranteed pool per VSI */ 5078c2ecf20Sopenharmony_ci g_val = pf->hw.func_caps.fd_fltr_guar; 5088c2ecf20Sopenharmony_ci if (!g_val) 5098c2ecf20Sopenharmony_ci return -EPERM; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* FD filters from best effort pool */ 5128c2ecf20Sopenharmony_ci b_val = pf->hw.func_caps.fd_fltr_best_effort; 5138c2ecf20Sopenharmony_ci if (!b_val) 5148c2ecf20Sopenharmony_ci return -EPERM; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) 5178c2ecf20Sopenharmony_ci return -EPERM; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_FD_ENA, pf->flags)) 5208c2ecf20Sopenharmony_ci return -EPERM; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci vsi->num_gfltr = g_val / pf->num_alloc_vsi; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* each VSI gets same "best_effort" quota */ 5258c2ecf20Sopenharmony_ci vsi->num_bfltr = b_val; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/** 5318c2ecf20Sopenharmony_ci * ice_vsi_get_qs - Assign queues from PF to VSI 5328c2ecf20Sopenharmony_ci * @vsi: the VSI to assign queues to 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * Returns 0 on success and a negative value on error 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_cistatic int ice_vsi_get_qs(struct ice_vsi *vsi) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 5398c2ecf20Sopenharmony_ci struct ice_qs_cfg tx_qs_cfg = { 5408c2ecf20Sopenharmony_ci .qs_mutex = &pf->avail_q_mutex, 5418c2ecf20Sopenharmony_ci .pf_map = pf->avail_txqs, 5428c2ecf20Sopenharmony_ci .pf_map_size = pf->max_pf_txqs, 5438c2ecf20Sopenharmony_ci .q_count = vsi->alloc_txq, 5448c2ecf20Sopenharmony_ci .scatter_count = ICE_MAX_SCATTER_TXQS, 5458c2ecf20Sopenharmony_ci .vsi_map = vsi->txq_map, 5468c2ecf20Sopenharmony_ci .vsi_map_offset = 0, 5478c2ecf20Sopenharmony_ci .mapping_mode = ICE_VSI_MAP_CONTIG 5488c2ecf20Sopenharmony_ci }; 5498c2ecf20Sopenharmony_ci struct ice_qs_cfg rx_qs_cfg = { 5508c2ecf20Sopenharmony_ci .qs_mutex = &pf->avail_q_mutex, 5518c2ecf20Sopenharmony_ci .pf_map = pf->avail_rxqs, 5528c2ecf20Sopenharmony_ci .pf_map_size = pf->max_pf_rxqs, 5538c2ecf20Sopenharmony_ci .q_count = vsi->alloc_rxq, 5548c2ecf20Sopenharmony_ci .scatter_count = ICE_MAX_SCATTER_RXQS, 5558c2ecf20Sopenharmony_ci .vsi_map = vsi->rxq_map, 5568c2ecf20Sopenharmony_ci .vsi_map_offset = 0, 5578c2ecf20Sopenharmony_ci .mapping_mode = ICE_VSI_MAP_CONTIG 5588c2ecf20Sopenharmony_ci }; 5598c2ecf20Sopenharmony_ci int ret; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ret = __ice_vsi_get_qs(&tx_qs_cfg); 5628c2ecf20Sopenharmony_ci if (ret) 5638c2ecf20Sopenharmony_ci return ret; 5648c2ecf20Sopenharmony_ci vsi->tx_mapping_mode = tx_qs_cfg.mapping_mode; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci ret = __ice_vsi_get_qs(&rx_qs_cfg); 5678c2ecf20Sopenharmony_ci if (ret) 5688c2ecf20Sopenharmony_ci return ret; 5698c2ecf20Sopenharmony_ci vsi->rx_mapping_mode = rx_qs_cfg.mapping_mode; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci/** 5758c2ecf20Sopenharmony_ci * ice_vsi_put_qs - Release queues from VSI to PF 5768c2ecf20Sopenharmony_ci * @vsi: the VSI that is going to release queues 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistatic void ice_vsi_put_qs(struct ice_vsi *vsi) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 5818c2ecf20Sopenharmony_ci int i; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci mutex_lock(&pf->avail_q_mutex); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_txq; i++) { 5868c2ecf20Sopenharmony_ci clear_bit(vsi->txq_map[i], pf->avail_txqs); 5878c2ecf20Sopenharmony_ci vsi->txq_map[i] = ICE_INVAL_Q_INDEX; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_rxq; i++) { 5918c2ecf20Sopenharmony_ci clear_bit(vsi->rxq_map[i], pf->avail_rxqs); 5928c2ecf20Sopenharmony_ci vsi->rxq_map[i] = ICE_INVAL_Q_INDEX; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mutex_unlock(&pf->avail_q_mutex); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/** 5998c2ecf20Sopenharmony_ci * ice_is_safe_mode 6008c2ecf20Sopenharmony_ci * @pf: pointer to the PF struct 6018c2ecf20Sopenharmony_ci * 6028c2ecf20Sopenharmony_ci * returns true if driver is in safe mode, false otherwise 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_cibool ice_is_safe_mode(struct ice_pf *pf) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci return !test_bit(ICE_FLAG_ADV_FEATURES, pf->flags); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/** 6108c2ecf20Sopenharmony_ci * ice_vsi_clean_rss_flow_fld - Delete RSS configuration 6118c2ecf20Sopenharmony_ci * @vsi: the VSI being cleaned up 6128c2ecf20Sopenharmony_ci * 6138c2ecf20Sopenharmony_ci * This function deletes RSS input set for all flows that were configured 6148c2ecf20Sopenharmony_ci * for this VSI 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_cistatic void ice_vsi_clean_rss_flow_fld(struct ice_vsi *vsi) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 6198c2ecf20Sopenharmony_ci enum ice_status status; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) 6228c2ecf20Sopenharmony_ci return; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx); 6258c2ecf20Sopenharmony_ci if (status) 6268c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "ice_rem_vsi_rss_cfg failed for vsi = %d, error = %s\n", 6278c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/** 6318c2ecf20Sopenharmony_ci * ice_rss_clean - Delete RSS related VSI structures and configuration 6328c2ecf20Sopenharmony_ci * @vsi: the VSI being removed 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_cistatic void ice_rss_clean(struct ice_vsi *vsi) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 6378c2ecf20Sopenharmony_ci struct device *dev; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (vsi->rss_hkey_user) 6428c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->rss_hkey_user); 6438c2ecf20Sopenharmony_ci if (vsi->rss_lut_user) 6448c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->rss_lut_user); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ice_vsi_clean_rss_flow_fld(vsi); 6478c2ecf20Sopenharmony_ci /* remove RSS replay list */ 6488c2ecf20Sopenharmony_ci if (!ice_is_safe_mode(pf)) 6498c2ecf20Sopenharmony_ci ice_rem_vsi_rss_list(&pf->hw, vsi->idx); 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci/** 6538c2ecf20Sopenharmony_ci * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type 6548c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 6558c2ecf20Sopenharmony_ci */ 6568c2ecf20Sopenharmony_cistatic void ice_vsi_set_rss_params(struct ice_vsi *vsi) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct ice_hw_common_caps *cap; 6598c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 6628c2ecf20Sopenharmony_ci vsi->rss_size = 1; 6638c2ecf20Sopenharmony_ci return; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci cap = &pf->hw.func_caps.common_cap; 6678c2ecf20Sopenharmony_ci switch (vsi->type) { 6688c2ecf20Sopenharmony_ci case ICE_VSI_PF: 6698c2ecf20Sopenharmony_ci /* PF VSI will inherit RSS instance of PF */ 6708c2ecf20Sopenharmony_ci vsi->rss_table_size = (u16)cap->rss_table_size; 6718c2ecf20Sopenharmony_ci vsi->rss_size = min_t(u16, num_online_cpus(), 6728c2ecf20Sopenharmony_ci BIT(cap->rss_table_entry_width)); 6738c2ecf20Sopenharmony_ci vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF; 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci case ICE_VSI_VF: 6768c2ecf20Sopenharmony_ci /* VF VSI will get a small RSS table. 6778c2ecf20Sopenharmony_ci * For VSI_LUT, LUT size should be set to 64 bytes. 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_ci vsi->rss_table_size = ICE_VSIQF_HLUT_ARRAY_SIZE; 6808c2ecf20Sopenharmony_ci vsi->rss_size = ICE_MAX_RSS_QS_PER_VF; 6818c2ecf20Sopenharmony_ci vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI; 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci case ICE_VSI_LB: 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci default: 6868c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Unsupported VSI type %s\n", 6878c2ecf20Sopenharmony_ci ice_vsi_type_str(vsi->type)); 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/** 6938c2ecf20Sopenharmony_ci * ice_set_dflt_vsi_ctx - Set default VSI context before adding a VSI 6948c2ecf20Sopenharmony_ci * @ctxt: the VSI context being set 6958c2ecf20Sopenharmony_ci * 6968c2ecf20Sopenharmony_ci * This initializes a default VSI context for all sections except the Queues. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_cistatic void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci u32 table = 0; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci memset(&ctxt->info, 0, sizeof(ctxt->info)); 7038c2ecf20Sopenharmony_ci /* VSI's should be allocated from shared pool */ 7048c2ecf20Sopenharmony_ci ctxt->alloc_from_pool = true; 7058c2ecf20Sopenharmony_ci /* Src pruning enabled by default */ 7068c2ecf20Sopenharmony_ci ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; 7078c2ecf20Sopenharmony_ci /* Traffic from VSI can be sent to LAN */ 7088c2ecf20Sopenharmony_ci ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; 7098c2ecf20Sopenharmony_ci /* By default bits 3 and 4 in vlan_flags are 0's which results in legacy 7108c2ecf20Sopenharmony_ci * behavior (show VLAN, DEI, and UP) in descriptor. Also, allow all 7118c2ecf20Sopenharmony_ci * packets untagged/tagged. 7128c2ecf20Sopenharmony_ci */ 7138c2ecf20Sopenharmony_ci ctxt->info.vlan_flags = ((ICE_AQ_VSI_VLAN_MODE_ALL & 7148c2ecf20Sopenharmony_ci ICE_AQ_VSI_VLAN_MODE_M) >> 7158c2ecf20Sopenharmony_ci ICE_AQ_VSI_VLAN_MODE_S); 7168c2ecf20Sopenharmony_ci /* Have 1:1 UP mapping for both ingress/egress tables */ 7178c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(0, 0); 7188c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(1, 1); 7198c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(2, 2); 7208c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(3, 3); 7218c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(4, 4); 7228c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(5, 5); 7238c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(6, 6); 7248c2ecf20Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(7, 7); 7258c2ecf20Sopenharmony_ci ctxt->info.ingress_table = cpu_to_le32(table); 7268c2ecf20Sopenharmony_ci ctxt->info.egress_table = cpu_to_le32(table); 7278c2ecf20Sopenharmony_ci /* Have 1:1 UP mapping for outer to inner UP table */ 7288c2ecf20Sopenharmony_ci ctxt->info.outer_up_table = cpu_to_le32(table); 7298c2ecf20Sopenharmony_ci /* No Outer tag support outer_tag_flags remains to zero */ 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/** 7338c2ecf20Sopenharmony_ci * ice_vsi_setup_q_map - Setup a VSI queue map 7348c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 7358c2ecf20Sopenharmony_ci * @ctxt: VSI context structure 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_cistatic void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci u16 offset = 0, qmap = 0, tx_count = 0; 7408c2ecf20Sopenharmony_ci u16 qcount_tx = vsi->alloc_txq; 7418c2ecf20Sopenharmony_ci u16 qcount_rx = vsi->alloc_rxq; 7428c2ecf20Sopenharmony_ci u16 tx_numq_tc, rx_numq_tc; 7438c2ecf20Sopenharmony_ci u16 pow = 0, max_rss = 0; 7448c2ecf20Sopenharmony_ci bool ena_tc0 = false; 7458c2ecf20Sopenharmony_ci u8 netdev_tc = 0; 7468c2ecf20Sopenharmony_ci int i; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* at least TC0 should be enabled by default */ 7498c2ecf20Sopenharmony_ci if (vsi->tc_cfg.numtc) { 7508c2ecf20Sopenharmony_ci if (!(vsi->tc_cfg.ena_tc & BIT(0))) 7518c2ecf20Sopenharmony_ci ena_tc0 = true; 7528c2ecf20Sopenharmony_ci } else { 7538c2ecf20Sopenharmony_ci ena_tc0 = true; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (ena_tc0) { 7578c2ecf20Sopenharmony_ci vsi->tc_cfg.numtc++; 7588c2ecf20Sopenharmony_ci vsi->tc_cfg.ena_tc |= 1; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci rx_numq_tc = qcount_rx / vsi->tc_cfg.numtc; 7628c2ecf20Sopenharmony_ci if (!rx_numq_tc) 7638c2ecf20Sopenharmony_ci rx_numq_tc = 1; 7648c2ecf20Sopenharmony_ci tx_numq_tc = qcount_tx / vsi->tc_cfg.numtc; 7658c2ecf20Sopenharmony_ci if (!tx_numq_tc) 7668c2ecf20Sopenharmony_ci tx_numq_tc = 1; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* TC mapping is a function of the number of Rx queues assigned to the 7698c2ecf20Sopenharmony_ci * VSI for each traffic class and the offset of these queues. 7708c2ecf20Sopenharmony_ci * The first 10 bits are for queue offset for TC0, next 4 bits for no:of 7718c2ecf20Sopenharmony_ci * queues allocated to TC0. No:of queues is a power-of-2. 7728c2ecf20Sopenharmony_ci * 7738c2ecf20Sopenharmony_ci * If TC is not enabled, the queue offset is set to 0, and allocate one 7748c2ecf20Sopenharmony_ci * queue, this way, traffic for the given TC will be sent to the default 7758c2ecf20Sopenharmony_ci * queue. 7768c2ecf20Sopenharmony_ci * 7778c2ecf20Sopenharmony_ci * Setup number and offset of Rx queues for all TCs for the VSI 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci qcount_rx = rx_numq_tc; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* qcount will change if RSS is enabled */ 7838c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) { 7848c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF) { 7858c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) 7868c2ecf20Sopenharmony_ci max_rss = ICE_MAX_LG_RSS_QS; 7878c2ecf20Sopenharmony_ci else 7888c2ecf20Sopenharmony_ci max_rss = ICE_MAX_RSS_QS_PER_VF; 7898c2ecf20Sopenharmony_ci qcount_rx = min_t(u16, rx_numq_tc, max_rss); 7908c2ecf20Sopenharmony_ci if (!vsi->req_rxq) 7918c2ecf20Sopenharmony_ci qcount_rx = min_t(u16, qcount_rx, 7928c2ecf20Sopenharmony_ci vsi->rss_size); 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* find the (rounded up) power-of-2 of qcount */ 7978c2ecf20Sopenharmony_ci pow = (u16)order_base_2(qcount_rx); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci ice_for_each_traffic_class(i) { 8008c2ecf20Sopenharmony_ci if (!(vsi->tc_cfg.ena_tc & BIT(i))) { 8018c2ecf20Sopenharmony_ci /* TC is not enabled */ 8028c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].qoffset = 0; 8038c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_rx = 1; 8048c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_tx = 1; 8058c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].netdev_tc = 0; 8068c2ecf20Sopenharmony_ci ctxt->info.tc_mapping[i] = 0; 8078c2ecf20Sopenharmony_ci continue; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* TC is enabled */ 8118c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].qoffset = offset; 8128c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_rx = qcount_rx; 8138c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_tx = tx_numq_tc; 8148c2ecf20Sopenharmony_ci vsi->tc_cfg.tc_info[i].netdev_tc = netdev_tc++; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) & 8178c2ecf20Sopenharmony_ci ICE_AQ_VSI_TC_Q_OFFSET_M) | 8188c2ecf20Sopenharmony_ci ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & 8198c2ecf20Sopenharmony_ci ICE_AQ_VSI_TC_Q_NUM_M); 8208c2ecf20Sopenharmony_ci offset += qcount_rx; 8218c2ecf20Sopenharmony_ci tx_count += tx_numq_tc; 8228c2ecf20Sopenharmony_ci ctxt->info.tc_mapping[i] = cpu_to_le16(qmap); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* if offset is non-zero, means it is calculated correctly based on 8268c2ecf20Sopenharmony_ci * enabled TCs for a given VSI otherwise qcount_rx will always 8278c2ecf20Sopenharmony_ci * be correct and non-zero because it is based off - VSI's 8288c2ecf20Sopenharmony_ci * allocated Rx queues which is at least 1 (hence qcount_tx will be 8298c2ecf20Sopenharmony_ci * at least 1) 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci if (offset) 8328c2ecf20Sopenharmony_ci vsi->num_rxq = offset; 8338c2ecf20Sopenharmony_ci else 8348c2ecf20Sopenharmony_ci vsi->num_rxq = qcount_rx; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci vsi->num_txq = tx_count; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF && vsi->num_txq != vsi->num_rxq) { 8398c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(vsi->back), "VF VSI should have same number of Tx and Rx queues. Hence making them equal\n"); 8408c2ecf20Sopenharmony_ci /* since there is a chance that num_rxq could have been changed 8418c2ecf20Sopenharmony_ci * in the above for loop, make num_txq equal to num_rxq. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci vsi->num_txq = vsi->num_rxq; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* Rx queue mapping */ 8478c2ecf20Sopenharmony_ci ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG); 8488c2ecf20Sopenharmony_ci /* q_mapping buffer holds the info for the first queue allocated for 8498c2ecf20Sopenharmony_ci * this VSI in the PF space and also the number of queues associated 8508c2ecf20Sopenharmony_ci * with this VSI. 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_ci ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]); 8538c2ecf20Sopenharmony_ci ctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/** 8578c2ecf20Sopenharmony_ci * ice_set_fd_vsi_ctx - Set FD VSI context before adding a VSI 8588c2ecf20Sopenharmony_ci * @ctxt: the VSI context being set 8598c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_cistatic void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci u8 dflt_q_group, dflt_q_prio; 8648c2ecf20Sopenharmony_ci u16 dflt_q, report_q, val; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_CTRL) 8678c2ecf20Sopenharmony_ci return; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci val = ICE_AQ_VSI_PROP_FLOW_DIR_VALID; 8708c2ecf20Sopenharmony_ci ctxt->info.valid_sections |= cpu_to_le16(val); 8718c2ecf20Sopenharmony_ci dflt_q = 0; 8728c2ecf20Sopenharmony_ci dflt_q_group = 0; 8738c2ecf20Sopenharmony_ci report_q = 0; 8748c2ecf20Sopenharmony_ci dflt_q_prio = 0; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* enable flow director filtering/programming */ 8778c2ecf20Sopenharmony_ci val = ICE_AQ_VSI_FD_ENABLE | ICE_AQ_VSI_FD_PROG_ENABLE; 8788c2ecf20Sopenharmony_ci ctxt->info.fd_options = cpu_to_le16(val); 8798c2ecf20Sopenharmony_ci /* max of allocated flow director filters */ 8808c2ecf20Sopenharmony_ci ctxt->info.max_fd_fltr_dedicated = 8818c2ecf20Sopenharmony_ci cpu_to_le16(vsi->num_gfltr); 8828c2ecf20Sopenharmony_ci /* max of shared flow director filters any VSI may program */ 8838c2ecf20Sopenharmony_ci ctxt->info.max_fd_fltr_shared = 8848c2ecf20Sopenharmony_ci cpu_to_le16(vsi->num_bfltr); 8858c2ecf20Sopenharmony_ci /* default queue index within the VSI of the default FD */ 8868c2ecf20Sopenharmony_ci val = ((dflt_q << ICE_AQ_VSI_FD_DEF_Q_S) & 8878c2ecf20Sopenharmony_ci ICE_AQ_VSI_FD_DEF_Q_M); 8888c2ecf20Sopenharmony_ci /* target queue or queue group to the FD filter */ 8898c2ecf20Sopenharmony_ci val |= ((dflt_q_group << ICE_AQ_VSI_FD_DEF_GRP_S) & 8908c2ecf20Sopenharmony_ci ICE_AQ_VSI_FD_DEF_GRP_M); 8918c2ecf20Sopenharmony_ci ctxt->info.fd_def_q = cpu_to_le16(val); 8928c2ecf20Sopenharmony_ci /* queue index on which FD filter completion is reported */ 8938c2ecf20Sopenharmony_ci val = ((report_q << ICE_AQ_VSI_FD_REPORT_Q_S) & 8948c2ecf20Sopenharmony_ci ICE_AQ_VSI_FD_REPORT_Q_M); 8958c2ecf20Sopenharmony_ci /* priority of the default qindex action */ 8968c2ecf20Sopenharmony_ci val |= ((dflt_q_prio << ICE_AQ_VSI_FD_DEF_PRIORITY_S) & 8978c2ecf20Sopenharmony_ci ICE_AQ_VSI_FD_DEF_PRIORITY_M); 8988c2ecf20Sopenharmony_ci ctxt->info.fd_report_opt = cpu_to_le16(val); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci/** 9028c2ecf20Sopenharmony_ci * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI 9038c2ecf20Sopenharmony_ci * @ctxt: the VSI context being set 9048c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 9058c2ecf20Sopenharmony_ci */ 9068c2ecf20Sopenharmony_cistatic void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci u8 lut_type, hash_type; 9098c2ecf20Sopenharmony_ci struct device *dev; 9108c2ecf20Sopenharmony_ci struct ice_pf *pf; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci pf = vsi->back; 9138c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci switch (vsi->type) { 9168c2ecf20Sopenharmony_ci case ICE_VSI_PF: 9178c2ecf20Sopenharmony_ci /* PF VSI will inherit RSS instance of PF */ 9188c2ecf20Sopenharmony_ci lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF; 9198c2ecf20Sopenharmony_ci hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; 9208c2ecf20Sopenharmony_ci break; 9218c2ecf20Sopenharmony_ci case ICE_VSI_VF: 9228c2ecf20Sopenharmony_ci /* VF VSI will gets a small RSS table which is a VSI LUT type */ 9238c2ecf20Sopenharmony_ci lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI; 9248c2ecf20Sopenharmony_ci hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci default: 9278c2ecf20Sopenharmony_ci dev_dbg(dev, "Unsupported VSI type %s\n", 9288c2ecf20Sopenharmony_ci ice_vsi_type_str(vsi->type)); 9298c2ecf20Sopenharmony_ci return; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) & 9338c2ecf20Sopenharmony_ci ICE_AQ_VSI_Q_OPT_RSS_LUT_M) | 9348c2ecf20Sopenharmony_ci (hash_type & ICE_AQ_VSI_Q_OPT_RSS_HASH_M); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci/** 9388c2ecf20Sopenharmony_ci * ice_vsi_init - Create and initialize a VSI 9398c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 9408c2ecf20Sopenharmony_ci * @init_vsi: is this call creating a VSI 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * This initializes a VSI context depending on the VSI type to be added and 9438c2ecf20Sopenharmony_ci * passes it down to the add_vsi aq command to create a new VSI. 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_cistatic int ice_vsi_init(struct ice_vsi *vsi, bool init_vsi) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 9488c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 9498c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctxt; 9508c2ecf20Sopenharmony_ci struct device *dev; 9518c2ecf20Sopenharmony_ci int ret = 0; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 9548c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 9558c2ecf20Sopenharmony_ci if (!ctxt) 9568c2ecf20Sopenharmony_ci return -ENOMEM; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci switch (vsi->type) { 9598c2ecf20Sopenharmony_ci case ICE_VSI_CTRL: 9608c2ecf20Sopenharmony_ci case ICE_VSI_LB: 9618c2ecf20Sopenharmony_ci case ICE_VSI_PF: 9628c2ecf20Sopenharmony_ci ctxt->flags = ICE_AQ_VSI_TYPE_PF; 9638c2ecf20Sopenharmony_ci break; 9648c2ecf20Sopenharmony_ci case ICE_VSI_VF: 9658c2ecf20Sopenharmony_ci ctxt->flags = ICE_AQ_VSI_TYPE_VF; 9668c2ecf20Sopenharmony_ci /* VF number here is the absolute VF number (0-255) */ 9678c2ecf20Sopenharmony_ci ctxt->vf_num = vsi->vf_id + hw->func_caps.vf_base_id; 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci default: 9708c2ecf20Sopenharmony_ci ret = -ENODEV; 9718c2ecf20Sopenharmony_ci goto out; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci ice_set_dflt_vsi_ctx(ctxt); 9758c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) 9768c2ecf20Sopenharmony_ci ice_set_fd_vsi_ctx(ctxt, vsi); 9778c2ecf20Sopenharmony_ci /* if the switch is in VEB mode, allow VSI loopback */ 9788c2ecf20Sopenharmony_ci if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB) 9798c2ecf20Sopenharmony_ci ctxt->info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* Set LUT type and HASH type if RSS is enabled */ 9828c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags) && 9838c2ecf20Sopenharmony_ci vsi->type != ICE_VSI_CTRL) { 9848c2ecf20Sopenharmony_ci ice_set_rss_vsi_ctx(ctxt, vsi); 9858c2ecf20Sopenharmony_ci /* if updating VSI context, make sure to set valid_section: 9868c2ecf20Sopenharmony_ci * to indicate which section of VSI context being updated 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ci if (!init_vsi) 9898c2ecf20Sopenharmony_ci ctxt->info.valid_sections |= 9908c2ecf20Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci ctxt->info.sw_id = vsi->port_info->sw_id; 9948c2ecf20Sopenharmony_ci ice_vsi_setup_q_map(vsi, ctxt); 9958c2ecf20Sopenharmony_ci if (!init_vsi) /* means VSI being updated */ 9968c2ecf20Sopenharmony_ci /* must to indicate which section of VSI context are 9978c2ecf20Sopenharmony_ci * being modified 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_ci ctxt->info.valid_sections |= 10008c2ecf20Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* enable/disable MAC and VLAN anti-spoof when spoofchk is on/off 10038c2ecf20Sopenharmony_ci * respectively 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) { 10068c2ecf20Sopenharmony_ci ctxt->info.valid_sections |= 10078c2ecf20Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); 10088c2ecf20Sopenharmony_ci if (pf->vf[vsi->vf_id].spoofchk) { 10098c2ecf20Sopenharmony_ci ctxt->info.sec_flags |= 10108c2ecf20Sopenharmony_ci ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF | 10118c2ecf20Sopenharmony_ci (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << 10128c2ecf20Sopenharmony_ci ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); 10138c2ecf20Sopenharmony_ci } else { 10148c2ecf20Sopenharmony_ci ctxt->info.sec_flags &= 10158c2ecf20Sopenharmony_ci ~(ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF | 10168c2ecf20Sopenharmony_ci (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << 10178c2ecf20Sopenharmony_ci ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S)); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* Allow control frames out of main VSI */ 10228c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 10238c2ecf20Sopenharmony_ci ctxt->info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD; 10248c2ecf20Sopenharmony_ci ctxt->info.valid_sections |= 10258c2ecf20Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (init_vsi) { 10298c2ecf20Sopenharmony_ci ret = ice_add_vsi(hw, vsi->idx, ctxt, NULL); 10308c2ecf20Sopenharmony_ci if (ret) { 10318c2ecf20Sopenharmony_ci dev_err(dev, "Add VSI failed, err %d\n", ret); 10328c2ecf20Sopenharmony_ci ret = -EIO; 10338c2ecf20Sopenharmony_ci goto out; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci } else { 10368c2ecf20Sopenharmony_ci ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL); 10378c2ecf20Sopenharmony_ci if (ret) { 10388c2ecf20Sopenharmony_ci dev_err(dev, "Update VSI failed, err %d\n", ret); 10398c2ecf20Sopenharmony_ci ret = -EIO; 10408c2ecf20Sopenharmony_ci goto out; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* keep context for update VSI operations */ 10458c2ecf20Sopenharmony_ci vsi->info = ctxt->info; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* record VSI number returned */ 10488c2ecf20Sopenharmony_ci vsi->vsi_num = ctxt->vsi_num; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ciout: 10518c2ecf20Sopenharmony_ci kfree(ctxt); 10528c2ecf20Sopenharmony_ci return ret; 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci/** 10568c2ecf20Sopenharmony_ci * ice_free_res - free a block of resources 10578c2ecf20Sopenharmony_ci * @res: pointer to the resource 10588c2ecf20Sopenharmony_ci * @index: starting index previously returned by ice_get_res 10598c2ecf20Sopenharmony_ci * @id: identifier to track owner 10608c2ecf20Sopenharmony_ci * 10618c2ecf20Sopenharmony_ci * Returns number of resources freed 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ciint ice_free_res(struct ice_res_tracker *res, u16 index, u16 id) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci int count = 0; 10668c2ecf20Sopenharmony_ci int i; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (!res || index >= res->end) 10698c2ecf20Sopenharmony_ci return -EINVAL; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci id |= ICE_RES_VALID_BIT; 10728c2ecf20Sopenharmony_ci for (i = index; i < res->end && res->list[i] == id; i++) { 10738c2ecf20Sopenharmony_ci res->list[i] = 0; 10748c2ecf20Sopenharmony_ci count++; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return count; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci/** 10818c2ecf20Sopenharmony_ci * ice_search_res - Search the tracker for a block of resources 10828c2ecf20Sopenharmony_ci * @res: pointer to the resource 10838c2ecf20Sopenharmony_ci * @needed: size of the block needed 10848c2ecf20Sopenharmony_ci * @id: identifier to track owner 10858c2ecf20Sopenharmony_ci * 10868c2ecf20Sopenharmony_ci * Returns the base item index of the block, or -ENOMEM for error 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_cistatic int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci u16 start = 0, end = 0; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (needed > res->end) 10938c2ecf20Sopenharmony_ci return -ENOMEM; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci id |= ICE_RES_VALID_BIT; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci do { 10988c2ecf20Sopenharmony_ci /* skip already allocated entries */ 10998c2ecf20Sopenharmony_ci if (res->list[end++] & ICE_RES_VALID_BIT) { 11008c2ecf20Sopenharmony_ci start = end; 11018c2ecf20Sopenharmony_ci if ((start + needed) > res->end) 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (end == (start + needed)) { 11068c2ecf20Sopenharmony_ci int i = start; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* there was enough, so assign it to the requestor */ 11098c2ecf20Sopenharmony_ci while (i != end) 11108c2ecf20Sopenharmony_ci res->list[i++] = id; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return start; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci } while (end < res->end); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci return -ENOMEM; 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci/** 11208c2ecf20Sopenharmony_ci * ice_get_free_res_count - Get free count from a resource tracker 11218c2ecf20Sopenharmony_ci * @res: Resource tracker instance 11228c2ecf20Sopenharmony_ci */ 11238c2ecf20Sopenharmony_cistatic u16 ice_get_free_res_count(struct ice_res_tracker *res) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci u16 i, count = 0; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci for (i = 0; i < res->end; i++) 11288c2ecf20Sopenharmony_ci if (!(res->list[i] & ICE_RES_VALID_BIT)) 11298c2ecf20Sopenharmony_ci count++; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return count; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci/** 11358c2ecf20Sopenharmony_ci * ice_get_res - get a block of resources 11368c2ecf20Sopenharmony_ci * @pf: board private structure 11378c2ecf20Sopenharmony_ci * @res: pointer to the resource 11388c2ecf20Sopenharmony_ci * @needed: size of the block needed 11398c2ecf20Sopenharmony_ci * @id: identifier to track owner 11408c2ecf20Sopenharmony_ci * 11418c2ecf20Sopenharmony_ci * Returns the base item index of the block, or negative for error 11428c2ecf20Sopenharmony_ci */ 11438c2ecf20Sopenharmony_ciint 11448c2ecf20Sopenharmony_ciice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci if (!res || !pf) 11478c2ecf20Sopenharmony_ci return -EINVAL; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) { 11508c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "param err: needed=%d, num_entries = %d id=0x%04x\n", 11518c2ecf20Sopenharmony_ci needed, res->num_entries, id); 11528c2ecf20Sopenharmony_ci return -EINVAL; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci return ice_search_res(res, needed, id); 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci/** 11598c2ecf20Sopenharmony_ci * ice_vsi_setup_vector_base - Set up the base vector for the given VSI 11608c2ecf20Sopenharmony_ci * @vsi: ptr to the VSI 11618c2ecf20Sopenharmony_ci * 11628c2ecf20Sopenharmony_ci * This should only be called after ice_vsi_alloc() which allocates the 11638c2ecf20Sopenharmony_ci * corresponding SW VSI structure and initializes num_queue_pairs for the 11648c2ecf20Sopenharmony_ci * newly allocated VSI. 11658c2ecf20Sopenharmony_ci * 11668c2ecf20Sopenharmony_ci * Returns 0 on success or negative on failure 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_cistatic int ice_vsi_setup_vector_base(struct ice_vsi *vsi) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 11718c2ecf20Sopenharmony_ci struct device *dev; 11728c2ecf20Sopenharmony_ci u16 num_q_vectors; 11738c2ecf20Sopenharmony_ci int base; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 11768c2ecf20Sopenharmony_ci /* SRIOV doesn't grab irq_tracker entries for each VSI */ 11778c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 11788c2ecf20Sopenharmony_ci return 0; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (vsi->base_vector) { 11818c2ecf20Sopenharmony_ci dev_dbg(dev, "VSI %d has non-zero base vector %d\n", 11828c2ecf20Sopenharmony_ci vsi->vsi_num, vsi->base_vector); 11838c2ecf20Sopenharmony_ci return -EEXIST; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci num_q_vectors = vsi->num_q_vectors; 11878c2ecf20Sopenharmony_ci /* reserve slots from OS requested IRQs */ 11888c2ecf20Sopenharmony_ci base = ice_get_res(pf, pf->irq_tracker, num_q_vectors, vsi->idx); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (base < 0) { 11918c2ecf20Sopenharmony_ci dev_err(dev, "%d MSI-X interrupts available. %s %d failed to get %d MSI-X vectors\n", 11928c2ecf20Sopenharmony_ci ice_get_free_res_count(pf->irq_tracker), 11938c2ecf20Sopenharmony_ci ice_vsi_type_str(vsi->type), vsi->idx, num_q_vectors); 11948c2ecf20Sopenharmony_ci return -ENOENT; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci vsi->base_vector = (u16)base; 11978c2ecf20Sopenharmony_ci pf->num_avail_sw_msix -= num_q_vectors; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci return 0; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci/** 12038c2ecf20Sopenharmony_ci * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI 12048c2ecf20Sopenharmony_ci * @vsi: the VSI having rings deallocated 12058c2ecf20Sopenharmony_ci */ 12068c2ecf20Sopenharmony_cistatic void ice_vsi_clear_rings(struct ice_vsi *vsi) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci int i; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* Avoid stale references by clearing map from vector to ring */ 12118c2ecf20Sopenharmony_ci if (vsi->q_vectors) { 12128c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 12138c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (q_vector) { 12168c2ecf20Sopenharmony_ci q_vector->tx.ring = NULL; 12178c2ecf20Sopenharmony_ci q_vector->rx.ring = NULL; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (vsi->tx_rings) { 12238c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_txq; i++) { 12248c2ecf20Sopenharmony_ci if (vsi->tx_rings[i]) { 12258c2ecf20Sopenharmony_ci kfree_rcu(vsi->tx_rings[i], rcu); 12268c2ecf20Sopenharmony_ci WRITE_ONCE(vsi->tx_rings[i], NULL); 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci if (vsi->rx_rings) { 12318c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_rxq; i++) { 12328c2ecf20Sopenharmony_ci if (vsi->rx_rings[i]) { 12338c2ecf20Sopenharmony_ci kfree_rcu(vsi->rx_rings[i], rcu); 12348c2ecf20Sopenharmony_ci WRITE_ONCE(vsi->rx_rings[i], NULL); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci/** 12418c2ecf20Sopenharmony_ci * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI 12428c2ecf20Sopenharmony_ci * @vsi: VSI which is having rings allocated 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_cistatic int ice_vsi_alloc_rings(struct ice_vsi *vsi) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 12478c2ecf20Sopenharmony_ci struct device *dev; 12488c2ecf20Sopenharmony_ci u16 i; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 12518c2ecf20Sopenharmony_ci /* Allocate Tx rings */ 12528c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_txq; i++) { 12538c2ecf20Sopenharmony_ci struct ice_ring *ring; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* allocate with kzalloc(), free with kfree_rcu() */ 12568c2ecf20Sopenharmony_ci ring = kzalloc(sizeof(*ring), GFP_KERNEL); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (!ring) 12598c2ecf20Sopenharmony_ci goto err_out; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci ring->q_index = i; 12628c2ecf20Sopenharmony_ci ring->reg_idx = vsi->txq_map[i]; 12638c2ecf20Sopenharmony_ci ring->ring_active = false; 12648c2ecf20Sopenharmony_ci ring->vsi = vsi; 12658c2ecf20Sopenharmony_ci ring->dev = dev; 12668c2ecf20Sopenharmony_ci ring->count = vsi->num_tx_desc; 12678c2ecf20Sopenharmony_ci ring->txq_teid = ICE_INVAL_TEID; 12688c2ecf20Sopenharmony_ci WRITE_ONCE(vsi->tx_rings[i], ring); 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* Allocate Rx rings */ 12728c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_rxq; i++) { 12738c2ecf20Sopenharmony_ci struct ice_ring *ring; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* allocate with kzalloc(), free with kfree_rcu() */ 12768c2ecf20Sopenharmony_ci ring = kzalloc(sizeof(*ring), GFP_KERNEL); 12778c2ecf20Sopenharmony_ci if (!ring) 12788c2ecf20Sopenharmony_ci goto err_out; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci ring->q_index = i; 12818c2ecf20Sopenharmony_ci ring->reg_idx = vsi->rxq_map[i]; 12828c2ecf20Sopenharmony_ci ring->ring_active = false; 12838c2ecf20Sopenharmony_ci ring->vsi = vsi; 12848c2ecf20Sopenharmony_ci ring->netdev = vsi->netdev; 12858c2ecf20Sopenharmony_ci ring->dev = dev; 12868c2ecf20Sopenharmony_ci ring->count = vsi->num_rx_desc; 12878c2ecf20Sopenharmony_ci WRITE_ONCE(vsi->rx_rings[i], ring); 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci return 0; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cierr_out: 12938c2ecf20Sopenharmony_ci ice_vsi_clear_rings(vsi); 12948c2ecf20Sopenharmony_ci return -ENOMEM; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci/** 12988c2ecf20Sopenharmony_ci * ice_vsi_manage_rss_lut - disable/enable RSS 12998c2ecf20Sopenharmony_ci * @vsi: the VSI being changed 13008c2ecf20Sopenharmony_ci * @ena: boolean value indicating if this is an enable or disable request 13018c2ecf20Sopenharmony_ci * 13028c2ecf20Sopenharmony_ci * In the event of disable request for RSS, this function will zero out RSS 13038c2ecf20Sopenharmony_ci * LUT, while in the event of enable request for RSS, it will reconfigure RSS 13048c2ecf20Sopenharmony_ci * LUT. 13058c2ecf20Sopenharmony_ci */ 13068c2ecf20Sopenharmony_ciint ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci int err = 0; 13098c2ecf20Sopenharmony_ci u8 *lut; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); 13128c2ecf20Sopenharmony_ci if (!lut) 13138c2ecf20Sopenharmony_ci return -ENOMEM; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (ena) { 13168c2ecf20Sopenharmony_ci if (vsi->rss_lut_user) 13178c2ecf20Sopenharmony_ci memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); 13188c2ecf20Sopenharmony_ci else 13198c2ecf20Sopenharmony_ci ice_fill_rss_lut(lut, vsi->rss_table_size, 13208c2ecf20Sopenharmony_ci vsi->rss_size); 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci err = ice_set_rss(vsi, NULL, lut, vsi->rss_table_size); 13248c2ecf20Sopenharmony_ci kfree(lut); 13258c2ecf20Sopenharmony_ci return err; 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci/** 13298c2ecf20Sopenharmony_ci * ice_vsi_cfg_rss_lut_key - Configure RSS params for a VSI 13308c2ecf20Sopenharmony_ci * @vsi: VSI to be configured 13318c2ecf20Sopenharmony_ci */ 13328c2ecf20Sopenharmony_cistatic int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct ice_aqc_get_set_rss_keys *key; 13358c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 13368c2ecf20Sopenharmony_ci enum ice_status status; 13378c2ecf20Sopenharmony_ci struct device *dev; 13388c2ecf20Sopenharmony_ci int err = 0; 13398c2ecf20Sopenharmony_ci u8 *lut; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 13428c2ecf20Sopenharmony_ci vsi->rss_size = min_t(u16, vsi->rss_size, vsi->num_rxq); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); 13458c2ecf20Sopenharmony_ci if (!lut) 13468c2ecf20Sopenharmony_ci return -ENOMEM; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci if (vsi->rss_lut_user) 13498c2ecf20Sopenharmony_ci memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); 13508c2ecf20Sopenharmony_ci else 13518c2ecf20Sopenharmony_ci ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci status = ice_aq_set_rss_lut(&pf->hw, vsi->idx, vsi->rss_lut_type, lut, 13548c2ecf20Sopenharmony_ci vsi->rss_table_size); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (status) { 13578c2ecf20Sopenharmony_ci dev_err(dev, "set_rss_lut failed, error %s\n", 13588c2ecf20Sopenharmony_ci ice_stat_str(status)); 13598c2ecf20Sopenharmony_ci err = -EIO; 13608c2ecf20Sopenharmony_ci goto ice_vsi_cfg_rss_exit; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci key = kzalloc(sizeof(*key), GFP_KERNEL); 13648c2ecf20Sopenharmony_ci if (!key) { 13658c2ecf20Sopenharmony_ci err = -ENOMEM; 13668c2ecf20Sopenharmony_ci goto ice_vsi_cfg_rss_exit; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (vsi->rss_hkey_user) 13708c2ecf20Sopenharmony_ci memcpy(key, 13718c2ecf20Sopenharmony_ci (struct ice_aqc_get_set_rss_keys *)vsi->rss_hkey_user, 13728c2ecf20Sopenharmony_ci ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE); 13738c2ecf20Sopenharmony_ci else 13748c2ecf20Sopenharmony_ci netdev_rss_key_fill((void *)key, 13758c2ecf20Sopenharmony_ci ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (status) { 13808c2ecf20Sopenharmony_ci dev_err(dev, "set_rss_key failed, error %s\n", 13818c2ecf20Sopenharmony_ci ice_stat_str(status)); 13828c2ecf20Sopenharmony_ci err = -EIO; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci kfree(key); 13868c2ecf20Sopenharmony_ciice_vsi_cfg_rss_exit: 13878c2ecf20Sopenharmony_ci kfree(lut); 13888c2ecf20Sopenharmony_ci return err; 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci/** 13928c2ecf20Sopenharmony_ci * ice_vsi_set_vf_rss_flow_fld - Sets VF VSI RSS input set for different flows 13938c2ecf20Sopenharmony_ci * @vsi: VSI to be configured 13948c2ecf20Sopenharmony_ci * 13958c2ecf20Sopenharmony_ci * This function will only be called during the VF VSI setup. Upon successful 13968c2ecf20Sopenharmony_ci * completion of package download, this function will configure default RSS 13978c2ecf20Sopenharmony_ci * input sets for VF VSI. 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_cistatic void ice_vsi_set_vf_rss_flow_fld(struct ice_vsi *vsi) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 14028c2ecf20Sopenharmony_ci enum ice_status status; 14038c2ecf20Sopenharmony_ci struct device *dev; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 14068c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 14078c2ecf20Sopenharmony_ci dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", 14088c2ecf20Sopenharmony_ci vsi->vsi_num); 14098c2ecf20Sopenharmony_ci return; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci status = ice_add_avf_rss_cfg(&pf->hw, vsi->idx, ICE_DEFAULT_RSS_HENA); 14138c2ecf20Sopenharmony_ci if (status) 14148c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_avf_rss_cfg failed for vsi = %d, error = %s\n", 14158c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci/** 14198c2ecf20Sopenharmony_ci * ice_vsi_set_rss_flow_fld - Sets RSS input set for different flows 14208c2ecf20Sopenharmony_ci * @vsi: VSI to be configured 14218c2ecf20Sopenharmony_ci * 14228c2ecf20Sopenharmony_ci * This function will only be called after successful download package call 14238c2ecf20Sopenharmony_ci * during initialization of PF. Since the downloaded package will erase the 14248c2ecf20Sopenharmony_ci * RSS section, this function will configure RSS input sets for different 14258c2ecf20Sopenharmony_ci * flow types. The last profile added has the highest priority, therefore 2 14268c2ecf20Sopenharmony_ci * tuple profiles (i.e. IPv4 src/dst) are added before 4 tuple profiles 14278c2ecf20Sopenharmony_ci * (i.e. IPv4 src/dst TCP src/dst port). 14288c2ecf20Sopenharmony_ci */ 14298c2ecf20Sopenharmony_cistatic void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi) 14308c2ecf20Sopenharmony_ci{ 14318c2ecf20Sopenharmony_ci u16 vsi_handle = vsi->idx, vsi_num = vsi->vsi_num; 14328c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 14338c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 14348c2ecf20Sopenharmony_ci enum ice_status status; 14358c2ecf20Sopenharmony_ci struct device *dev; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 14388c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 14398c2ecf20Sopenharmony_ci dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", 14408c2ecf20Sopenharmony_ci vsi_num); 14418c2ecf20Sopenharmony_ci return; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci /* configure RSS for IPv4 with input set IP src/dst */ 14448c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4, 14458c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_IPV4); 14468c2ecf20Sopenharmony_ci if (status) 14478c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for ipv4 flow, vsi = %d, error = %s\n", 14488c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci /* configure RSS for IPv6 with input set IPv6 src/dst */ 14518c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6, 14528c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_IPV6); 14538c2ecf20Sopenharmony_ci if (status) 14548c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for ipv6 flow, vsi = %d, error = %s\n", 14558c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci /* configure RSS for tcp4 with input set IP src/dst, TCP src/dst */ 14588c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV4, 14598c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4); 14608c2ecf20Sopenharmony_ci if (status) 14618c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for tcp4 flow, vsi = %d, error = %s\n", 14628c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci /* configure RSS for udp4 with input set IP src/dst, UDP src/dst */ 14658c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV4, 14668c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4); 14678c2ecf20Sopenharmony_ci if (status) 14688c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for udp4 flow, vsi = %d, error = %s\n", 14698c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* configure RSS for sctp4 with input set IP src/dst */ 14728c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4, 14738c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4); 14748c2ecf20Sopenharmony_ci if (status) 14758c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for sctp4 flow, vsi = %d, error = %s\n", 14768c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* configure RSS for tcp6 with input set IPv6 src/dst, TCP src/dst */ 14798c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV6, 14808c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6); 14818c2ecf20Sopenharmony_ci if (status) 14828c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for tcp6 flow, vsi = %d, error = %s\n", 14838c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci /* configure RSS for udp6 with input set IPv6 src/dst, UDP src/dst */ 14868c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV6, 14878c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6); 14888c2ecf20Sopenharmony_ci if (status) 14898c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for udp6 flow, vsi = %d, error = %s\n", 14908c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* configure RSS for sctp6 with input set IPv6 src/dst */ 14938c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6, 14948c2ecf20Sopenharmony_ci ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6); 14958c2ecf20Sopenharmony_ci if (status) 14968c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for sctp6 flow, vsi = %d, error = %s\n", 14978c2ecf20Sopenharmony_ci vsi_num, ice_stat_str(status)); 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci/** 15018c2ecf20Sopenharmony_ci * ice_pf_state_is_nominal - checks the PF for nominal state 15028c2ecf20Sopenharmony_ci * @pf: pointer to PF to check 15038c2ecf20Sopenharmony_ci * 15048c2ecf20Sopenharmony_ci * Check the PF's state for a collection of bits that would indicate 15058c2ecf20Sopenharmony_ci * the PF is in a state that would inhibit normal operation for 15068c2ecf20Sopenharmony_ci * driver functionality. 15078c2ecf20Sopenharmony_ci * 15088c2ecf20Sopenharmony_ci * Returns true if PF is in a nominal state, false otherwise 15098c2ecf20Sopenharmony_ci */ 15108c2ecf20Sopenharmony_cibool ice_pf_state_is_nominal(struct ice_pf *pf) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci DECLARE_BITMAP(check_bits, __ICE_STATE_NBITS) = { 0 }; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci if (!pf) 15158c2ecf20Sopenharmony_ci return false; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci bitmap_set(check_bits, 0, __ICE_STATE_NOMINAL_CHECK_BITS); 15188c2ecf20Sopenharmony_ci if (bitmap_intersects(pf->state, check_bits, __ICE_STATE_NBITS)) 15198c2ecf20Sopenharmony_ci return false; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci return true; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci/** 15258c2ecf20Sopenharmony_ci * ice_update_eth_stats - Update VSI-specific ethernet statistics counters 15268c2ecf20Sopenharmony_ci * @vsi: the VSI to be updated 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_civoid ice_update_eth_stats(struct ice_vsi *vsi) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci struct ice_eth_stats *prev_es, *cur_es; 15318c2ecf20Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 15328c2ecf20Sopenharmony_ci u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */ 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci prev_es = &vsi->eth_stats_prev; 15358c2ecf20Sopenharmony_ci cur_es = &vsi->eth_stats; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_GORCL(vsi_num), vsi->stat_offsets_loaded, 15388c2ecf20Sopenharmony_ci &prev_es->rx_bytes, &cur_es->rx_bytes); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_UPRCL(vsi_num), vsi->stat_offsets_loaded, 15418c2ecf20Sopenharmony_ci &prev_es->rx_unicast, &cur_es->rx_unicast); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_MPRCL(vsi_num), vsi->stat_offsets_loaded, 15448c2ecf20Sopenharmony_ci &prev_es->rx_multicast, &cur_es->rx_multicast); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_BPRCL(vsi_num), vsi->stat_offsets_loaded, 15478c2ecf20Sopenharmony_ci &prev_es->rx_broadcast, &cur_es->rx_broadcast); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLV_RDPC(vsi_num), vsi->stat_offsets_loaded, 15508c2ecf20Sopenharmony_ci &prev_es->rx_discards, &cur_es->rx_discards); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_GOTCL(vsi_num), vsi->stat_offsets_loaded, 15538c2ecf20Sopenharmony_ci &prev_es->tx_bytes, &cur_es->tx_bytes); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_UPTCL(vsi_num), vsi->stat_offsets_loaded, 15568c2ecf20Sopenharmony_ci &prev_es->tx_unicast, &cur_es->tx_unicast); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_MPTCL(vsi_num), vsi->stat_offsets_loaded, 15598c2ecf20Sopenharmony_ci &prev_es->tx_multicast, &cur_es->tx_multicast); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLV_BPTCL(vsi_num), vsi->stat_offsets_loaded, 15628c2ecf20Sopenharmony_ci &prev_es->tx_broadcast, &cur_es->tx_broadcast); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLV_TEPC(vsi_num), vsi->stat_offsets_loaded, 15658c2ecf20Sopenharmony_ci &prev_es->tx_errors, &cur_es->tx_errors); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci vsi->stat_offsets_loaded = true; 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci/** 15718c2ecf20Sopenharmony_ci * ice_vsi_add_vlan - Add VSI membership for given VLAN 15728c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 15738c2ecf20Sopenharmony_ci * @vid: VLAN ID to be added 15748c2ecf20Sopenharmony_ci * @action: filter action to be performed on match 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_ciint 15778c2ecf20Sopenharmony_ciice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid, enum ice_sw_fwd_act_type action) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 15808c2ecf20Sopenharmony_ci struct device *dev; 15818c2ecf20Sopenharmony_ci int err = 0; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (!ice_fltr_add_vlan(vsi, vid, action)) { 15868c2ecf20Sopenharmony_ci vsi->num_vlan++; 15878c2ecf20Sopenharmony_ci } else { 15888c2ecf20Sopenharmony_ci err = -ENODEV; 15898c2ecf20Sopenharmony_ci dev_err(dev, "Failure Adding VLAN %d on VSI %i\n", vid, 15908c2ecf20Sopenharmony_ci vsi->vsi_num); 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci return err; 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci/** 15978c2ecf20Sopenharmony_ci * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN 15988c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 15998c2ecf20Sopenharmony_ci * @vid: VLAN ID to be removed 16008c2ecf20Sopenharmony_ci * 16018c2ecf20Sopenharmony_ci * Returns 0 on success and negative on failure 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_ciint ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 16068c2ecf20Sopenharmony_ci enum ice_status status; 16078c2ecf20Sopenharmony_ci struct device *dev; 16088c2ecf20Sopenharmony_ci int err = 0; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci status = ice_fltr_remove_vlan(vsi, vid, ICE_FWD_TO_VSI); 16138c2ecf20Sopenharmony_ci if (!status) { 16148c2ecf20Sopenharmony_ci vsi->num_vlan--; 16158c2ecf20Sopenharmony_ci } else if (status == ICE_ERR_DOES_NOT_EXIST) { 16168c2ecf20Sopenharmony_ci dev_dbg(dev, "Failed to remove VLAN %d on VSI %i, it does not exist, status: %s\n", 16178c2ecf20Sopenharmony_ci vid, vsi->vsi_num, ice_stat_str(status)); 16188c2ecf20Sopenharmony_ci } else { 16198c2ecf20Sopenharmony_ci dev_err(dev, "Error removing VLAN %d on vsi %i error: %s\n", 16208c2ecf20Sopenharmony_ci vid, vsi->vsi_num, ice_stat_str(status)); 16218c2ecf20Sopenharmony_ci err = -EIO; 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci return err; 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci/** 16288c2ecf20Sopenharmony_ci * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length 16298c2ecf20Sopenharmony_ci * @vsi: VSI 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_civoid ice_vsi_cfg_frame_size(struct ice_vsi *vsi) 16328c2ecf20Sopenharmony_ci{ 16338c2ecf20Sopenharmony_ci if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) { 16348c2ecf20Sopenharmony_ci vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; 16358c2ecf20Sopenharmony_ci vsi->rx_buf_len = ICE_RXBUF_2048; 16368c2ecf20Sopenharmony_ci#if (PAGE_SIZE < 8192) 16378c2ecf20Sopenharmony_ci } else if (!ICE_2K_TOO_SMALL_WITH_PADDING && 16388c2ecf20Sopenharmony_ci (vsi->netdev->mtu <= ETH_DATA_LEN)) { 16398c2ecf20Sopenharmony_ci vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; 16408c2ecf20Sopenharmony_ci vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; 16418c2ecf20Sopenharmony_ci#endif 16428c2ecf20Sopenharmony_ci } else { 16438c2ecf20Sopenharmony_ci vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; 16448c2ecf20Sopenharmony_ci#if (PAGE_SIZE < 8192) 16458c2ecf20Sopenharmony_ci vsi->rx_buf_len = ICE_RXBUF_3072; 16468c2ecf20Sopenharmony_ci#else 16478c2ecf20Sopenharmony_ci vsi->rx_buf_len = ICE_RXBUF_2048; 16488c2ecf20Sopenharmony_ci#endif 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci/** 16538c2ecf20Sopenharmony_ci * ice_write_qrxflxp_cntxt - write/configure QRXFLXP_CNTXT register 16548c2ecf20Sopenharmony_ci * @hw: HW pointer 16558c2ecf20Sopenharmony_ci * @pf_q: index of the Rx queue in the PF's queue space 16568c2ecf20Sopenharmony_ci * @rxdid: flexible descriptor RXDID 16578c2ecf20Sopenharmony_ci * @prio: priority for the RXDID for this queue 16588c2ecf20Sopenharmony_ci */ 16598c2ecf20Sopenharmony_civoid 16608c2ecf20Sopenharmony_ciice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci int regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* clear any previous values */ 16658c2ecf20Sopenharmony_ci regval &= ~(QRXFLXP_CNTXT_RXDID_IDX_M | 16668c2ecf20Sopenharmony_ci QRXFLXP_CNTXT_RXDID_PRIO_M | 16678c2ecf20Sopenharmony_ci QRXFLXP_CNTXT_TS_M); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & 16708c2ecf20Sopenharmony_ci QRXFLXP_CNTXT_RXDID_IDX_M; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci regval |= (prio << QRXFLXP_CNTXT_RXDID_PRIO_S) & 16738c2ecf20Sopenharmony_ci QRXFLXP_CNTXT_RXDID_PRIO_M; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci wr32(hw, QRXFLXP_CNTXT(pf_q), regval); 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci/** 16798c2ecf20Sopenharmony_ci * ice_vsi_cfg_rxqs - Configure the VSI for Rx 16808c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 16818c2ecf20Sopenharmony_ci * 16828c2ecf20Sopenharmony_ci * Return 0 on success and a negative value on error 16838c2ecf20Sopenharmony_ci * Configure the Rx VSI for operation. 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ciint ice_vsi_cfg_rxqs(struct ice_vsi *vsi) 16868c2ecf20Sopenharmony_ci{ 16878c2ecf20Sopenharmony_ci u16 i; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 16908c2ecf20Sopenharmony_ci goto setup_rings; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci ice_vsi_cfg_frame_size(vsi); 16938c2ecf20Sopenharmony_cisetup_rings: 16948c2ecf20Sopenharmony_ci /* set up individual rings */ 16958c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_rxq; i++) { 16968c2ecf20Sopenharmony_ci int err; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci err = ice_setup_rx_ctx(vsi->rx_rings[i]); 16998c2ecf20Sopenharmony_ci if (err) { 17008c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "ice_setup_rx_ctx failed for RxQ %d, err %d\n", 17018c2ecf20Sopenharmony_ci i, err); 17028c2ecf20Sopenharmony_ci return err; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci return 0; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci/** 17108c2ecf20Sopenharmony_ci * ice_vsi_cfg_txqs - Configure the VSI for Tx 17118c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 17128c2ecf20Sopenharmony_ci * @rings: Tx ring array to be configured 17138c2ecf20Sopenharmony_ci * @count: number of Tx ring array elements 17148c2ecf20Sopenharmony_ci * 17158c2ecf20Sopenharmony_ci * Return 0 on success and a negative value on error 17168c2ecf20Sopenharmony_ci * Configure the Tx VSI for operation. 17178c2ecf20Sopenharmony_ci */ 17188c2ecf20Sopenharmony_cistatic int 17198c2ecf20Sopenharmony_ciice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings, u16 count) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci struct ice_aqc_add_tx_qgrp *qg_buf; 17228c2ecf20Sopenharmony_ci u16 q_idx = 0; 17238c2ecf20Sopenharmony_ci int err = 0; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci qg_buf = kzalloc(struct_size(qg_buf, txqs, 1), GFP_KERNEL); 17268c2ecf20Sopenharmony_ci if (!qg_buf) 17278c2ecf20Sopenharmony_ci return -ENOMEM; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci qg_buf->num_txqs = 1; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci for (q_idx = 0; q_idx < count; q_idx++) { 17328c2ecf20Sopenharmony_ci err = ice_vsi_cfg_txq(vsi, rings[q_idx], qg_buf); 17338c2ecf20Sopenharmony_ci if (err) 17348c2ecf20Sopenharmony_ci goto err_cfg_txqs; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_cierr_cfg_txqs: 17388c2ecf20Sopenharmony_ci kfree(qg_buf); 17398c2ecf20Sopenharmony_ci return err; 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci/** 17438c2ecf20Sopenharmony_ci * ice_vsi_cfg_lan_txqs - Configure the VSI for Tx 17448c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 17458c2ecf20Sopenharmony_ci * 17468c2ecf20Sopenharmony_ci * Return 0 on success and a negative value on error 17478c2ecf20Sopenharmony_ci * Configure the Tx VSI for operation. 17488c2ecf20Sopenharmony_ci */ 17498c2ecf20Sopenharmony_ciint ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) 17508c2ecf20Sopenharmony_ci{ 17518c2ecf20Sopenharmony_ci return ice_vsi_cfg_txqs(vsi, vsi->tx_rings, vsi->num_txq); 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci/** 17558c2ecf20Sopenharmony_ci * ice_vsi_cfg_xdp_txqs - Configure Tx queues dedicated for XDP in given VSI 17568c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 17578c2ecf20Sopenharmony_ci * 17588c2ecf20Sopenharmony_ci * Return 0 on success and a negative value on error 17598c2ecf20Sopenharmony_ci * Configure the Tx queues dedicated for XDP in given VSI for operation. 17608c2ecf20Sopenharmony_ci */ 17618c2ecf20Sopenharmony_ciint ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci int ret; 17648c2ecf20Sopenharmony_ci int i; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci ret = ice_vsi_cfg_txqs(vsi, vsi->xdp_rings, vsi->num_xdp_txq); 17678c2ecf20Sopenharmony_ci if (ret) 17688c2ecf20Sopenharmony_ci return ret; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) 17718c2ecf20Sopenharmony_ci vsi->xdp_rings[i]->xsk_pool = ice_xsk_pool(vsi->xdp_rings[i]); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci return ret; 17748c2ecf20Sopenharmony_ci} 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci/** 17778c2ecf20Sopenharmony_ci * ice_intrl_usec_to_reg - convert interrupt rate limit to register value 17788c2ecf20Sopenharmony_ci * @intrl: interrupt rate limit in usecs 17798c2ecf20Sopenharmony_ci * @gran: interrupt rate limit granularity in usecs 17808c2ecf20Sopenharmony_ci * 17818c2ecf20Sopenharmony_ci * This function converts a decimal interrupt rate limit in usecs to the format 17828c2ecf20Sopenharmony_ci * expected by firmware. 17838c2ecf20Sopenharmony_ci */ 17848c2ecf20Sopenharmony_ciu32 ice_intrl_usec_to_reg(u8 intrl, u8 gran) 17858c2ecf20Sopenharmony_ci{ 17868c2ecf20Sopenharmony_ci u32 val = intrl / gran; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (val) 17898c2ecf20Sopenharmony_ci return val | GLINT_RATE_INTRL_ENA_M; 17908c2ecf20Sopenharmony_ci return 0; 17918c2ecf20Sopenharmony_ci} 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci/** 17948c2ecf20Sopenharmony_ci * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW 17958c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 17968c2ecf20Sopenharmony_ci * 17978c2ecf20Sopenharmony_ci * This configures MSIX mode interrupts for the PF VSI, and should not be used 17988c2ecf20Sopenharmony_ci * for the VF VSI. 17998c2ecf20Sopenharmony_ci */ 18008c2ecf20Sopenharmony_civoid ice_vsi_cfg_msix(struct ice_vsi *vsi) 18018c2ecf20Sopenharmony_ci{ 18028c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 18038c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 18048c2ecf20Sopenharmony_ci u16 txq = 0, rxq = 0; 18058c2ecf20Sopenharmony_ci int i, q; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_q_vectors; i++) { 18088c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 18098c2ecf20Sopenharmony_ci u16 reg_idx = q_vector->reg_idx; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci ice_cfg_itr(hw, q_vector); 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci wr32(hw, GLINT_RATE(reg_idx), 18148c2ecf20Sopenharmony_ci ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* Both Transmit Queue Interrupt Cause Control register 18178c2ecf20Sopenharmony_ci * and Receive Queue Interrupt Cause control register 18188c2ecf20Sopenharmony_ci * expects MSIX_INDX field to be the vector index 18198c2ecf20Sopenharmony_ci * within the function space and not the absolute 18208c2ecf20Sopenharmony_ci * vector index across PF or across device. 18218c2ecf20Sopenharmony_ci * For SR-IOV VF VSIs queue vector index always starts 18228c2ecf20Sopenharmony_ci * with 1 since first vector index(0) is used for OICR 18238c2ecf20Sopenharmony_ci * in VF space. Since VMDq and other PF VSIs are within 18248c2ecf20Sopenharmony_ci * the PF function space, use the vector index that is 18258c2ecf20Sopenharmony_ci * tracked for this PF. 18268c2ecf20Sopenharmony_ci */ 18278c2ecf20Sopenharmony_ci for (q = 0; q < q_vector->num_ring_tx; q++) { 18288c2ecf20Sopenharmony_ci ice_cfg_txq_interrupt(vsi, txq, reg_idx, 18298c2ecf20Sopenharmony_ci q_vector->tx.itr_idx); 18308c2ecf20Sopenharmony_ci txq++; 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci for (q = 0; q < q_vector->num_ring_rx; q++) { 18348c2ecf20Sopenharmony_ci ice_cfg_rxq_interrupt(vsi, rxq, reg_idx, 18358c2ecf20Sopenharmony_ci q_vector->rx.itr_idx); 18368c2ecf20Sopenharmony_ci rxq++; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci/** 18428c2ecf20Sopenharmony_ci * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx 18438c2ecf20Sopenharmony_ci * @vsi: the VSI being changed 18448c2ecf20Sopenharmony_ci */ 18458c2ecf20Sopenharmony_ciint ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 18488c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctxt; 18498c2ecf20Sopenharmony_ci enum ice_status status; 18508c2ecf20Sopenharmony_ci int ret = 0; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 18538c2ecf20Sopenharmony_ci if (!ctxt) 18548c2ecf20Sopenharmony_ci return -ENOMEM; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci /* Here we are configuring the VSI to let the driver add VLAN tags by 18578c2ecf20Sopenharmony_ci * setting vlan_flags to ICE_AQ_VSI_VLAN_MODE_ALL. The actual VLAN tag 18588c2ecf20Sopenharmony_ci * insertion happens in the Tx hot path, in ice_tx_map. 18598c2ecf20Sopenharmony_ci */ 18608c2ecf20Sopenharmony_ci ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci /* Preserve existing VLAN strip setting */ 18638c2ecf20Sopenharmony_ci ctxt->info.vlan_flags |= (vsi->info.vlan_flags & 18648c2ecf20Sopenharmony_ci ICE_AQ_VSI_VLAN_EMOD_M); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); 18698c2ecf20Sopenharmony_ci if (status) { 18708c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN insert failed, err %s aq_err %s\n", 18718c2ecf20Sopenharmony_ci ice_stat_str(status), 18728c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 18738c2ecf20Sopenharmony_ci ret = -EIO; 18748c2ecf20Sopenharmony_ci goto out; 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci vsi->info.vlan_flags = ctxt->info.vlan_flags; 18788c2ecf20Sopenharmony_ciout: 18798c2ecf20Sopenharmony_ci kfree(ctxt); 18808c2ecf20Sopenharmony_ci return ret; 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci/** 18848c2ecf20Sopenharmony_ci * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx 18858c2ecf20Sopenharmony_ci * @vsi: the VSI being changed 18868c2ecf20Sopenharmony_ci * @ena: boolean value indicating if this is a enable or disable request 18878c2ecf20Sopenharmony_ci */ 18888c2ecf20Sopenharmony_ciint ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) 18898c2ecf20Sopenharmony_ci{ 18908c2ecf20Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 18918c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctxt; 18928c2ecf20Sopenharmony_ci enum ice_status status; 18938c2ecf20Sopenharmony_ci int ret = 0; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci /* do not allow modifying VLAN stripping when a port VLAN is configured 18968c2ecf20Sopenharmony_ci * on this VSI 18978c2ecf20Sopenharmony_ci */ 18988c2ecf20Sopenharmony_ci if (vsi->info.pvid) 18998c2ecf20Sopenharmony_ci return 0; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 19028c2ecf20Sopenharmony_ci if (!ctxt) 19038c2ecf20Sopenharmony_ci return -ENOMEM; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci /* Here we are configuring what the VSI should do with the VLAN tag in 19068c2ecf20Sopenharmony_ci * the Rx packet. We can either leave the tag in the packet or put it in 19078c2ecf20Sopenharmony_ci * the Rx descriptor. 19088c2ecf20Sopenharmony_ci */ 19098c2ecf20Sopenharmony_ci if (ena) 19108c2ecf20Sopenharmony_ci /* Strip VLAN tag from Rx packet and put it in the desc */ 19118c2ecf20Sopenharmony_ci ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_STR_BOTH; 19128c2ecf20Sopenharmony_ci else 19138c2ecf20Sopenharmony_ci /* Disable stripping. Leave tag in packet */ 19148c2ecf20Sopenharmony_ci ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci /* Allow all packets untagged/tagged */ 19178c2ecf20Sopenharmony_ci ctxt->info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); 19228c2ecf20Sopenharmony_ci if (status) { 19238c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN strip failed, ena = %d err %s aq_err %s\n", 19248c2ecf20Sopenharmony_ci ena, ice_stat_str(status), 19258c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 19268c2ecf20Sopenharmony_ci ret = -EIO; 19278c2ecf20Sopenharmony_ci goto out; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci vsi->info.vlan_flags = ctxt->info.vlan_flags; 19318c2ecf20Sopenharmony_ciout: 19328c2ecf20Sopenharmony_ci kfree(ctxt); 19338c2ecf20Sopenharmony_ci return ret; 19348c2ecf20Sopenharmony_ci} 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci/** 19378c2ecf20Sopenharmony_ci * ice_vsi_start_all_rx_rings - start/enable all of a VSI's Rx rings 19388c2ecf20Sopenharmony_ci * @vsi: the VSI whose rings are to be enabled 19398c2ecf20Sopenharmony_ci * 19408c2ecf20Sopenharmony_ci * Returns 0 on success and a negative value on error 19418c2ecf20Sopenharmony_ci */ 19428c2ecf20Sopenharmony_ciint ice_vsi_start_all_rx_rings(struct ice_vsi *vsi) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci return ice_vsi_ctrl_all_rx_rings(vsi, true); 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci/** 19488c2ecf20Sopenharmony_ci * ice_vsi_stop_all_rx_rings - stop/disable all of a VSI's Rx rings 19498c2ecf20Sopenharmony_ci * @vsi: the VSI whose rings are to be disabled 19508c2ecf20Sopenharmony_ci * 19518c2ecf20Sopenharmony_ci * Returns 0 on success and a negative value on error 19528c2ecf20Sopenharmony_ci */ 19538c2ecf20Sopenharmony_ciint ice_vsi_stop_all_rx_rings(struct ice_vsi *vsi) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci return ice_vsi_ctrl_all_rx_rings(vsi, false); 19568c2ecf20Sopenharmony_ci} 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci/** 19598c2ecf20Sopenharmony_ci * ice_vsi_stop_tx_rings - Disable Tx rings 19608c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 19618c2ecf20Sopenharmony_ci * @rst_src: reset source 19628c2ecf20Sopenharmony_ci * @rel_vmvf_num: Relative ID of VF/VM 19638c2ecf20Sopenharmony_ci * @rings: Tx ring array to be stopped 19648c2ecf20Sopenharmony_ci * @count: number of Tx ring array elements 19658c2ecf20Sopenharmony_ci */ 19668c2ecf20Sopenharmony_cistatic int 19678c2ecf20Sopenharmony_ciice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, 19688c2ecf20Sopenharmony_ci u16 rel_vmvf_num, struct ice_ring **rings, u16 count) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci u16 q_idx; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS) 19738c2ecf20Sopenharmony_ci return -EINVAL; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci for (q_idx = 0; q_idx < count; q_idx++) { 19768c2ecf20Sopenharmony_ci struct ice_txq_meta txq_meta = { }; 19778c2ecf20Sopenharmony_ci int status; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci if (!rings || !rings[q_idx]) 19808c2ecf20Sopenharmony_ci return -EINVAL; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci ice_fill_txq_meta(vsi, rings[q_idx], &txq_meta); 19838c2ecf20Sopenharmony_ci status = ice_vsi_stop_tx_ring(vsi, rst_src, rel_vmvf_num, 19848c2ecf20Sopenharmony_ci rings[q_idx], &txq_meta); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (status) 19878c2ecf20Sopenharmony_ci return status; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci return 0; 19918c2ecf20Sopenharmony_ci} 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci/** 19948c2ecf20Sopenharmony_ci * ice_vsi_stop_lan_tx_rings - Disable LAN Tx rings 19958c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 19968c2ecf20Sopenharmony_ci * @rst_src: reset source 19978c2ecf20Sopenharmony_ci * @rel_vmvf_num: Relative ID of VF/VM 19988c2ecf20Sopenharmony_ci */ 19998c2ecf20Sopenharmony_ciint 20008c2ecf20Sopenharmony_ciice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, 20018c2ecf20Sopenharmony_ci u16 rel_vmvf_num) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci return ice_vsi_stop_tx_rings(vsi, rst_src, rel_vmvf_num, vsi->tx_rings, vsi->num_txq); 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci/** 20078c2ecf20Sopenharmony_ci * ice_vsi_stop_xdp_tx_rings - Disable XDP Tx rings 20088c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 20098c2ecf20Sopenharmony_ci */ 20108c2ecf20Sopenharmony_ciint ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi) 20118c2ecf20Sopenharmony_ci{ 20128c2ecf20Sopenharmony_ci return ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0, vsi->xdp_rings, vsi->num_xdp_txq); 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci/** 20168c2ecf20Sopenharmony_ci * ice_vsi_is_vlan_pruning_ena - check if VLAN pruning is enabled or not 20178c2ecf20Sopenharmony_ci * @vsi: VSI to check whether or not VLAN pruning is enabled. 20188c2ecf20Sopenharmony_ci * 20198c2ecf20Sopenharmony_ci * returns true if Rx VLAN pruning is enabled and false otherwise. 20208c2ecf20Sopenharmony_ci */ 20218c2ecf20Sopenharmony_cibool ice_vsi_is_vlan_pruning_ena(struct ice_vsi *vsi) 20228c2ecf20Sopenharmony_ci{ 20238c2ecf20Sopenharmony_ci if (!vsi) 20248c2ecf20Sopenharmony_ci return false; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci return (vsi->info.sw_flags2 & ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA); 20278c2ecf20Sopenharmony_ci} 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci/** 20308c2ecf20Sopenharmony_ci * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI 20318c2ecf20Sopenharmony_ci * @vsi: VSI to enable or disable VLAN pruning on 20328c2ecf20Sopenharmony_ci * @ena: set to true to enable VLAN pruning and false to disable it 20338c2ecf20Sopenharmony_ci * @vlan_promisc: enable valid security flags if not in VLAN promiscuous mode 20348c2ecf20Sopenharmony_ci * 20358c2ecf20Sopenharmony_ci * returns 0 if VSI is updated, negative otherwise 20368c2ecf20Sopenharmony_ci */ 20378c2ecf20Sopenharmony_ciint ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc) 20388c2ecf20Sopenharmony_ci{ 20398c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctxt; 20408c2ecf20Sopenharmony_ci struct ice_pf *pf; 20418c2ecf20Sopenharmony_ci int status; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci if (!vsi) 20448c2ecf20Sopenharmony_ci return -EINVAL; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci /* Don't enable VLAN pruning if the netdev is currently in promiscuous 20478c2ecf20Sopenharmony_ci * mode. VLAN pruning will be enabled when the interface exits 20488c2ecf20Sopenharmony_ci * promiscuous mode if any VLAN filters are active. 20498c2ecf20Sopenharmony_ci */ 20508c2ecf20Sopenharmony_ci if (vsi->netdev && vsi->netdev->flags & IFF_PROMISC && ena) 20518c2ecf20Sopenharmony_ci return 0; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci pf = vsi->back; 20548c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 20558c2ecf20Sopenharmony_ci if (!ctxt) 20568c2ecf20Sopenharmony_ci return -ENOMEM; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci ctxt->info = vsi->info; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci if (ena) 20618c2ecf20Sopenharmony_ci ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; 20628c2ecf20Sopenharmony_ci else 20638c2ecf20Sopenharmony_ci ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci if (!vlan_promisc) 20668c2ecf20Sopenharmony_ci ctxt->info.valid_sections = 20678c2ecf20Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL); 20708c2ecf20Sopenharmony_ci if (status) { 20718c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %s, aq_err = %s\n", 20728c2ecf20Sopenharmony_ci ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, 20738c2ecf20Sopenharmony_ci ice_stat_str(status), 20748c2ecf20Sopenharmony_ci ice_aq_str(pf->hw.adminq.sq_last_status)); 20758c2ecf20Sopenharmony_ci goto err_out; 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci vsi->info.sw_flags2 = ctxt->info.sw_flags2; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci kfree(ctxt); 20818c2ecf20Sopenharmony_ci return 0; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cierr_out: 20848c2ecf20Sopenharmony_ci kfree(ctxt); 20858c2ecf20Sopenharmony_ci return -EIO; 20868c2ecf20Sopenharmony_ci} 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_cistatic void ice_vsi_set_tc_cfg(struct ice_vsi *vsi) 20898c2ecf20Sopenharmony_ci{ 20908c2ecf20Sopenharmony_ci struct ice_dcbx_cfg *cfg = &vsi->port_info->qos_cfg.local_dcbx_cfg; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci vsi->tc_cfg.ena_tc = ice_dcb_get_ena_tc(cfg); 20938c2ecf20Sopenharmony_ci vsi->tc_cfg.numtc = ice_dcb_get_num_tc(cfg); 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci/** 20978c2ecf20Sopenharmony_ci * ice_vsi_set_q_vectors_reg_idx - set the HW register index for all q_vectors 20988c2ecf20Sopenharmony_ci * @vsi: VSI to set the q_vectors register index on 20998c2ecf20Sopenharmony_ci */ 21008c2ecf20Sopenharmony_cistatic int 21018c2ecf20Sopenharmony_ciice_vsi_set_q_vectors_reg_idx(struct ice_vsi *vsi) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci u16 i; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (!vsi || !vsi->q_vectors) 21068c2ecf20Sopenharmony_ci return -EINVAL; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 21098c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (!q_vector) { 21128c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Failed to set reg_idx on q_vector %d VSI %d\n", 21138c2ecf20Sopenharmony_ci i, vsi->vsi_num); 21148c2ecf20Sopenharmony_ci goto clear_reg_idx; 21158c2ecf20Sopenharmony_ci } 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) { 21188c2ecf20Sopenharmony_ci struct ice_vf *vf = &vsi->back->vf[vsi->vf_id]; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci q_vector->reg_idx = ice_calc_vf_reg_idx(vf, q_vector); 21218c2ecf20Sopenharmony_ci } else { 21228c2ecf20Sopenharmony_ci q_vector->reg_idx = 21238c2ecf20Sopenharmony_ci q_vector->v_idx + vsi->base_vector; 21248c2ecf20Sopenharmony_ci } 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci return 0; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ciclear_reg_idx: 21308c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 21318c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (q_vector) 21348c2ecf20Sopenharmony_ci q_vector->reg_idx = 0; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci return -EINVAL; 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci/** 21418c2ecf20Sopenharmony_ci * ice_cfg_sw_lldp - Config switch rules for LLDP packet handling 21428c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 21438c2ecf20Sopenharmony_ci * @tx: bool to determine Tx or Rx rule 21448c2ecf20Sopenharmony_ci * @create: bool to determine create or remove Rule 21458c2ecf20Sopenharmony_ci */ 21468c2ecf20Sopenharmony_civoid ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci enum ice_status (*eth_fltr)(struct ice_vsi *v, u16 type, u16 flag, 21498c2ecf20Sopenharmony_ci enum ice_sw_fwd_act_type act); 21508c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 21518c2ecf20Sopenharmony_ci enum ice_status status; 21528c2ecf20Sopenharmony_ci struct device *dev; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 21558c2ecf20Sopenharmony_ci eth_fltr = create ? ice_fltr_add_eth : ice_fltr_remove_eth; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if (tx) 21588c2ecf20Sopenharmony_ci status = eth_fltr(vsi, ETH_P_LLDP, ICE_FLTR_TX, 21598c2ecf20Sopenharmony_ci ICE_DROP_PACKET); 21608c2ecf20Sopenharmony_ci else 21618c2ecf20Sopenharmony_ci status = eth_fltr(vsi, ETH_P_LLDP, ICE_FLTR_RX, ICE_FWD_TO_VSI); 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci if (status) 21648c2ecf20Sopenharmony_ci dev_err(dev, "Fail %s %s LLDP rule on VSI %i error: %s\n", 21658c2ecf20Sopenharmony_ci create ? "adding" : "removing", tx ? "TX" : "RX", 21668c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 21678c2ecf20Sopenharmony_ci} 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci/** 21708c2ecf20Sopenharmony_ci * ice_vsi_setup - Set up a VSI by a given type 21718c2ecf20Sopenharmony_ci * @pf: board private structure 21728c2ecf20Sopenharmony_ci * @pi: pointer to the port_info instance 21738c2ecf20Sopenharmony_ci * @vsi_type: VSI type 21748c2ecf20Sopenharmony_ci * @vf_id: defines VF ID to which this VSI connects. This field is meant to be 21758c2ecf20Sopenharmony_ci * used only for ICE_VSI_VF VSI type. For other VSI types, should 21768c2ecf20Sopenharmony_ci * fill-in ICE_INVAL_VFID as input. 21778c2ecf20Sopenharmony_ci * 21788c2ecf20Sopenharmony_ci * This allocates the sw VSI structure and its queue resources. 21798c2ecf20Sopenharmony_ci * 21808c2ecf20Sopenharmony_ci * Returns pointer to the successfully allocated and configured VSI sw struct on 21818c2ecf20Sopenharmony_ci * success, NULL on failure. 21828c2ecf20Sopenharmony_ci */ 21838c2ecf20Sopenharmony_cistruct ice_vsi * 21848c2ecf20Sopenharmony_ciice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, 21858c2ecf20Sopenharmony_ci enum ice_vsi_type vsi_type, u16 vf_id) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 21888c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 21898c2ecf20Sopenharmony_ci enum ice_status status; 21908c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 21918c2ecf20Sopenharmony_ci int ret, i; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (vsi_type == ICE_VSI_VF) 21948c2ecf20Sopenharmony_ci vsi = ice_vsi_alloc(pf, vsi_type, vf_id); 21958c2ecf20Sopenharmony_ci else 21968c2ecf20Sopenharmony_ci vsi = ice_vsi_alloc(pf, vsi_type, ICE_INVAL_VFID); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci if (!vsi) { 21998c2ecf20Sopenharmony_ci dev_err(dev, "could not allocate VSI\n"); 22008c2ecf20Sopenharmony_ci return NULL; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci vsi->port_info = pi; 22048c2ecf20Sopenharmony_ci vsi->vsw = pf->first_sw; 22058c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) 22068c2ecf20Sopenharmony_ci vsi->ethtype = ETH_P_PAUSE; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 22098c2ecf20Sopenharmony_ci vsi->vf_id = vf_id; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci ice_alloc_fd_res(vsi); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci if (ice_vsi_get_qs(vsi)) { 22148c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate queues. vsi->idx = %d\n", 22158c2ecf20Sopenharmony_ci vsi->idx); 22168c2ecf20Sopenharmony_ci goto unroll_vsi_alloc; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci /* set RSS capabilities */ 22208c2ecf20Sopenharmony_ci ice_vsi_set_rss_params(vsi); 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci /* set TC configuration */ 22238c2ecf20Sopenharmony_ci ice_vsi_set_tc_cfg(vsi); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci /* create the VSI */ 22268c2ecf20Sopenharmony_ci ret = ice_vsi_init(vsi, true); 22278c2ecf20Sopenharmony_ci if (ret) 22288c2ecf20Sopenharmony_ci goto unroll_get_qs; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci switch (vsi->type) { 22318c2ecf20Sopenharmony_ci case ICE_VSI_CTRL: 22328c2ecf20Sopenharmony_ci case ICE_VSI_PF: 22338c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_q_vectors(vsi); 22348c2ecf20Sopenharmony_ci if (ret) 22358c2ecf20Sopenharmony_ci goto unroll_vsi_init; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci ret = ice_vsi_setup_vector_base(vsi); 22388c2ecf20Sopenharmony_ci if (ret) 22398c2ecf20Sopenharmony_ci goto unroll_alloc_q_vector; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci ret = ice_vsi_set_q_vectors_reg_idx(vsi); 22428c2ecf20Sopenharmony_ci if (ret) 22438c2ecf20Sopenharmony_ci goto unroll_vector_base; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 22468c2ecf20Sopenharmony_ci if (ret) 22478c2ecf20Sopenharmony_ci goto unroll_vector_base; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci /* Always add VLAN ID 0 switch rule by default. This is needed 22508c2ecf20Sopenharmony_ci * in order to allow all untagged and 0 tagged priority traffic 22518c2ecf20Sopenharmony_ci * if Rx VLAN pruning is enabled. Also there are cases where we 22528c2ecf20Sopenharmony_ci * don't get the call to add VLAN 0 via ice_vlan_rx_add_vid() 22538c2ecf20Sopenharmony_ci * so this handles those cases (i.e. adding the PF to a bridge 22548c2ecf20Sopenharmony_ci * without the 8021q module loaded). 22558c2ecf20Sopenharmony_ci */ 22568c2ecf20Sopenharmony_ci ret = ice_vsi_add_vlan(vsi, 0, ICE_FWD_TO_VSI); 22578c2ecf20Sopenharmony_ci if (ret) 22588c2ecf20Sopenharmony_ci goto unroll_clear_rings; 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci ice_vsi_map_rings_to_vectors(vsi); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci /* ICE_VSI_CTRL does not need RSS so skip RSS processing */ 22638c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_CTRL) 22648c2ecf20Sopenharmony_ci /* Do not exit if configuring RSS had an issue, at 22658c2ecf20Sopenharmony_ci * least receive traffic on first queue. Hence no 22668c2ecf20Sopenharmony_ci * need to capture return value 22678c2ecf20Sopenharmony_ci */ 22688c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 22698c2ecf20Sopenharmony_ci ice_vsi_cfg_rss_lut_key(vsi); 22708c2ecf20Sopenharmony_ci ice_vsi_set_rss_flow_fld(vsi); 22718c2ecf20Sopenharmony_ci } 22728c2ecf20Sopenharmony_ci ice_init_arfs(vsi); 22738c2ecf20Sopenharmony_ci break; 22748c2ecf20Sopenharmony_ci case ICE_VSI_VF: 22758c2ecf20Sopenharmony_ci /* VF driver will take care of creating netdev for this type and 22768c2ecf20Sopenharmony_ci * map queues to vectors through Virtchnl, PF driver only 22778c2ecf20Sopenharmony_ci * creates a VSI and corresponding structures for bookkeeping 22788c2ecf20Sopenharmony_ci * purpose 22798c2ecf20Sopenharmony_ci */ 22808c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_q_vectors(vsi); 22818c2ecf20Sopenharmony_ci if (ret) 22828c2ecf20Sopenharmony_ci goto unroll_vsi_init; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 22858c2ecf20Sopenharmony_ci if (ret) 22868c2ecf20Sopenharmony_ci goto unroll_alloc_q_vector; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci ret = ice_vsi_set_q_vectors_reg_idx(vsi); 22898c2ecf20Sopenharmony_ci if (ret) 22908c2ecf20Sopenharmony_ci goto unroll_vector_base; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci /* Do not exit if configuring RSS had an issue, at least 22938c2ecf20Sopenharmony_ci * receive traffic on first queue. Hence no need to capture 22948c2ecf20Sopenharmony_ci * return value 22958c2ecf20Sopenharmony_ci */ 22968c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 22978c2ecf20Sopenharmony_ci ice_vsi_cfg_rss_lut_key(vsi); 22988c2ecf20Sopenharmony_ci ice_vsi_set_vf_rss_flow_fld(vsi); 22998c2ecf20Sopenharmony_ci } 23008c2ecf20Sopenharmony_ci break; 23018c2ecf20Sopenharmony_ci case ICE_VSI_LB: 23028c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 23038c2ecf20Sopenharmony_ci if (ret) 23048c2ecf20Sopenharmony_ci goto unroll_vsi_init; 23058c2ecf20Sopenharmony_ci break; 23068c2ecf20Sopenharmony_ci default: 23078c2ecf20Sopenharmony_ci /* clean up the resources and exit */ 23088c2ecf20Sopenharmony_ci goto unroll_vsi_init; 23098c2ecf20Sopenharmony_ci } 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci /* configure VSI nodes based on number of queues and TC's */ 23128c2ecf20Sopenharmony_ci for (i = 0; i < vsi->tc_cfg.numtc; i++) 23138c2ecf20Sopenharmony_ci max_txqs[i] = vsi->alloc_txq; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, 23168c2ecf20Sopenharmony_ci max_txqs); 23178c2ecf20Sopenharmony_ci if (status) { 23188c2ecf20Sopenharmony_ci dev_err(dev, "VSI %d failed lan queue config, error %s\n", 23198c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 23208c2ecf20Sopenharmony_ci goto unroll_clear_rings; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci /* Add switch rule to drop all Tx Flow Control Frames, of look up 23248c2ecf20Sopenharmony_ci * type ETHERTYPE from VSIs, and restrict malicious VF from sending 23258c2ecf20Sopenharmony_ci * out PAUSE or PFC frames. If enabled, FW can still send FC frames. 23268c2ecf20Sopenharmony_ci * The rule is added once for PF VSI in order to create appropriate 23278c2ecf20Sopenharmony_ci * recipe, since VSI/VSI list is ignored with drop action... 23288c2ecf20Sopenharmony_ci * Also add rules to handle LLDP Tx packets. Tx LLDP packets need to 23298c2ecf20Sopenharmony_ci * be dropped so that VFs cannot send LLDP packets to reconfig DCB 23308c2ecf20Sopenharmony_ci * settings in the HW. 23318c2ecf20Sopenharmony_ci */ 23328c2ecf20Sopenharmony_ci if (!ice_is_safe_mode(pf)) 23338c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 23348c2ecf20Sopenharmony_ci ice_fltr_add_eth(vsi, ETH_P_PAUSE, ICE_FLTR_TX, 23358c2ecf20Sopenharmony_ci ICE_DROP_PACKET); 23368c2ecf20Sopenharmony_ci ice_cfg_sw_lldp(vsi, true, true); 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci return vsi; 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ciunroll_clear_rings: 23428c2ecf20Sopenharmony_ci ice_vsi_clear_rings(vsi); 23438c2ecf20Sopenharmony_ciunroll_vector_base: 23448c2ecf20Sopenharmony_ci /* reclaim SW interrupts back to the common pool */ 23458c2ecf20Sopenharmony_ci ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx); 23468c2ecf20Sopenharmony_ci pf->num_avail_sw_msix += vsi->num_q_vectors; 23478c2ecf20Sopenharmony_ciunroll_alloc_q_vector: 23488c2ecf20Sopenharmony_ci ice_vsi_free_q_vectors(vsi); 23498c2ecf20Sopenharmony_ciunroll_vsi_init: 23508c2ecf20Sopenharmony_ci ice_vsi_delete(vsi); 23518c2ecf20Sopenharmony_ciunroll_get_qs: 23528c2ecf20Sopenharmony_ci ice_vsi_put_qs(vsi); 23538c2ecf20Sopenharmony_ciunroll_vsi_alloc: 23548c2ecf20Sopenharmony_ci ice_vsi_clear(vsi); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci return NULL; 23578c2ecf20Sopenharmony_ci} 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci/** 23608c2ecf20Sopenharmony_ci * ice_vsi_release_msix - Clear the queue to Interrupt mapping in HW 23618c2ecf20Sopenharmony_ci * @vsi: the VSI being cleaned up 23628c2ecf20Sopenharmony_ci */ 23638c2ecf20Sopenharmony_cistatic void ice_vsi_release_msix(struct ice_vsi *vsi) 23648c2ecf20Sopenharmony_ci{ 23658c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 23668c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 23678c2ecf20Sopenharmony_ci u32 txq = 0; 23688c2ecf20Sopenharmony_ci u32 rxq = 0; 23698c2ecf20Sopenharmony_ci int i, q; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_q_vectors; i++) { 23728c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 23738c2ecf20Sopenharmony_ci u16 reg_idx = q_vector->reg_idx; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci wr32(hw, GLINT_ITR(ICE_IDX_ITR0, reg_idx), 0); 23768c2ecf20Sopenharmony_ci wr32(hw, GLINT_ITR(ICE_IDX_ITR1, reg_idx), 0); 23778c2ecf20Sopenharmony_ci for (q = 0; q < q_vector->num_ring_tx; q++) { 23788c2ecf20Sopenharmony_ci wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0); 23798c2ecf20Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) { 23808c2ecf20Sopenharmony_ci u32 xdp_txq = txq + vsi->num_xdp_txq; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci wr32(hw, QINT_TQCTL(vsi->txq_map[xdp_txq]), 0); 23838c2ecf20Sopenharmony_ci } 23848c2ecf20Sopenharmony_ci txq++; 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci for (q = 0; q < q_vector->num_ring_rx; q++) { 23888c2ecf20Sopenharmony_ci wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), 0); 23898c2ecf20Sopenharmony_ci rxq++; 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci } 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci ice_flush(hw); 23948c2ecf20Sopenharmony_ci} 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci/** 23978c2ecf20Sopenharmony_ci * ice_vsi_free_irq - Free the IRQ association with the OS 23988c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 23998c2ecf20Sopenharmony_ci */ 24008c2ecf20Sopenharmony_civoid ice_vsi_free_irq(struct ice_vsi *vsi) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 24038c2ecf20Sopenharmony_ci int base = vsi->base_vector; 24048c2ecf20Sopenharmony_ci int i; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci if (!vsi->q_vectors || !vsi->irqs_ready) 24078c2ecf20Sopenharmony_ci return; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci ice_vsi_release_msix(vsi); 24108c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 24118c2ecf20Sopenharmony_ci return; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci vsi->irqs_ready = false; 24148c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 24158c2ecf20Sopenharmony_ci u16 vector = i + base; 24168c2ecf20Sopenharmony_ci int irq_num; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci irq_num = pf->msix_entries[vector].vector; 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci /* free only the irqs that were actually requested */ 24218c2ecf20Sopenharmony_ci if (!vsi->q_vectors[i] || 24228c2ecf20Sopenharmony_ci !(vsi->q_vectors[i]->num_ring_tx || 24238c2ecf20Sopenharmony_ci vsi->q_vectors[i]->num_ring_rx)) 24248c2ecf20Sopenharmony_ci continue; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci /* clear the affinity notifier in the IRQ descriptor */ 24278c2ecf20Sopenharmony_ci irq_set_affinity_notifier(irq_num, NULL); 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci /* clear the affinity_mask in the IRQ descriptor */ 24308c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq_num, NULL); 24318c2ecf20Sopenharmony_ci synchronize_irq(irq_num); 24328c2ecf20Sopenharmony_ci devm_free_irq(ice_pf_to_dev(pf), irq_num, vsi->q_vectors[i]); 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci/** 24378c2ecf20Sopenharmony_ci * ice_vsi_free_tx_rings - Free Tx resources for VSI queues 24388c2ecf20Sopenharmony_ci * @vsi: the VSI having resources freed 24398c2ecf20Sopenharmony_ci */ 24408c2ecf20Sopenharmony_civoid ice_vsi_free_tx_rings(struct ice_vsi *vsi) 24418c2ecf20Sopenharmony_ci{ 24428c2ecf20Sopenharmony_ci int i; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci if (!vsi->tx_rings) 24458c2ecf20Sopenharmony_ci return; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci ice_for_each_txq(vsi, i) 24488c2ecf20Sopenharmony_ci if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) 24498c2ecf20Sopenharmony_ci ice_free_tx_ring(vsi->tx_rings[i]); 24508c2ecf20Sopenharmony_ci} 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci/** 24538c2ecf20Sopenharmony_ci * ice_vsi_free_rx_rings - Free Rx resources for VSI queues 24548c2ecf20Sopenharmony_ci * @vsi: the VSI having resources freed 24558c2ecf20Sopenharmony_ci */ 24568c2ecf20Sopenharmony_civoid ice_vsi_free_rx_rings(struct ice_vsi *vsi) 24578c2ecf20Sopenharmony_ci{ 24588c2ecf20Sopenharmony_ci int i; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (!vsi->rx_rings) 24618c2ecf20Sopenharmony_ci return; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) 24648c2ecf20Sopenharmony_ci if (vsi->rx_rings[i] && vsi->rx_rings[i]->desc) 24658c2ecf20Sopenharmony_ci ice_free_rx_ring(vsi->rx_rings[i]); 24668c2ecf20Sopenharmony_ci} 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci/** 24698c2ecf20Sopenharmony_ci * ice_vsi_close - Shut down a VSI 24708c2ecf20Sopenharmony_ci * @vsi: the VSI being shut down 24718c2ecf20Sopenharmony_ci */ 24728c2ecf20Sopenharmony_civoid ice_vsi_close(struct ice_vsi *vsi) 24738c2ecf20Sopenharmony_ci{ 24748c2ecf20Sopenharmony_ci if (!test_and_set_bit(__ICE_DOWN, vsi->state)) 24758c2ecf20Sopenharmony_ci ice_down(vsi); 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci ice_vsi_free_irq(vsi); 24788c2ecf20Sopenharmony_ci ice_vsi_free_tx_rings(vsi); 24798c2ecf20Sopenharmony_ci ice_vsi_free_rx_rings(vsi); 24808c2ecf20Sopenharmony_ci} 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci/** 24838c2ecf20Sopenharmony_ci * ice_ena_vsi - resume a VSI 24848c2ecf20Sopenharmony_ci * @vsi: the VSI being resume 24858c2ecf20Sopenharmony_ci * @locked: is the rtnl_lock already held 24868c2ecf20Sopenharmony_ci */ 24878c2ecf20Sopenharmony_ciint ice_ena_vsi(struct ice_vsi *vsi, bool locked) 24888c2ecf20Sopenharmony_ci{ 24898c2ecf20Sopenharmony_ci int err = 0; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci if (!test_bit(__ICE_NEEDS_RESTART, vsi->state)) 24928c2ecf20Sopenharmony_ci return 0; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci clear_bit(__ICE_NEEDS_RESTART, vsi->state); 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci if (vsi->netdev && vsi->type == ICE_VSI_PF) { 24978c2ecf20Sopenharmony_ci if (netif_running(vsi->netdev)) { 24988c2ecf20Sopenharmony_ci if (!locked) 24998c2ecf20Sopenharmony_ci rtnl_lock(); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci err = ice_open_internal(vsi->netdev); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci if (!locked) 25048c2ecf20Sopenharmony_ci rtnl_unlock(); 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci } else if (vsi->type == ICE_VSI_CTRL) { 25078c2ecf20Sopenharmony_ci err = ice_vsi_open_ctrl(vsi); 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci return err; 25118c2ecf20Sopenharmony_ci} 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci/** 25148c2ecf20Sopenharmony_ci * ice_dis_vsi - pause a VSI 25158c2ecf20Sopenharmony_ci * @vsi: the VSI being paused 25168c2ecf20Sopenharmony_ci * @locked: is the rtnl_lock already held 25178c2ecf20Sopenharmony_ci */ 25188c2ecf20Sopenharmony_civoid ice_dis_vsi(struct ice_vsi *vsi, bool locked) 25198c2ecf20Sopenharmony_ci{ 25208c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, vsi->state)) 25218c2ecf20Sopenharmony_ci return; 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci set_bit(__ICE_NEEDS_RESTART, vsi->state); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF && vsi->netdev) { 25268c2ecf20Sopenharmony_ci if (netif_running(vsi->netdev)) { 25278c2ecf20Sopenharmony_ci if (!locked) 25288c2ecf20Sopenharmony_ci rtnl_lock(); 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci ice_vsi_close(vsi); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci if (!locked) 25338c2ecf20Sopenharmony_ci rtnl_unlock(); 25348c2ecf20Sopenharmony_ci } else { 25358c2ecf20Sopenharmony_ci ice_vsi_close(vsi); 25368c2ecf20Sopenharmony_ci } 25378c2ecf20Sopenharmony_ci } else if (vsi->type == ICE_VSI_CTRL) { 25388c2ecf20Sopenharmony_ci ice_vsi_close(vsi); 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci} 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci/** 25438c2ecf20Sopenharmony_ci * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI 25448c2ecf20Sopenharmony_ci * @vsi: the VSI being un-configured 25458c2ecf20Sopenharmony_ci */ 25468c2ecf20Sopenharmony_civoid ice_vsi_dis_irq(struct ice_vsi *vsi) 25478c2ecf20Sopenharmony_ci{ 25488c2ecf20Sopenharmony_ci int base = vsi->base_vector; 25498c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 25508c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 25518c2ecf20Sopenharmony_ci u32 val; 25528c2ecf20Sopenharmony_ci int i; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci /* disable interrupt causation from each queue */ 25558c2ecf20Sopenharmony_ci if (vsi->tx_rings) { 25568c2ecf20Sopenharmony_ci ice_for_each_txq(vsi, i) { 25578c2ecf20Sopenharmony_ci if (vsi->tx_rings[i]) { 25588c2ecf20Sopenharmony_ci u16 reg; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci reg = vsi->tx_rings[i]->reg_idx; 25618c2ecf20Sopenharmony_ci val = rd32(hw, QINT_TQCTL(reg)); 25628c2ecf20Sopenharmony_ci val &= ~QINT_TQCTL_CAUSE_ENA_M; 25638c2ecf20Sopenharmony_ci wr32(hw, QINT_TQCTL(reg), val); 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci } 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci if (vsi->rx_rings) { 25698c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) { 25708c2ecf20Sopenharmony_ci if (vsi->rx_rings[i]) { 25718c2ecf20Sopenharmony_ci u16 reg; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci reg = vsi->rx_rings[i]->reg_idx; 25748c2ecf20Sopenharmony_ci val = rd32(hw, QINT_RQCTL(reg)); 25758c2ecf20Sopenharmony_ci val &= ~QINT_RQCTL_CAUSE_ENA_M; 25768c2ecf20Sopenharmony_ci wr32(hw, QINT_RQCTL(reg), val); 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci } 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci /* disable each interrupt */ 25828c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 25838c2ecf20Sopenharmony_ci if (!vsi->q_vectors[i]) 25848c2ecf20Sopenharmony_ci continue; 25858c2ecf20Sopenharmony_ci wr32(hw, GLINT_DYN_CTL(vsi->q_vectors[i]->reg_idx), 0); 25868c2ecf20Sopenharmony_ci } 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci ice_flush(hw); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci /* don't call synchronize_irq() for VF's from the host */ 25918c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 25928c2ecf20Sopenharmony_ci return; 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) 25958c2ecf20Sopenharmony_ci synchronize_irq(pf->msix_entries[i + base].vector); 25968c2ecf20Sopenharmony_ci} 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci/** 25998c2ecf20Sopenharmony_ci * ice_napi_del - Remove NAPI handler for the VSI 26008c2ecf20Sopenharmony_ci * @vsi: VSI for which NAPI handler is to be removed 26018c2ecf20Sopenharmony_ci */ 26028c2ecf20Sopenharmony_civoid ice_napi_del(struct ice_vsi *vsi) 26038c2ecf20Sopenharmony_ci{ 26048c2ecf20Sopenharmony_ci int v_idx; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci if (!vsi->netdev) 26078c2ecf20Sopenharmony_ci return; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, v_idx) 26108c2ecf20Sopenharmony_ci netif_napi_del(&vsi->q_vectors[v_idx]->napi); 26118c2ecf20Sopenharmony_ci} 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci/** 26148c2ecf20Sopenharmony_ci * ice_vsi_release - Delete a VSI and free its resources 26158c2ecf20Sopenharmony_ci * @vsi: the VSI being removed 26168c2ecf20Sopenharmony_ci * 26178c2ecf20Sopenharmony_ci * Returns 0 on success or < 0 on error 26188c2ecf20Sopenharmony_ci */ 26198c2ecf20Sopenharmony_ciint ice_vsi_release(struct ice_vsi *vsi) 26208c2ecf20Sopenharmony_ci{ 26218c2ecf20Sopenharmony_ci struct ice_pf *pf; 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci if (!vsi->back) 26248c2ecf20Sopenharmony_ci return -ENODEV; 26258c2ecf20Sopenharmony_ci pf = vsi->back; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci /* do not unregister while driver is in the reset recovery pending 26288c2ecf20Sopenharmony_ci * state. Since reset/rebuild happens through PF service task workqueue, 26298c2ecf20Sopenharmony_ci * it's not a good idea to unregister netdev that is associated to the 26308c2ecf20Sopenharmony_ci * PF that is running the work queue items currently. This is done to 26318c2ecf20Sopenharmony_ci * avoid check_flush_dependency() warning on this wq 26328c2ecf20Sopenharmony_ci */ 26338c2ecf20Sopenharmony_ci if (vsi->netdev && !ice_is_reset_in_progress(pf->state)) { 26348c2ecf20Sopenharmony_ci unregister_netdev(vsi->netdev); 26358c2ecf20Sopenharmony_ci ice_devlink_destroy_port(vsi); 26368c2ecf20Sopenharmony_ci } 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) 26398c2ecf20Sopenharmony_ci ice_rss_clean(vsi); 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci /* Disable VSI and free resources */ 26428c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_LB) 26438c2ecf20Sopenharmony_ci ice_vsi_dis_irq(vsi); 26448c2ecf20Sopenharmony_ci ice_vsi_close(vsi); 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci /* SR-IOV determines needed MSIX resources all at once instead of per 26478c2ecf20Sopenharmony_ci * VSI since when VFs are spawned we know how many VFs there are and how 26488c2ecf20Sopenharmony_ci * many interrupts each VF needs. SR-IOV MSIX resources are also 26498c2ecf20Sopenharmony_ci * cleared in the same manner. 26508c2ecf20Sopenharmony_ci */ 26518c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_VF) { 26528c2ecf20Sopenharmony_ci /* reclaim SW interrupts back to the common pool */ 26538c2ecf20Sopenharmony_ci ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx); 26548c2ecf20Sopenharmony_ci pf->num_avail_sw_msix += vsi->num_q_vectors; 26558c2ecf20Sopenharmony_ci } 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci if (!ice_is_safe_mode(pf)) { 26588c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 26598c2ecf20Sopenharmony_ci ice_fltr_remove_eth(vsi, ETH_P_PAUSE, ICE_FLTR_TX, 26608c2ecf20Sopenharmony_ci ICE_DROP_PACKET); 26618c2ecf20Sopenharmony_ci ice_cfg_sw_lldp(vsi, true, false); 26628c2ecf20Sopenharmony_ci /* The Rx rule will only exist to remove if the LLDP FW 26638c2ecf20Sopenharmony_ci * engine is currently stopped 26648c2ecf20Sopenharmony_ci */ 26658c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) 26668c2ecf20Sopenharmony_ci ice_cfg_sw_lldp(vsi, false, false); 26678c2ecf20Sopenharmony_ci } 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci if (ice_is_vsi_dflt_vsi(pf->first_sw, vsi)) 26718c2ecf20Sopenharmony_ci ice_clear_dflt_vsi(pf->first_sw); 26728c2ecf20Sopenharmony_ci ice_fltr_remove_all(vsi); 26738c2ecf20Sopenharmony_ci ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx); 26748c2ecf20Sopenharmony_ci ice_vsi_delete(vsi); 26758c2ecf20Sopenharmony_ci ice_vsi_free_q_vectors(vsi); 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci /* make sure unregister_netdev() was called by checking __ICE_DOWN */ 26788c2ecf20Sopenharmony_ci if (vsi->netdev && test_bit(__ICE_DOWN, vsi->state)) { 26798c2ecf20Sopenharmony_ci free_netdev(vsi->netdev); 26808c2ecf20Sopenharmony_ci vsi->netdev = NULL; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci ice_vsi_clear_rings(vsi); 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci ice_vsi_put_qs(vsi); 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci /* retain SW VSI data structure since it is needed to unregister and 26888c2ecf20Sopenharmony_ci * free VSI netdev when PF is not in reset recovery pending state,\ 26898c2ecf20Sopenharmony_ci * for ex: during rmmod. 26908c2ecf20Sopenharmony_ci */ 26918c2ecf20Sopenharmony_ci if (!ice_is_reset_in_progress(pf->state)) 26928c2ecf20Sopenharmony_ci ice_vsi_clear(vsi); 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci return 0; 26958c2ecf20Sopenharmony_ci} 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci/** 26988c2ecf20Sopenharmony_ci * ice_vsi_rebuild_update_coalesce_intrl - set interrupt rate limit for a q_vector 26998c2ecf20Sopenharmony_ci * @q_vector: pointer to q_vector which is being updated 27008c2ecf20Sopenharmony_ci * @stored_intrl_setting: original INTRL setting 27018c2ecf20Sopenharmony_ci * 27028c2ecf20Sopenharmony_ci * Set coalesce param in q_vector and update these parameters in HW. 27038c2ecf20Sopenharmony_ci */ 27048c2ecf20Sopenharmony_cistatic void 27058c2ecf20Sopenharmony_ciice_vsi_rebuild_update_coalesce_intrl(struct ice_q_vector *q_vector, 27068c2ecf20Sopenharmony_ci u16 stored_intrl_setting) 27078c2ecf20Sopenharmony_ci{ 27088c2ecf20Sopenharmony_ci struct ice_hw *hw = &q_vector->vsi->back->hw; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci q_vector->intrl = stored_intrl_setting; 27118c2ecf20Sopenharmony_ci wr32(hw, GLINT_RATE(q_vector->reg_idx), 27128c2ecf20Sopenharmony_ci ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); 27138c2ecf20Sopenharmony_ci} 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci/** 27168c2ecf20Sopenharmony_ci * ice_vsi_rebuild_update_coalesce_itr - set coalesce for a q_vector 27178c2ecf20Sopenharmony_ci * @q_vector: pointer to q_vector which is being updated 27188c2ecf20Sopenharmony_ci * @rc: pointer to ring container 27198c2ecf20Sopenharmony_ci * @stored_itr_setting: original ITR setting 27208c2ecf20Sopenharmony_ci * 27218c2ecf20Sopenharmony_ci * Set coalesce param in q_vector and update these parameters in HW. 27228c2ecf20Sopenharmony_ci */ 27238c2ecf20Sopenharmony_cistatic void 27248c2ecf20Sopenharmony_ciice_vsi_rebuild_update_coalesce_itr(struct ice_q_vector *q_vector, 27258c2ecf20Sopenharmony_ci struct ice_ring_container *rc, 27268c2ecf20Sopenharmony_ci u16 stored_itr_setting) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci struct ice_hw *hw = &q_vector->vsi->back->hw; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci rc->itr_setting = stored_itr_setting; 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci /* dynamic ITR values will be updated during Tx/Rx */ 27338c2ecf20Sopenharmony_ci if (!ITR_IS_DYNAMIC(rc->itr_setting)) 27348c2ecf20Sopenharmony_ci wr32(hw, GLINT_ITR(rc->itr_idx, q_vector->reg_idx), 27358c2ecf20Sopenharmony_ci ITR_REG_ALIGN(rc->itr_setting) >> ICE_ITR_GRAN_S); 27368c2ecf20Sopenharmony_ci} 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci/** 27398c2ecf20Sopenharmony_ci * ice_vsi_rebuild_get_coalesce - get coalesce from all q_vectors 27408c2ecf20Sopenharmony_ci * @vsi: VSI connected with q_vectors 27418c2ecf20Sopenharmony_ci * @coalesce: array of struct with stored coalesce 27428c2ecf20Sopenharmony_ci * 27438c2ecf20Sopenharmony_ci * Returns array size. 27448c2ecf20Sopenharmony_ci */ 27458c2ecf20Sopenharmony_cistatic int 27468c2ecf20Sopenharmony_ciice_vsi_rebuild_get_coalesce(struct ice_vsi *vsi, 27478c2ecf20Sopenharmony_ci struct ice_coalesce_stored *coalesce) 27488c2ecf20Sopenharmony_ci{ 27498c2ecf20Sopenharmony_ci int i; 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 27528c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci coalesce[i].itr_tx = q_vector->tx.itr_setting; 27558c2ecf20Sopenharmony_ci coalesce[i].itr_rx = q_vector->rx.itr_setting; 27568c2ecf20Sopenharmony_ci coalesce[i].intrl = q_vector->intrl; 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci if (i < vsi->num_txq) 27598c2ecf20Sopenharmony_ci coalesce[i].tx_valid = true; 27608c2ecf20Sopenharmony_ci if (i < vsi->num_rxq) 27618c2ecf20Sopenharmony_ci coalesce[i].rx_valid = true; 27628c2ecf20Sopenharmony_ci } 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci return vsi->num_q_vectors; 27658c2ecf20Sopenharmony_ci} 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci/** 27688c2ecf20Sopenharmony_ci * ice_vsi_rebuild_set_coalesce - set coalesce from earlier saved arrays 27698c2ecf20Sopenharmony_ci * @vsi: VSI connected with q_vectors 27708c2ecf20Sopenharmony_ci * @coalesce: pointer to array of struct with stored coalesce 27718c2ecf20Sopenharmony_ci * @size: size of coalesce array 27728c2ecf20Sopenharmony_ci * 27738c2ecf20Sopenharmony_ci * Before this function, ice_vsi_rebuild_get_coalesce should be called to save 27748c2ecf20Sopenharmony_ci * ITR params in arrays. If size is 0 or coalesce wasn't stored set coalesce 27758c2ecf20Sopenharmony_ci * to default value. 27768c2ecf20Sopenharmony_ci */ 27778c2ecf20Sopenharmony_cistatic void 27788c2ecf20Sopenharmony_ciice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, 27798c2ecf20Sopenharmony_ci struct ice_coalesce_stored *coalesce, int size) 27808c2ecf20Sopenharmony_ci{ 27818c2ecf20Sopenharmony_ci int i; 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci if ((size && !coalesce) || !vsi) 27848c2ecf20Sopenharmony_ci return; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci /* There are a couple of cases that have to be handled here: 27878c2ecf20Sopenharmony_ci * 1. The case where the number of queue vectors stays the same, but 27888c2ecf20Sopenharmony_ci * the number of Tx or Rx rings changes (the first for loop) 27898c2ecf20Sopenharmony_ci * 2. The case where the number of queue vectors increased (the 27908c2ecf20Sopenharmony_ci * second for loop) 27918c2ecf20Sopenharmony_ci */ 27928c2ecf20Sopenharmony_ci for (i = 0; i < size && i < vsi->num_q_vectors; i++) { 27938c2ecf20Sopenharmony_ci /* There are 2 cases to handle here and they are the same for 27948c2ecf20Sopenharmony_ci * both Tx and Rx: 27958c2ecf20Sopenharmony_ci * if the entry was valid previously (coalesce[i].[tr]x_valid 27968c2ecf20Sopenharmony_ci * and the loop variable is less than the number of rings 27978c2ecf20Sopenharmony_ci * allocated, then write the previous values 27988c2ecf20Sopenharmony_ci * 27998c2ecf20Sopenharmony_ci * if the entry was not valid previously, but the number of 28008c2ecf20Sopenharmony_ci * rings is less than are allocated (this means the number of 28018c2ecf20Sopenharmony_ci * rings increased from previously), then write out the 28028c2ecf20Sopenharmony_ci * values in the first element 28038c2ecf20Sopenharmony_ci */ 28048c2ecf20Sopenharmony_ci if (i < vsi->alloc_rxq && coalesce[i].rx_valid) 28058c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_itr(vsi->q_vectors[i], 28068c2ecf20Sopenharmony_ci &vsi->q_vectors[i]->rx, 28078c2ecf20Sopenharmony_ci coalesce[i].itr_rx); 28088c2ecf20Sopenharmony_ci else if (i < vsi->alloc_rxq) 28098c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_itr(vsi->q_vectors[i], 28108c2ecf20Sopenharmony_ci &vsi->q_vectors[i]->rx, 28118c2ecf20Sopenharmony_ci coalesce[0].itr_rx); 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci if (i < vsi->alloc_txq && coalesce[i].tx_valid) 28148c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_itr(vsi->q_vectors[i], 28158c2ecf20Sopenharmony_ci &vsi->q_vectors[i]->tx, 28168c2ecf20Sopenharmony_ci coalesce[i].itr_tx); 28178c2ecf20Sopenharmony_ci else if (i < vsi->alloc_txq) 28188c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_itr(vsi->q_vectors[i], 28198c2ecf20Sopenharmony_ci &vsi->q_vectors[i]->tx, 28208c2ecf20Sopenharmony_ci coalesce[0].itr_tx); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_intrl(vsi->q_vectors[i], 28238c2ecf20Sopenharmony_ci coalesce[i].intrl); 28248c2ecf20Sopenharmony_ci } 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci /* the number of queue vectors increased so write whatever is in 28278c2ecf20Sopenharmony_ci * the first element 28288c2ecf20Sopenharmony_ci */ 28298c2ecf20Sopenharmony_ci for (; i < vsi->num_q_vectors; i++) { 28308c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_itr(vsi->q_vectors[i], 28318c2ecf20Sopenharmony_ci &vsi->q_vectors[i]->tx, 28328c2ecf20Sopenharmony_ci coalesce[0].itr_tx); 28338c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_itr(vsi->q_vectors[i], 28348c2ecf20Sopenharmony_ci &vsi->q_vectors[i]->rx, 28358c2ecf20Sopenharmony_ci coalesce[0].itr_rx); 28368c2ecf20Sopenharmony_ci ice_vsi_rebuild_update_coalesce_intrl(vsi->q_vectors[i], 28378c2ecf20Sopenharmony_ci coalesce[0].intrl); 28388c2ecf20Sopenharmony_ci } 28398c2ecf20Sopenharmony_ci} 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci/** 28428c2ecf20Sopenharmony_ci * ice_vsi_rebuild - Rebuild VSI after reset 28438c2ecf20Sopenharmony_ci * @vsi: VSI to be rebuild 28448c2ecf20Sopenharmony_ci * @init_vsi: is this an initialization or a reconfigure of the VSI 28458c2ecf20Sopenharmony_ci * 28468c2ecf20Sopenharmony_ci * Returns 0 on success and negative value on failure 28478c2ecf20Sopenharmony_ci */ 28488c2ecf20Sopenharmony_ciint ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) 28498c2ecf20Sopenharmony_ci{ 28508c2ecf20Sopenharmony_ci u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 28518c2ecf20Sopenharmony_ci struct ice_coalesce_stored *coalesce; 28528c2ecf20Sopenharmony_ci int prev_num_q_vectors = 0; 28538c2ecf20Sopenharmony_ci struct ice_vf *vf = NULL; 28548c2ecf20Sopenharmony_ci enum ice_status status; 28558c2ecf20Sopenharmony_ci struct ice_pf *pf; 28568c2ecf20Sopenharmony_ci int ret, i; 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci if (!vsi) 28598c2ecf20Sopenharmony_ci return -EINVAL; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci pf = vsi->back; 28628c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 28638c2ecf20Sopenharmony_ci vf = &pf->vf[vsi->vf_id]; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci coalesce = kcalloc(vsi->num_q_vectors, 28668c2ecf20Sopenharmony_ci sizeof(struct ice_coalesce_stored), GFP_KERNEL); 28678c2ecf20Sopenharmony_ci if (!coalesce) 28688c2ecf20Sopenharmony_ci return -ENOMEM; 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi, coalesce); 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx); 28738c2ecf20Sopenharmony_ci ice_vsi_free_q_vectors(vsi); 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci /* SR-IOV determines needed MSIX resources all at once instead of per 28768c2ecf20Sopenharmony_ci * VSI since when VFs are spawned we know how many VFs there are and how 28778c2ecf20Sopenharmony_ci * many interrupts each VF needs. SR-IOV MSIX resources are also 28788c2ecf20Sopenharmony_ci * cleared in the same manner. 28798c2ecf20Sopenharmony_ci */ 28808c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_VF) { 28818c2ecf20Sopenharmony_ci /* reclaim SW interrupts back to the common pool */ 28828c2ecf20Sopenharmony_ci ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx); 28838c2ecf20Sopenharmony_ci pf->num_avail_sw_msix += vsi->num_q_vectors; 28848c2ecf20Sopenharmony_ci vsi->base_vector = 0; 28858c2ecf20Sopenharmony_ci } 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) 28888c2ecf20Sopenharmony_ci /* return value check can be skipped here, it always returns 28898c2ecf20Sopenharmony_ci * 0 if reset is in progress 28908c2ecf20Sopenharmony_ci */ 28918c2ecf20Sopenharmony_ci ice_destroy_xdp_rings(vsi); 28928c2ecf20Sopenharmony_ci ice_vsi_put_qs(vsi); 28938c2ecf20Sopenharmony_ci ice_vsi_clear_rings(vsi); 28948c2ecf20Sopenharmony_ci ice_vsi_free_arrays(vsi); 28958c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 28968c2ecf20Sopenharmony_ci ice_vsi_set_num_qs(vsi, vf->vf_id); 28978c2ecf20Sopenharmony_ci else 28988c2ecf20Sopenharmony_ci ice_vsi_set_num_qs(vsi, ICE_INVAL_VFID); 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_arrays(vsi); 29018c2ecf20Sopenharmony_ci if (ret < 0) 29028c2ecf20Sopenharmony_ci goto err_vsi; 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci ice_vsi_get_qs(vsi); 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci ice_alloc_fd_res(vsi); 29078c2ecf20Sopenharmony_ci ice_vsi_set_tc_cfg(vsi); 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci /* Initialize VSI struct elements and create VSI in FW */ 29108c2ecf20Sopenharmony_ci ret = ice_vsi_init(vsi, init_vsi); 29118c2ecf20Sopenharmony_ci if (ret < 0) 29128c2ecf20Sopenharmony_ci goto err_vsi; 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci switch (vsi->type) { 29158c2ecf20Sopenharmony_ci case ICE_VSI_CTRL: 29168c2ecf20Sopenharmony_ci case ICE_VSI_PF: 29178c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_q_vectors(vsi); 29188c2ecf20Sopenharmony_ci if (ret) 29198c2ecf20Sopenharmony_ci goto err_rings; 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci ret = ice_vsi_setup_vector_base(vsi); 29228c2ecf20Sopenharmony_ci if (ret) 29238c2ecf20Sopenharmony_ci goto err_vectors; 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci ret = ice_vsi_set_q_vectors_reg_idx(vsi); 29268c2ecf20Sopenharmony_ci if (ret) 29278c2ecf20Sopenharmony_ci goto err_vectors; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 29308c2ecf20Sopenharmony_ci if (ret) 29318c2ecf20Sopenharmony_ci goto err_vectors; 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci ice_vsi_map_rings_to_vectors(vsi); 29348c2ecf20Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) { 29358c2ecf20Sopenharmony_ci vsi->num_xdp_txq = vsi->alloc_rxq; 29368c2ecf20Sopenharmony_ci ret = ice_prepare_xdp_rings(vsi, vsi->xdp_prog); 29378c2ecf20Sopenharmony_ci if (ret) 29388c2ecf20Sopenharmony_ci goto err_vectors; 29398c2ecf20Sopenharmony_ci } 29408c2ecf20Sopenharmony_ci /* ICE_VSI_CTRL does not need RSS so skip RSS processing */ 29418c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_CTRL) 29428c2ecf20Sopenharmony_ci /* Do not exit if configuring RSS had an issue, at 29438c2ecf20Sopenharmony_ci * least receive traffic on first queue. Hence no 29448c2ecf20Sopenharmony_ci * need to capture return value 29458c2ecf20Sopenharmony_ci */ 29468c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) 29478c2ecf20Sopenharmony_ci ice_vsi_cfg_rss_lut_key(vsi); 29488c2ecf20Sopenharmony_ci break; 29498c2ecf20Sopenharmony_ci case ICE_VSI_VF: 29508c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_q_vectors(vsi); 29518c2ecf20Sopenharmony_ci if (ret) 29528c2ecf20Sopenharmony_ci goto err_rings; 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ci ret = ice_vsi_set_q_vectors_reg_idx(vsi); 29558c2ecf20Sopenharmony_ci if (ret) 29568c2ecf20Sopenharmony_ci goto err_vectors; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 29598c2ecf20Sopenharmony_ci if (ret) 29608c2ecf20Sopenharmony_ci goto err_vectors; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci break; 29638c2ecf20Sopenharmony_ci default: 29648c2ecf20Sopenharmony_ci break; 29658c2ecf20Sopenharmony_ci } 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci /* configure VSI nodes based on number of queues and TC's */ 29688c2ecf20Sopenharmony_ci for (i = 0; i < vsi->tc_cfg.numtc; i++) { 29698c2ecf20Sopenharmony_ci max_txqs[i] = vsi->alloc_txq; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) 29728c2ecf20Sopenharmony_ci max_txqs[i] += vsi->num_xdp_txq; 29738c2ecf20Sopenharmony_ci } 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, 29768c2ecf20Sopenharmony_ci max_txqs); 29778c2ecf20Sopenharmony_ci if (status) { 29788c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "VSI %d failed lan queue config, error %s\n", 29798c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 29808c2ecf20Sopenharmony_ci if (init_vsi) { 29818c2ecf20Sopenharmony_ci ret = -EIO; 29828c2ecf20Sopenharmony_ci goto err_vectors; 29838c2ecf20Sopenharmony_ci } else { 29848c2ecf20Sopenharmony_ci return ice_schedule_reset(pf, ICE_RESET_PFR); 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci } 29878c2ecf20Sopenharmony_ci ice_vsi_rebuild_set_coalesce(vsi, coalesce, prev_num_q_vectors); 29888c2ecf20Sopenharmony_ci kfree(coalesce); 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci return 0; 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_cierr_vectors: 29938c2ecf20Sopenharmony_ci ice_vsi_free_q_vectors(vsi); 29948c2ecf20Sopenharmony_cierr_rings: 29958c2ecf20Sopenharmony_ci if (vsi->netdev) { 29968c2ecf20Sopenharmony_ci vsi->current_netdev_flags = 0; 29978c2ecf20Sopenharmony_ci unregister_netdev(vsi->netdev); 29988c2ecf20Sopenharmony_ci free_netdev(vsi->netdev); 29998c2ecf20Sopenharmony_ci vsi->netdev = NULL; 30008c2ecf20Sopenharmony_ci } 30018c2ecf20Sopenharmony_cierr_vsi: 30028c2ecf20Sopenharmony_ci ice_vsi_clear(vsi); 30038c2ecf20Sopenharmony_ci set_bit(__ICE_RESET_FAILED, pf->state); 30048c2ecf20Sopenharmony_ci kfree(coalesce); 30058c2ecf20Sopenharmony_ci return ret; 30068c2ecf20Sopenharmony_ci} 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci/** 30098c2ecf20Sopenharmony_ci * ice_is_reset_in_progress - check for a reset in progress 30108c2ecf20Sopenharmony_ci * @state: PF state field 30118c2ecf20Sopenharmony_ci */ 30128c2ecf20Sopenharmony_cibool ice_is_reset_in_progress(unsigned long *state) 30138c2ecf20Sopenharmony_ci{ 30148c2ecf20Sopenharmony_ci return test_bit(__ICE_RESET_OICR_RECV, state) || 30158c2ecf20Sopenharmony_ci test_bit(__ICE_PFR_REQ, state) || 30168c2ecf20Sopenharmony_ci test_bit(__ICE_CORER_REQ, state) || 30178c2ecf20Sopenharmony_ci test_bit(__ICE_GLOBR_REQ, state); 30188c2ecf20Sopenharmony_ci} 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci#ifdef CONFIG_DCB 30218c2ecf20Sopenharmony_ci/** 30228c2ecf20Sopenharmony_ci * ice_vsi_update_q_map - update our copy of the VSI info with new queue map 30238c2ecf20Sopenharmony_ci * @vsi: VSI being configured 30248c2ecf20Sopenharmony_ci * @ctx: the context buffer returned from AQ VSI update command 30258c2ecf20Sopenharmony_ci */ 30268c2ecf20Sopenharmony_cistatic void ice_vsi_update_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctx) 30278c2ecf20Sopenharmony_ci{ 30288c2ecf20Sopenharmony_ci vsi->info.mapping_flags = ctx->info.mapping_flags; 30298c2ecf20Sopenharmony_ci memcpy(&vsi->info.q_mapping, &ctx->info.q_mapping, 30308c2ecf20Sopenharmony_ci sizeof(vsi->info.q_mapping)); 30318c2ecf20Sopenharmony_ci memcpy(&vsi->info.tc_mapping, ctx->info.tc_mapping, 30328c2ecf20Sopenharmony_ci sizeof(vsi->info.tc_mapping)); 30338c2ecf20Sopenharmony_ci} 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci/** 30368c2ecf20Sopenharmony_ci * ice_vsi_cfg_tc - Configure VSI Tx Sched for given TC map 30378c2ecf20Sopenharmony_ci * @vsi: VSI to be configured 30388c2ecf20Sopenharmony_ci * @ena_tc: TC bitmap 30398c2ecf20Sopenharmony_ci * 30408c2ecf20Sopenharmony_ci * VSI queues expected to be quiesced before calling this function 30418c2ecf20Sopenharmony_ci */ 30428c2ecf20Sopenharmony_ciint ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc) 30438c2ecf20Sopenharmony_ci{ 30448c2ecf20Sopenharmony_ci u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 30458c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 30468c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctx; 30478c2ecf20Sopenharmony_ci enum ice_status status; 30488c2ecf20Sopenharmony_ci struct device *dev; 30498c2ecf20Sopenharmony_ci int i, ret = 0; 30508c2ecf20Sopenharmony_ci u8 num_tc = 0; 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci ice_for_each_traffic_class(i) { 30558c2ecf20Sopenharmony_ci /* build bitmap of enabled TCs */ 30568c2ecf20Sopenharmony_ci if (ena_tc & BIT(i)) 30578c2ecf20Sopenharmony_ci num_tc++; 30588c2ecf20Sopenharmony_ci /* populate max_txqs per TC */ 30598c2ecf20Sopenharmony_ci max_txqs[i] = vsi->alloc_txq; 30608c2ecf20Sopenharmony_ci } 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci vsi->tc_cfg.ena_tc = ena_tc; 30638c2ecf20Sopenharmony_ci vsi->tc_cfg.numtc = num_tc; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 30668c2ecf20Sopenharmony_ci if (!ctx) 30678c2ecf20Sopenharmony_ci return -ENOMEM; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci ctx->vf_num = 0; 30708c2ecf20Sopenharmony_ci ctx->info = vsi->info; 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci ice_vsi_setup_q_map(vsi, ctx); 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci /* must to indicate which section of VSI context are being modified */ 30758c2ecf20Sopenharmony_ci ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID); 30768c2ecf20Sopenharmony_ci status = ice_update_vsi(&pf->hw, vsi->idx, ctx, NULL); 30778c2ecf20Sopenharmony_ci if (status) { 30788c2ecf20Sopenharmony_ci dev_info(dev, "Failed VSI Update\n"); 30798c2ecf20Sopenharmony_ci ret = -EIO; 30808c2ecf20Sopenharmony_ci goto out; 30818c2ecf20Sopenharmony_ci } 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, 30848c2ecf20Sopenharmony_ci max_txqs); 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci if (status) { 30878c2ecf20Sopenharmony_ci dev_err(dev, "VSI %d failed TC config, error %s\n", 30888c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 30898c2ecf20Sopenharmony_ci ret = -EIO; 30908c2ecf20Sopenharmony_ci goto out; 30918c2ecf20Sopenharmony_ci } 30928c2ecf20Sopenharmony_ci ice_vsi_update_q_map(vsi, ctx); 30938c2ecf20Sopenharmony_ci vsi->info.valid_sections = 0; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci ice_vsi_cfg_netdev_tc(vsi, ena_tc); 30968c2ecf20Sopenharmony_ciout: 30978c2ecf20Sopenharmony_ci kfree(ctx); 30988c2ecf20Sopenharmony_ci return ret; 30998c2ecf20Sopenharmony_ci} 31008c2ecf20Sopenharmony_ci#endif /* CONFIG_DCB */ 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci/** 31038c2ecf20Sopenharmony_ci * ice_update_ring_stats - Update ring statistics 31048c2ecf20Sopenharmony_ci * @ring: ring to update 31058c2ecf20Sopenharmony_ci * @cont: used to increment per-vector counters 31068c2ecf20Sopenharmony_ci * @pkts: number of processed packets 31078c2ecf20Sopenharmony_ci * @bytes: number of processed bytes 31088c2ecf20Sopenharmony_ci * 31098c2ecf20Sopenharmony_ci * This function assumes that caller has acquired a u64_stats_sync lock. 31108c2ecf20Sopenharmony_ci */ 31118c2ecf20Sopenharmony_cistatic void 31128c2ecf20Sopenharmony_ciice_update_ring_stats(struct ice_ring *ring, struct ice_ring_container *cont, 31138c2ecf20Sopenharmony_ci u64 pkts, u64 bytes) 31148c2ecf20Sopenharmony_ci{ 31158c2ecf20Sopenharmony_ci ring->stats.bytes += bytes; 31168c2ecf20Sopenharmony_ci ring->stats.pkts += pkts; 31178c2ecf20Sopenharmony_ci cont->total_bytes += bytes; 31188c2ecf20Sopenharmony_ci cont->total_pkts += pkts; 31198c2ecf20Sopenharmony_ci} 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci/** 31228c2ecf20Sopenharmony_ci * ice_update_tx_ring_stats - Update Tx ring specific counters 31238c2ecf20Sopenharmony_ci * @tx_ring: ring to update 31248c2ecf20Sopenharmony_ci * @pkts: number of processed packets 31258c2ecf20Sopenharmony_ci * @bytes: number of processed bytes 31268c2ecf20Sopenharmony_ci */ 31278c2ecf20Sopenharmony_civoid ice_update_tx_ring_stats(struct ice_ring *tx_ring, u64 pkts, u64 bytes) 31288c2ecf20Sopenharmony_ci{ 31298c2ecf20Sopenharmony_ci u64_stats_update_begin(&tx_ring->syncp); 31308c2ecf20Sopenharmony_ci ice_update_ring_stats(tx_ring, &tx_ring->q_vector->tx, pkts, bytes); 31318c2ecf20Sopenharmony_ci u64_stats_update_end(&tx_ring->syncp); 31328c2ecf20Sopenharmony_ci} 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci/** 31358c2ecf20Sopenharmony_ci * ice_update_rx_ring_stats - Update Rx ring specific counters 31368c2ecf20Sopenharmony_ci * @rx_ring: ring to update 31378c2ecf20Sopenharmony_ci * @pkts: number of processed packets 31388c2ecf20Sopenharmony_ci * @bytes: number of processed bytes 31398c2ecf20Sopenharmony_ci */ 31408c2ecf20Sopenharmony_civoid ice_update_rx_ring_stats(struct ice_ring *rx_ring, u64 pkts, u64 bytes) 31418c2ecf20Sopenharmony_ci{ 31428c2ecf20Sopenharmony_ci u64_stats_update_begin(&rx_ring->syncp); 31438c2ecf20Sopenharmony_ci ice_update_ring_stats(rx_ring, &rx_ring->q_vector->rx, pkts, bytes); 31448c2ecf20Sopenharmony_ci u64_stats_update_end(&rx_ring->syncp); 31458c2ecf20Sopenharmony_ci} 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci/** 31488c2ecf20Sopenharmony_ci * ice_status_to_errno - convert from enum ice_status to Linux errno 31498c2ecf20Sopenharmony_ci * @err: ice_status value to convert 31508c2ecf20Sopenharmony_ci */ 31518c2ecf20Sopenharmony_ciint ice_status_to_errno(enum ice_status err) 31528c2ecf20Sopenharmony_ci{ 31538c2ecf20Sopenharmony_ci switch (err) { 31548c2ecf20Sopenharmony_ci case ICE_SUCCESS: 31558c2ecf20Sopenharmony_ci return 0; 31568c2ecf20Sopenharmony_ci case ICE_ERR_DOES_NOT_EXIST: 31578c2ecf20Sopenharmony_ci return -ENOENT; 31588c2ecf20Sopenharmony_ci case ICE_ERR_OUT_OF_RANGE: 31598c2ecf20Sopenharmony_ci return -ENOTTY; 31608c2ecf20Sopenharmony_ci case ICE_ERR_PARAM: 31618c2ecf20Sopenharmony_ci return -EINVAL; 31628c2ecf20Sopenharmony_ci case ICE_ERR_NO_MEMORY: 31638c2ecf20Sopenharmony_ci return -ENOMEM; 31648c2ecf20Sopenharmony_ci case ICE_ERR_MAX_LIMIT: 31658c2ecf20Sopenharmony_ci return -EAGAIN; 31668c2ecf20Sopenharmony_ci default: 31678c2ecf20Sopenharmony_ci return -EINVAL; 31688c2ecf20Sopenharmony_ci } 31698c2ecf20Sopenharmony_ci} 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci/** 31728c2ecf20Sopenharmony_ci * ice_is_dflt_vsi_in_use - check if the default forwarding VSI is being used 31738c2ecf20Sopenharmony_ci * @sw: switch to check if its default forwarding VSI is free 31748c2ecf20Sopenharmony_ci * 31758c2ecf20Sopenharmony_ci * Return true if the default forwarding VSI is already being used, else returns 31768c2ecf20Sopenharmony_ci * false signalling that it's available to use. 31778c2ecf20Sopenharmony_ci */ 31788c2ecf20Sopenharmony_cibool ice_is_dflt_vsi_in_use(struct ice_sw *sw) 31798c2ecf20Sopenharmony_ci{ 31808c2ecf20Sopenharmony_ci return (sw->dflt_vsi && sw->dflt_vsi_ena); 31818c2ecf20Sopenharmony_ci} 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci/** 31848c2ecf20Sopenharmony_ci * ice_is_vsi_dflt_vsi - check if the VSI passed in is the default VSI 31858c2ecf20Sopenharmony_ci * @sw: switch for the default forwarding VSI to compare against 31868c2ecf20Sopenharmony_ci * @vsi: VSI to compare against default forwarding VSI 31878c2ecf20Sopenharmony_ci * 31888c2ecf20Sopenharmony_ci * If this VSI passed in is the default forwarding VSI then return true, else 31898c2ecf20Sopenharmony_ci * return false 31908c2ecf20Sopenharmony_ci */ 31918c2ecf20Sopenharmony_cibool ice_is_vsi_dflt_vsi(struct ice_sw *sw, struct ice_vsi *vsi) 31928c2ecf20Sopenharmony_ci{ 31938c2ecf20Sopenharmony_ci return (sw->dflt_vsi == vsi && sw->dflt_vsi_ena); 31948c2ecf20Sopenharmony_ci} 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci/** 31978c2ecf20Sopenharmony_ci * ice_set_dflt_vsi - set the default forwarding VSI 31988c2ecf20Sopenharmony_ci * @sw: switch used to assign the default forwarding VSI 31998c2ecf20Sopenharmony_ci * @vsi: VSI getting set as the default forwarding VSI on the switch 32008c2ecf20Sopenharmony_ci * 32018c2ecf20Sopenharmony_ci * If the VSI passed in is already the default VSI and it's enabled just return 32028c2ecf20Sopenharmony_ci * success. 32038c2ecf20Sopenharmony_ci * 32048c2ecf20Sopenharmony_ci * If there is already a default VSI on the switch and it's enabled then return 32058c2ecf20Sopenharmony_ci * -EEXIST since there can only be one default VSI per switch. 32068c2ecf20Sopenharmony_ci * 32078c2ecf20Sopenharmony_ci * Otherwise try to set the VSI passed in as the switch's default VSI and 32088c2ecf20Sopenharmony_ci * return the result. 32098c2ecf20Sopenharmony_ci */ 32108c2ecf20Sopenharmony_ciint ice_set_dflt_vsi(struct ice_sw *sw, struct ice_vsi *vsi) 32118c2ecf20Sopenharmony_ci{ 32128c2ecf20Sopenharmony_ci enum ice_status status; 32138c2ecf20Sopenharmony_ci struct device *dev; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci if (!sw || !vsi) 32168c2ecf20Sopenharmony_ci return -EINVAL; 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci /* the VSI passed in is already the default VSI */ 32218c2ecf20Sopenharmony_ci if (ice_is_vsi_dflt_vsi(sw, vsi)) { 32228c2ecf20Sopenharmony_ci dev_dbg(dev, "VSI %d passed in is already the default forwarding VSI, nothing to do\n", 32238c2ecf20Sopenharmony_ci vsi->vsi_num); 32248c2ecf20Sopenharmony_ci return 0; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci /* another VSI is already the default VSI for this switch */ 32288c2ecf20Sopenharmony_ci if (ice_is_dflt_vsi_in_use(sw)) { 32298c2ecf20Sopenharmony_ci dev_err(dev, "Default forwarding VSI %d already in use, disable it and try again\n", 32308c2ecf20Sopenharmony_ci sw->dflt_vsi->vsi_num); 32318c2ecf20Sopenharmony_ci return -EEXIST; 32328c2ecf20Sopenharmony_ci } 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci status = ice_cfg_dflt_vsi(&vsi->back->hw, vsi->idx, true, ICE_FLTR_RX); 32358c2ecf20Sopenharmony_ci if (status) { 32368c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set VSI %d as the default forwarding VSI, error %s\n", 32378c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 32388c2ecf20Sopenharmony_ci return -EIO; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci sw->dflt_vsi = vsi; 32428c2ecf20Sopenharmony_ci sw->dflt_vsi_ena = true; 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci return 0; 32458c2ecf20Sopenharmony_ci} 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci/** 32488c2ecf20Sopenharmony_ci * ice_clear_dflt_vsi - clear the default forwarding VSI 32498c2ecf20Sopenharmony_ci * @sw: switch used to clear the default VSI 32508c2ecf20Sopenharmony_ci * 32518c2ecf20Sopenharmony_ci * If the switch has no default VSI or it's not enabled then return error. 32528c2ecf20Sopenharmony_ci * 32538c2ecf20Sopenharmony_ci * Otherwise try to clear the default VSI and return the result. 32548c2ecf20Sopenharmony_ci */ 32558c2ecf20Sopenharmony_ciint ice_clear_dflt_vsi(struct ice_sw *sw) 32568c2ecf20Sopenharmony_ci{ 32578c2ecf20Sopenharmony_ci struct ice_vsi *dflt_vsi; 32588c2ecf20Sopenharmony_ci enum ice_status status; 32598c2ecf20Sopenharmony_ci struct device *dev; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci if (!sw) 32628c2ecf20Sopenharmony_ci return -EINVAL; 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(sw->pf); 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci dflt_vsi = sw->dflt_vsi; 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci /* there is no default VSI configured */ 32698c2ecf20Sopenharmony_ci if (!ice_is_dflt_vsi_in_use(sw)) 32708c2ecf20Sopenharmony_ci return -ENODEV; 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci status = ice_cfg_dflt_vsi(&dflt_vsi->back->hw, dflt_vsi->idx, false, 32738c2ecf20Sopenharmony_ci ICE_FLTR_RX); 32748c2ecf20Sopenharmony_ci if (status) { 32758c2ecf20Sopenharmony_ci dev_err(dev, "Failed to clear the default forwarding VSI %d, error %s\n", 32768c2ecf20Sopenharmony_ci dflt_vsi->vsi_num, ice_stat_str(status)); 32778c2ecf20Sopenharmony_ci return -EIO; 32788c2ecf20Sopenharmony_ci } 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci sw->dflt_vsi = NULL; 32818c2ecf20Sopenharmony_ci sw->dflt_vsi_ena = false; 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci return 0; 32848c2ecf20Sopenharmony_ci} 3285