162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "ice.h" 562306a36Sopenharmony_ci#include "ice_base.h" 662306a36Sopenharmony_ci#include "ice_flow.h" 762306a36Sopenharmony_ci#include "ice_lib.h" 862306a36Sopenharmony_ci#include "ice_fltr.h" 962306a36Sopenharmony_ci#include "ice_dcb_lib.h" 1062306a36Sopenharmony_ci#include "ice_devlink.h" 1162306a36Sopenharmony_ci#include "ice_vsi_vlan_ops.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/** 1462306a36Sopenharmony_ci * ice_vsi_type_str - maps VSI type enum to string equivalents 1562306a36Sopenharmony_ci * @vsi_type: VSI type enum 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ciconst char *ice_vsi_type_str(enum ice_vsi_type vsi_type) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci switch (vsi_type) { 2062306a36Sopenharmony_ci case ICE_VSI_PF: 2162306a36Sopenharmony_ci return "ICE_VSI_PF"; 2262306a36Sopenharmony_ci case ICE_VSI_VF: 2362306a36Sopenharmony_ci return "ICE_VSI_VF"; 2462306a36Sopenharmony_ci case ICE_VSI_CTRL: 2562306a36Sopenharmony_ci return "ICE_VSI_CTRL"; 2662306a36Sopenharmony_ci case ICE_VSI_CHNL: 2762306a36Sopenharmony_ci return "ICE_VSI_CHNL"; 2862306a36Sopenharmony_ci case ICE_VSI_LB: 2962306a36Sopenharmony_ci return "ICE_VSI_LB"; 3062306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 3162306a36Sopenharmony_ci return "ICE_VSI_SWITCHDEV_CTRL"; 3262306a36Sopenharmony_ci default: 3362306a36Sopenharmony_ci return "unknown"; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/** 3862306a36Sopenharmony_ci * ice_vsi_ctrl_all_rx_rings - Start or stop a VSI's Rx rings 3962306a36Sopenharmony_ci * @vsi: the VSI being configured 4062306a36Sopenharmony_ci * @ena: start or stop the Rx rings 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * First enable/disable all of the Rx rings, flush any remaining writes, and 4362306a36Sopenharmony_ci * then verify that they have all been enabled/disabled successfully. This will 4462306a36Sopenharmony_ci * let all of the register writes complete when enabling/disabling the Rx rings 4562306a36Sopenharmony_ci * before waiting for the change in hardware to complete. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistatic int ice_vsi_ctrl_all_rx_rings(struct ice_vsi *vsi, bool ena) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int ret = 0; 5062306a36Sopenharmony_ci u16 i; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) 5362306a36Sopenharmony_ci ice_vsi_ctrl_one_rx_ring(vsi, ena, i, false); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci ice_flush(&vsi->back->hw); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) { 5862306a36Sopenharmony_ci ret = ice_vsi_wait_one_rx_ring(vsi, ena, i); 5962306a36Sopenharmony_ci if (ret) 6062306a36Sopenharmony_ci break; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return ret; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/** 6762306a36Sopenharmony_ci * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the VSI 6862306a36Sopenharmony_ci * @vsi: VSI pointer 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * On error: returns error code (negative) 7162306a36Sopenharmony_ci * On success: returns 0 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic int ice_vsi_alloc_arrays(struct ice_vsi *vsi) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 7662306a36Sopenharmony_ci struct device *dev; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 7962306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* allocate memory for both Tx and Rx ring pointers */ 8362306a36Sopenharmony_ci vsi->tx_rings = devm_kcalloc(dev, vsi->alloc_txq, 8462306a36Sopenharmony_ci sizeof(*vsi->tx_rings), GFP_KERNEL); 8562306a36Sopenharmony_ci if (!vsi->tx_rings) 8662306a36Sopenharmony_ci return -ENOMEM; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci vsi->rx_rings = devm_kcalloc(dev, vsi->alloc_rxq, 8962306a36Sopenharmony_ci sizeof(*vsi->rx_rings), GFP_KERNEL); 9062306a36Sopenharmony_ci if (!vsi->rx_rings) 9162306a36Sopenharmony_ci goto err_rings; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* txq_map needs to have enough space to track both Tx (stack) rings 9462306a36Sopenharmony_ci * and XDP rings; at this point vsi->num_xdp_txq might not be set, 9562306a36Sopenharmony_ci * so use num_possible_cpus() as we want to always provide XDP ring 9662306a36Sopenharmony_ci * per CPU, regardless of queue count settings from user that might 9762306a36Sopenharmony_ci * have come from ethtool's set_channels() callback; 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci vsi->txq_map = devm_kcalloc(dev, (vsi->alloc_txq + num_possible_cpus()), 10062306a36Sopenharmony_ci sizeof(*vsi->txq_map), GFP_KERNEL); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (!vsi->txq_map) 10362306a36Sopenharmony_ci goto err_txq_map; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci vsi->rxq_map = devm_kcalloc(dev, vsi->alloc_rxq, 10662306a36Sopenharmony_ci sizeof(*vsi->rxq_map), GFP_KERNEL); 10762306a36Sopenharmony_ci if (!vsi->rxq_map) 10862306a36Sopenharmony_ci goto err_rxq_map; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* There is no need to allocate q_vectors for a loopback VSI. */ 11162306a36Sopenharmony_ci if (vsi->type == ICE_VSI_LB) 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* allocate memory for q_vector pointers */ 11562306a36Sopenharmony_ci vsi->q_vectors = devm_kcalloc(dev, vsi->num_q_vectors, 11662306a36Sopenharmony_ci sizeof(*vsi->q_vectors), GFP_KERNEL); 11762306a36Sopenharmony_ci if (!vsi->q_vectors) 11862306a36Sopenharmony_ci goto err_vectors; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci vsi->af_xdp_zc_qps = bitmap_zalloc(max_t(int, vsi->alloc_txq, vsi->alloc_rxq), GFP_KERNEL); 12162306a36Sopenharmony_ci if (!vsi->af_xdp_zc_qps) 12262306a36Sopenharmony_ci goto err_zc_qps; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cierr_zc_qps: 12762306a36Sopenharmony_ci devm_kfree(dev, vsi->q_vectors); 12862306a36Sopenharmony_cierr_vectors: 12962306a36Sopenharmony_ci devm_kfree(dev, vsi->rxq_map); 13062306a36Sopenharmony_cierr_rxq_map: 13162306a36Sopenharmony_ci devm_kfree(dev, vsi->txq_map); 13262306a36Sopenharmony_cierr_txq_map: 13362306a36Sopenharmony_ci devm_kfree(dev, vsi->rx_rings); 13462306a36Sopenharmony_cierr_rings: 13562306a36Sopenharmony_ci devm_kfree(dev, vsi->tx_rings); 13662306a36Sopenharmony_ci return -ENOMEM; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/** 14062306a36Sopenharmony_ci * ice_vsi_set_num_desc - Set number of descriptors for queues on this VSI 14162306a36Sopenharmony_ci * @vsi: the VSI being configured 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_cistatic void ice_vsi_set_num_desc(struct ice_vsi *vsi) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci switch (vsi->type) { 14662306a36Sopenharmony_ci case ICE_VSI_PF: 14762306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 14862306a36Sopenharmony_ci case ICE_VSI_CTRL: 14962306a36Sopenharmony_ci case ICE_VSI_LB: 15062306a36Sopenharmony_ci /* a user could change the values of num_[tr]x_desc using 15162306a36Sopenharmony_ci * ethtool -G so we should keep those values instead of 15262306a36Sopenharmony_ci * overwriting them with the defaults. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci if (!vsi->num_rx_desc) 15562306a36Sopenharmony_ci vsi->num_rx_desc = ICE_DFLT_NUM_RX_DESC; 15662306a36Sopenharmony_ci if (!vsi->num_tx_desc) 15762306a36Sopenharmony_ci vsi->num_tx_desc = ICE_DFLT_NUM_TX_DESC; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci default: 16062306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(vsi->back), "Not setting number of Tx/Rx descriptors for VSI type %d\n", 16162306a36Sopenharmony_ci vsi->type); 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/** 16762306a36Sopenharmony_ci * ice_vsi_set_num_qs - Set number of queues, descriptors and vectors for a VSI 16862306a36Sopenharmony_ci * @vsi: the VSI being configured 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * Return 0 on success and a negative value on error 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_cistatic void ice_vsi_set_num_qs(struct ice_vsi *vsi) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci enum ice_vsi_type vsi_type = vsi->type; 17562306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 17662306a36Sopenharmony_ci struct ice_vf *vf = vsi->vf; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (WARN_ON(vsi_type == ICE_VSI_VF && !vf)) 17962306a36Sopenharmony_ci return; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci switch (vsi_type) { 18262306a36Sopenharmony_ci case ICE_VSI_PF: 18362306a36Sopenharmony_ci if (vsi->req_txq) { 18462306a36Sopenharmony_ci vsi->alloc_txq = vsi->req_txq; 18562306a36Sopenharmony_ci vsi->num_txq = vsi->req_txq; 18662306a36Sopenharmony_ci } else { 18762306a36Sopenharmony_ci vsi->alloc_txq = min3(pf->num_lan_msix, 18862306a36Sopenharmony_ci ice_get_avail_txq_count(pf), 18962306a36Sopenharmony_ci (u16)num_online_cpus()); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci pf->num_lan_tx = vsi->alloc_txq; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* only 1 Rx queue unless RSS is enabled */ 19562306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 19662306a36Sopenharmony_ci vsi->alloc_rxq = 1; 19762306a36Sopenharmony_ci } else { 19862306a36Sopenharmony_ci if (vsi->req_rxq) { 19962306a36Sopenharmony_ci vsi->alloc_rxq = vsi->req_rxq; 20062306a36Sopenharmony_ci vsi->num_rxq = vsi->req_rxq; 20162306a36Sopenharmony_ci } else { 20262306a36Sopenharmony_ci vsi->alloc_rxq = min3(pf->num_lan_msix, 20362306a36Sopenharmony_ci ice_get_avail_rxq_count(pf), 20462306a36Sopenharmony_ci (u16)num_online_cpus()); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci pf->num_lan_rx = vsi->alloc_rxq; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci vsi->num_q_vectors = min_t(int, pf->num_lan_msix, 21162306a36Sopenharmony_ci max_t(int, vsi->alloc_rxq, 21262306a36Sopenharmony_ci vsi->alloc_txq)); 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 21562306a36Sopenharmony_ci /* The number of queues for ctrl VSI is equal to number of VFs. 21662306a36Sopenharmony_ci * Each ring is associated to the corresponding VF_PR netdev. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci vsi->alloc_txq = ice_get_num_vfs(pf); 21962306a36Sopenharmony_ci vsi->alloc_rxq = vsi->alloc_txq; 22062306a36Sopenharmony_ci vsi->num_q_vectors = 1; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case ICE_VSI_VF: 22362306a36Sopenharmony_ci if (vf->num_req_qs) 22462306a36Sopenharmony_ci vf->num_vf_qs = vf->num_req_qs; 22562306a36Sopenharmony_ci vsi->alloc_txq = vf->num_vf_qs; 22662306a36Sopenharmony_ci vsi->alloc_rxq = vf->num_vf_qs; 22762306a36Sopenharmony_ci /* pf->vfs.num_msix_per includes (VF miscellaneous vector + 22862306a36Sopenharmony_ci * data queue interrupts). Since vsi->num_q_vectors is number 22962306a36Sopenharmony_ci * of queues vectors, subtract 1 (ICE_NONQ_VECS_VF) from the 23062306a36Sopenharmony_ci * original vector count 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci vsi->num_q_vectors = pf->vfs.num_msix_per - ICE_NONQ_VECS_VF; 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci case ICE_VSI_CTRL: 23562306a36Sopenharmony_ci vsi->alloc_txq = 1; 23662306a36Sopenharmony_ci vsi->alloc_rxq = 1; 23762306a36Sopenharmony_ci vsi->num_q_vectors = 1; 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci case ICE_VSI_CHNL: 24062306a36Sopenharmony_ci vsi->alloc_txq = 0; 24162306a36Sopenharmony_ci vsi->alloc_rxq = 0; 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci case ICE_VSI_LB: 24462306a36Sopenharmony_ci vsi->alloc_txq = 1; 24562306a36Sopenharmony_ci vsi->alloc_rxq = 1; 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci default: 24862306a36Sopenharmony_ci dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi_type); 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci ice_vsi_set_num_desc(vsi); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/** 25662306a36Sopenharmony_ci * ice_get_free_slot - get the next non-NULL location index in array 25762306a36Sopenharmony_ci * @array: array to search 25862306a36Sopenharmony_ci * @size: size of the array 25962306a36Sopenharmony_ci * @curr: last known occupied index to be used as a search hint 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * void * is being used to keep the functionality generic. This lets us use this 26262306a36Sopenharmony_ci * function on any array of pointers. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_cistatic int ice_get_free_slot(void *array, int size, int curr) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci int **tmp_array = (int **)array; 26762306a36Sopenharmony_ci int next; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (curr < (size - 1) && !tmp_array[curr + 1]) { 27062306a36Sopenharmony_ci next = curr + 1; 27162306a36Sopenharmony_ci } else { 27262306a36Sopenharmony_ci int i = 0; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci while ((i < size) && (tmp_array[i])) 27562306a36Sopenharmony_ci i++; 27662306a36Sopenharmony_ci if (i == size) 27762306a36Sopenharmony_ci next = ICE_NO_VSI; 27862306a36Sopenharmony_ci else 27962306a36Sopenharmony_ci next = i; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci return next; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * ice_vsi_delete_from_hw - delete a VSI from the switch 28662306a36Sopenharmony_ci * @vsi: pointer to VSI being removed 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistatic void ice_vsi_delete_from_hw(struct ice_vsi *vsi) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 29162306a36Sopenharmony_ci struct ice_vsi_ctx *ctxt; 29262306a36Sopenharmony_ci int status; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ice_fltr_remove_all(vsi); 29562306a36Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 29662306a36Sopenharmony_ci if (!ctxt) 29762306a36Sopenharmony_ci return; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 30062306a36Sopenharmony_ci ctxt->vf_num = vsi->vf->vf_id; 30162306a36Sopenharmony_ci ctxt->vsi_num = vsi->vsi_num; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci memcpy(&ctxt->info, &vsi->info, sizeof(ctxt->info)); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci status = ice_free_vsi(&pf->hw, vsi->idx, ctxt, false, NULL); 30662306a36Sopenharmony_ci if (status) 30762306a36Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Failed to delete VSI %i in FW - error: %d\n", 30862306a36Sopenharmony_ci vsi->vsi_num, status); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci kfree(ctxt); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/** 31462306a36Sopenharmony_ci * ice_vsi_free_arrays - De-allocate queue and vector pointer arrays for the VSI 31562306a36Sopenharmony_ci * @vsi: pointer to VSI being cleared 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistatic void ice_vsi_free_arrays(struct ice_vsi *vsi) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 32062306a36Sopenharmony_ci struct device *dev; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci bitmap_free(vsi->af_xdp_zc_qps); 32562306a36Sopenharmony_ci vsi->af_xdp_zc_qps = NULL; 32662306a36Sopenharmony_ci /* free the ring and vector containers */ 32762306a36Sopenharmony_ci devm_kfree(dev, vsi->q_vectors); 32862306a36Sopenharmony_ci vsi->q_vectors = NULL; 32962306a36Sopenharmony_ci devm_kfree(dev, vsi->tx_rings); 33062306a36Sopenharmony_ci vsi->tx_rings = NULL; 33162306a36Sopenharmony_ci devm_kfree(dev, vsi->rx_rings); 33262306a36Sopenharmony_ci vsi->rx_rings = NULL; 33362306a36Sopenharmony_ci devm_kfree(dev, vsi->txq_map); 33462306a36Sopenharmony_ci vsi->txq_map = NULL; 33562306a36Sopenharmony_ci devm_kfree(dev, vsi->rxq_map); 33662306a36Sopenharmony_ci vsi->rxq_map = NULL; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/** 34062306a36Sopenharmony_ci * ice_vsi_free_stats - Free the ring statistics structures 34162306a36Sopenharmony_ci * @vsi: VSI pointer 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistatic void ice_vsi_free_stats(struct ice_vsi *vsi) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct ice_vsi_stats *vsi_stat; 34662306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 34762306a36Sopenharmony_ci int i; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) 35062306a36Sopenharmony_ci return; 35162306a36Sopenharmony_ci if (!pf->vsi_stats) 35262306a36Sopenharmony_ci return; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci vsi_stat = pf->vsi_stats[vsi->idx]; 35562306a36Sopenharmony_ci if (!vsi_stat) 35662306a36Sopenharmony_ci return; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ice_for_each_alloc_txq(vsi, i) { 35962306a36Sopenharmony_ci if (vsi_stat->tx_ring_stats[i]) { 36062306a36Sopenharmony_ci kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); 36162306a36Sopenharmony_ci WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ice_for_each_alloc_rxq(vsi, i) { 36662306a36Sopenharmony_ci if (vsi_stat->rx_ring_stats[i]) { 36762306a36Sopenharmony_ci kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); 36862306a36Sopenharmony_ci WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci kfree(vsi_stat->tx_ring_stats); 37362306a36Sopenharmony_ci kfree(vsi_stat->rx_ring_stats); 37462306a36Sopenharmony_ci kfree(vsi_stat); 37562306a36Sopenharmony_ci pf->vsi_stats[vsi->idx] = NULL; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/** 37962306a36Sopenharmony_ci * ice_vsi_alloc_ring_stats - Allocates Tx and Rx ring stats for the VSI 38062306a36Sopenharmony_ci * @vsi: VSI which is having stats allocated 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct ice_ring_stats **tx_ring_stats; 38562306a36Sopenharmony_ci struct ice_ring_stats **rx_ring_stats; 38662306a36Sopenharmony_ci struct ice_vsi_stats *vsi_stats; 38762306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 38862306a36Sopenharmony_ci u16 i; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci vsi_stats = pf->vsi_stats[vsi->idx]; 39162306a36Sopenharmony_ci tx_ring_stats = vsi_stats->tx_ring_stats; 39262306a36Sopenharmony_ci rx_ring_stats = vsi_stats->rx_ring_stats; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* Allocate Tx ring stats */ 39562306a36Sopenharmony_ci ice_for_each_alloc_txq(vsi, i) { 39662306a36Sopenharmony_ci struct ice_ring_stats *ring_stats; 39762306a36Sopenharmony_ci struct ice_tx_ring *ring; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ring = vsi->tx_rings[i]; 40062306a36Sopenharmony_ci ring_stats = tx_ring_stats[i]; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!ring_stats) { 40362306a36Sopenharmony_ci ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL); 40462306a36Sopenharmony_ci if (!ring_stats) 40562306a36Sopenharmony_ci goto err_out; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci WRITE_ONCE(tx_ring_stats[i], ring_stats); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ring->ring_stats = ring_stats; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Allocate Rx ring stats */ 41462306a36Sopenharmony_ci ice_for_each_alloc_rxq(vsi, i) { 41562306a36Sopenharmony_ci struct ice_ring_stats *ring_stats; 41662306a36Sopenharmony_ci struct ice_rx_ring *ring; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ring = vsi->rx_rings[i]; 41962306a36Sopenharmony_ci ring_stats = rx_ring_stats[i]; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (!ring_stats) { 42262306a36Sopenharmony_ci ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL); 42362306a36Sopenharmony_ci if (!ring_stats) 42462306a36Sopenharmony_ci goto err_out; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci WRITE_ONCE(rx_ring_stats[i], ring_stats); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci ring->ring_stats = ring_stats; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cierr_out: 43562306a36Sopenharmony_ci ice_vsi_free_stats(vsi); 43662306a36Sopenharmony_ci return -ENOMEM; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/** 44062306a36Sopenharmony_ci * ice_vsi_free - clean up and deallocate the provided VSI 44162306a36Sopenharmony_ci * @vsi: pointer to VSI being cleared 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * This deallocates the VSI's queue resources, removes it from the PF's 44462306a36Sopenharmony_ci * VSI array if necessary, and deallocates the VSI 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_cistatic void ice_vsi_free(struct ice_vsi *vsi) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct ice_pf *pf = NULL; 44962306a36Sopenharmony_ci struct device *dev; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!vsi || !vsi->back) 45262306a36Sopenharmony_ci return; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci pf = vsi->back; 45562306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) { 45862306a36Sopenharmony_ci dev_dbg(dev, "vsi does not exist at pf->vsi[%d]\n", vsi->idx); 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci mutex_lock(&pf->sw_mutex); 46362306a36Sopenharmony_ci /* updates the PF for this cleared VSI */ 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci pf->vsi[vsi->idx] = NULL; 46662306a36Sopenharmony_ci pf->next_vsi = vsi->idx; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci ice_vsi_free_stats(vsi); 46962306a36Sopenharmony_ci ice_vsi_free_arrays(vsi); 47062306a36Sopenharmony_ci mutex_unlock(&pf->sw_mutex); 47162306a36Sopenharmony_ci devm_kfree(dev, vsi); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_civoid ice_vsi_delete(struct ice_vsi *vsi) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci ice_vsi_delete_from_hw(vsi); 47762306a36Sopenharmony_ci ice_vsi_free(vsi); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci/** 48162306a36Sopenharmony_ci * ice_msix_clean_ctrl_vsi - MSIX mode interrupt handler for ctrl VSI 48262306a36Sopenharmony_ci * @irq: interrupt number 48362306a36Sopenharmony_ci * @data: pointer to a q_vector 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_cistatic irqreturn_t ice_msix_clean_ctrl_vsi(int __always_unused irq, void *data) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct ice_q_vector *q_vector = (struct ice_q_vector *)data; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (!q_vector->tx.tx_ring) 49062306a36Sopenharmony_ci return IRQ_HANDLED; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci#define FDIR_RX_DESC_CLEAN_BUDGET 64 49362306a36Sopenharmony_ci ice_clean_rx_irq(q_vector->rx.rx_ring, FDIR_RX_DESC_CLEAN_BUDGET); 49462306a36Sopenharmony_ci ice_clean_ctrl_tx_irq(q_vector->tx.tx_ring); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return IRQ_HANDLED; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci/** 50062306a36Sopenharmony_ci * ice_msix_clean_rings - MSIX mode Interrupt Handler 50162306a36Sopenharmony_ci * @irq: interrupt number 50262306a36Sopenharmony_ci * @data: pointer to a q_vector 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_cistatic irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct ice_q_vector *q_vector = (struct ice_q_vector *)data; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!q_vector->tx.tx_ring && !q_vector->rx.rx_ring) 50962306a36Sopenharmony_ci return IRQ_HANDLED; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci q_vector->total_events++; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci napi_schedule(&q_vector->napi); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return IRQ_HANDLED; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic irqreturn_t ice_eswitch_msix_clean_rings(int __always_unused irq, void *data) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct ice_q_vector *q_vector = (struct ice_q_vector *)data; 52162306a36Sopenharmony_ci struct ice_pf *pf = q_vector->vsi->back; 52262306a36Sopenharmony_ci struct ice_vf *vf; 52362306a36Sopenharmony_ci unsigned int bkt; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (!q_vector->tx.tx_ring && !q_vector->rx.rx_ring) 52662306a36Sopenharmony_ci return IRQ_HANDLED; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci rcu_read_lock(); 52962306a36Sopenharmony_ci ice_for_each_vf_rcu(pf, bkt, vf) 53062306a36Sopenharmony_ci napi_schedule(&vf->repr->q_vector->napi); 53162306a36Sopenharmony_ci rcu_read_unlock(); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return IRQ_HANDLED; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/** 53762306a36Sopenharmony_ci * ice_vsi_alloc_stat_arrays - Allocate statistics arrays 53862306a36Sopenharmony_ci * @vsi: VSI pointer 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_cistatic int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct ice_vsi_stats *vsi_stat; 54362306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci if (!pf->vsi_stats) 54862306a36Sopenharmony_ci return -ENOENT; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (pf->vsi_stats[vsi->idx]) 55162306a36Sopenharmony_ci /* realloc will happen in rebuild path */ 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci vsi_stat = kzalloc(sizeof(*vsi_stat), GFP_KERNEL); 55562306a36Sopenharmony_ci if (!vsi_stat) 55662306a36Sopenharmony_ci return -ENOMEM; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci vsi_stat->tx_ring_stats = 55962306a36Sopenharmony_ci kcalloc(vsi->alloc_txq, sizeof(*vsi_stat->tx_ring_stats), 56062306a36Sopenharmony_ci GFP_KERNEL); 56162306a36Sopenharmony_ci if (!vsi_stat->tx_ring_stats) 56262306a36Sopenharmony_ci goto err_alloc_tx; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci vsi_stat->rx_ring_stats = 56562306a36Sopenharmony_ci kcalloc(vsi->alloc_rxq, sizeof(*vsi_stat->rx_ring_stats), 56662306a36Sopenharmony_ci GFP_KERNEL); 56762306a36Sopenharmony_ci if (!vsi_stat->rx_ring_stats) 56862306a36Sopenharmony_ci goto err_alloc_rx; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci pf->vsi_stats[vsi->idx] = vsi_stat; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return 0; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cierr_alloc_rx: 57562306a36Sopenharmony_ci kfree(vsi_stat->rx_ring_stats); 57662306a36Sopenharmony_cierr_alloc_tx: 57762306a36Sopenharmony_ci kfree(vsi_stat->tx_ring_stats); 57862306a36Sopenharmony_ci kfree(vsi_stat); 57962306a36Sopenharmony_ci pf->vsi_stats[vsi->idx] = NULL; 58062306a36Sopenharmony_ci return -ENOMEM; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/** 58462306a36Sopenharmony_ci * ice_vsi_alloc_def - set default values for already allocated VSI 58562306a36Sopenharmony_ci * @vsi: ptr to VSI 58662306a36Sopenharmony_ci * @ch: ptr to channel 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_cistatic int 58962306a36Sopenharmony_ciice_vsi_alloc_def(struct ice_vsi *vsi, struct ice_channel *ch) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci if (vsi->type != ICE_VSI_CHNL) { 59262306a36Sopenharmony_ci ice_vsi_set_num_qs(vsi); 59362306a36Sopenharmony_ci if (ice_vsi_alloc_arrays(vsi)) 59462306a36Sopenharmony_ci return -ENOMEM; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci switch (vsi->type) { 59862306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 59962306a36Sopenharmony_ci /* Setup eswitch MSIX irq handler for VSI */ 60062306a36Sopenharmony_ci vsi->irq_handler = ice_eswitch_msix_clean_rings; 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci case ICE_VSI_PF: 60362306a36Sopenharmony_ci /* Setup default MSIX irq handler for VSI */ 60462306a36Sopenharmony_ci vsi->irq_handler = ice_msix_clean_rings; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case ICE_VSI_CTRL: 60762306a36Sopenharmony_ci /* Setup ctrl VSI MSIX irq handler */ 60862306a36Sopenharmony_ci vsi->irq_handler = ice_msix_clean_ctrl_vsi; 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case ICE_VSI_CHNL: 61162306a36Sopenharmony_ci if (!ch) 61262306a36Sopenharmony_ci return -EINVAL; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci vsi->num_rxq = ch->num_rxq; 61562306a36Sopenharmony_ci vsi->num_txq = ch->num_txq; 61662306a36Sopenharmony_ci vsi->next_base_q = ch->base_q; 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case ICE_VSI_VF: 61962306a36Sopenharmony_ci case ICE_VSI_LB: 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci default: 62262306a36Sopenharmony_ci ice_vsi_free_arrays(vsi); 62362306a36Sopenharmony_ci return -EINVAL; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return 0; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci/** 63062306a36Sopenharmony_ci * ice_vsi_alloc - Allocates the next available struct VSI in the PF 63162306a36Sopenharmony_ci * @pf: board private structure 63262306a36Sopenharmony_ci * 63362306a36Sopenharmony_ci * Reserves a VSI index from the PF and allocates an empty VSI structure 63462306a36Sopenharmony_ci * without a type. The VSI structure must later be initialized by calling 63562306a36Sopenharmony_ci * ice_vsi_cfg(). 63662306a36Sopenharmony_ci * 63762306a36Sopenharmony_ci * returns a pointer to a VSI on success, NULL on failure. 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_cistatic struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 64262306a36Sopenharmony_ci struct ice_vsi *vsi = NULL; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Need to protect the allocation of the VSIs at the PF level */ 64562306a36Sopenharmony_ci mutex_lock(&pf->sw_mutex); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* If we have already allocated our maximum number of VSIs, 64862306a36Sopenharmony_ci * pf->next_vsi will be ICE_NO_VSI. If not, pf->next_vsi index 64962306a36Sopenharmony_ci * is available to be populated 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci if (pf->next_vsi == ICE_NO_VSI) { 65262306a36Sopenharmony_ci dev_dbg(dev, "out of VSI slots!\n"); 65362306a36Sopenharmony_ci goto unlock_pf; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci vsi = devm_kzalloc(dev, sizeof(*vsi), GFP_KERNEL); 65762306a36Sopenharmony_ci if (!vsi) 65862306a36Sopenharmony_ci goto unlock_pf; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci vsi->back = pf; 66162306a36Sopenharmony_ci set_bit(ICE_VSI_DOWN, vsi->state); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* fill slot and make note of the index */ 66462306a36Sopenharmony_ci vsi->idx = pf->next_vsi; 66562306a36Sopenharmony_ci pf->vsi[pf->next_vsi] = vsi; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* prepare pf->next_vsi for next use */ 66862306a36Sopenharmony_ci pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi, 66962306a36Sopenharmony_ci pf->next_vsi); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ciunlock_pf: 67262306a36Sopenharmony_ci mutex_unlock(&pf->sw_mutex); 67362306a36Sopenharmony_ci return vsi; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci/** 67762306a36Sopenharmony_ci * ice_alloc_fd_res - Allocate FD resource for a VSI 67862306a36Sopenharmony_ci * @vsi: pointer to the ice_vsi 67962306a36Sopenharmony_ci * 68062306a36Sopenharmony_ci * This allocates the FD resources 68162306a36Sopenharmony_ci * 68262306a36Sopenharmony_ci * Returns 0 on success, -EPERM on no-op or -EIO on failure 68362306a36Sopenharmony_ci */ 68462306a36Sopenharmony_cistatic int ice_alloc_fd_res(struct ice_vsi *vsi) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 68762306a36Sopenharmony_ci u32 g_val, b_val; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Flow Director filters are only allocated/assigned to the PF VSI or 69062306a36Sopenharmony_ci * CHNL VSI which passes the traffic. The CTRL VSI is only used to 69162306a36Sopenharmony_ci * add/delete filters so resources are not allocated to it 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_FD_ENA, pf->flags)) 69462306a36Sopenharmony_ci return -EPERM; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (!(vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF || 69762306a36Sopenharmony_ci vsi->type == ICE_VSI_CHNL)) 69862306a36Sopenharmony_ci return -EPERM; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* FD filters from guaranteed pool per VSI */ 70162306a36Sopenharmony_ci g_val = pf->hw.func_caps.fd_fltr_guar; 70262306a36Sopenharmony_ci if (!g_val) 70362306a36Sopenharmony_ci return -EPERM; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* FD filters from best effort pool */ 70662306a36Sopenharmony_ci b_val = pf->hw.func_caps.fd_fltr_best_effort; 70762306a36Sopenharmony_ci if (!b_val) 70862306a36Sopenharmony_ci return -EPERM; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* PF main VSI gets only 64 FD resources from guaranteed pool 71162306a36Sopenharmony_ci * when ADQ is configured. 71262306a36Sopenharmony_ci */ 71362306a36Sopenharmony_ci#define ICE_PF_VSI_GFLTR 64 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* determine FD filter resources per VSI from shared(best effort) and 71662306a36Sopenharmony_ci * dedicated pool 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 71962306a36Sopenharmony_ci vsi->num_gfltr = g_val; 72062306a36Sopenharmony_ci /* if MQPRIO is configured, main VSI doesn't get all FD 72162306a36Sopenharmony_ci * resources from guaranteed pool. PF VSI gets 64 FD resources 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci if (test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) { 72462306a36Sopenharmony_ci if (g_val < ICE_PF_VSI_GFLTR) 72562306a36Sopenharmony_ci return -EPERM; 72662306a36Sopenharmony_ci /* allow bare minimum entries for PF VSI */ 72762306a36Sopenharmony_ci vsi->num_gfltr = ICE_PF_VSI_GFLTR; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* each VSI gets same "best_effort" quota */ 73162306a36Sopenharmony_ci vsi->num_bfltr = b_val; 73262306a36Sopenharmony_ci } else if (vsi->type == ICE_VSI_VF) { 73362306a36Sopenharmony_ci vsi->num_gfltr = 0; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* each VSI gets same "best_effort" quota */ 73662306a36Sopenharmony_ci vsi->num_bfltr = b_val; 73762306a36Sopenharmony_ci } else { 73862306a36Sopenharmony_ci struct ice_vsi *main_vsi; 73962306a36Sopenharmony_ci int numtc; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci main_vsi = ice_get_main_vsi(pf); 74262306a36Sopenharmony_ci if (!main_vsi) 74362306a36Sopenharmony_ci return -EPERM; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (!main_vsi->all_numtc) 74662306a36Sopenharmony_ci return -EINVAL; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* figure out ADQ numtc */ 74962306a36Sopenharmony_ci numtc = main_vsi->all_numtc - ICE_CHNL_START_TC; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* only one TC but still asking resources for channels, 75262306a36Sopenharmony_ci * invalid config 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci if (numtc < ICE_CHNL_START_TC) 75562306a36Sopenharmony_ci return -EPERM; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci g_val -= ICE_PF_VSI_GFLTR; 75862306a36Sopenharmony_ci /* channel VSIs gets equal share from guaranteed pool */ 75962306a36Sopenharmony_ci vsi->num_gfltr = g_val / numtc; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* each VSI gets same "best_effort" quota */ 76262306a36Sopenharmony_ci vsi->num_bfltr = b_val; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return 0; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/** 76962306a36Sopenharmony_ci * ice_vsi_get_qs - Assign queues from PF to VSI 77062306a36Sopenharmony_ci * @vsi: the VSI to assign queues to 77162306a36Sopenharmony_ci * 77262306a36Sopenharmony_ci * Returns 0 on success and a negative value on error 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_cistatic int ice_vsi_get_qs(struct ice_vsi *vsi) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 77762306a36Sopenharmony_ci struct ice_qs_cfg tx_qs_cfg = { 77862306a36Sopenharmony_ci .qs_mutex = &pf->avail_q_mutex, 77962306a36Sopenharmony_ci .pf_map = pf->avail_txqs, 78062306a36Sopenharmony_ci .pf_map_size = pf->max_pf_txqs, 78162306a36Sopenharmony_ci .q_count = vsi->alloc_txq, 78262306a36Sopenharmony_ci .scatter_count = ICE_MAX_SCATTER_TXQS, 78362306a36Sopenharmony_ci .vsi_map = vsi->txq_map, 78462306a36Sopenharmony_ci .vsi_map_offset = 0, 78562306a36Sopenharmony_ci .mapping_mode = ICE_VSI_MAP_CONTIG 78662306a36Sopenharmony_ci }; 78762306a36Sopenharmony_ci struct ice_qs_cfg rx_qs_cfg = { 78862306a36Sopenharmony_ci .qs_mutex = &pf->avail_q_mutex, 78962306a36Sopenharmony_ci .pf_map = pf->avail_rxqs, 79062306a36Sopenharmony_ci .pf_map_size = pf->max_pf_rxqs, 79162306a36Sopenharmony_ci .q_count = vsi->alloc_rxq, 79262306a36Sopenharmony_ci .scatter_count = ICE_MAX_SCATTER_RXQS, 79362306a36Sopenharmony_ci .vsi_map = vsi->rxq_map, 79462306a36Sopenharmony_ci .vsi_map_offset = 0, 79562306a36Sopenharmony_ci .mapping_mode = ICE_VSI_MAP_CONTIG 79662306a36Sopenharmony_ci }; 79762306a36Sopenharmony_ci int ret; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) 80062306a36Sopenharmony_ci return 0; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci ret = __ice_vsi_get_qs(&tx_qs_cfg); 80362306a36Sopenharmony_ci if (ret) 80462306a36Sopenharmony_ci return ret; 80562306a36Sopenharmony_ci vsi->tx_mapping_mode = tx_qs_cfg.mapping_mode; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci ret = __ice_vsi_get_qs(&rx_qs_cfg); 80862306a36Sopenharmony_ci if (ret) 80962306a36Sopenharmony_ci return ret; 81062306a36Sopenharmony_ci vsi->rx_mapping_mode = rx_qs_cfg.mapping_mode; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci/** 81662306a36Sopenharmony_ci * ice_vsi_put_qs - Release queues from VSI to PF 81762306a36Sopenharmony_ci * @vsi: the VSI that is going to release queues 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_cistatic void ice_vsi_put_qs(struct ice_vsi *vsi) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 82262306a36Sopenharmony_ci int i; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci mutex_lock(&pf->avail_q_mutex); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci ice_for_each_alloc_txq(vsi, i) { 82762306a36Sopenharmony_ci clear_bit(vsi->txq_map[i], pf->avail_txqs); 82862306a36Sopenharmony_ci vsi->txq_map[i] = ICE_INVAL_Q_INDEX; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci ice_for_each_alloc_rxq(vsi, i) { 83262306a36Sopenharmony_ci clear_bit(vsi->rxq_map[i], pf->avail_rxqs); 83362306a36Sopenharmony_ci vsi->rxq_map[i] = ICE_INVAL_Q_INDEX; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci mutex_unlock(&pf->avail_q_mutex); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci/** 84062306a36Sopenharmony_ci * ice_is_safe_mode 84162306a36Sopenharmony_ci * @pf: pointer to the PF struct 84262306a36Sopenharmony_ci * 84362306a36Sopenharmony_ci * returns true if driver is in safe mode, false otherwise 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_cibool ice_is_safe_mode(struct ice_pf *pf) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci return !test_bit(ICE_FLAG_ADV_FEATURES, pf->flags); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/** 85162306a36Sopenharmony_ci * ice_is_rdma_ena 85262306a36Sopenharmony_ci * @pf: pointer to the PF struct 85362306a36Sopenharmony_ci * 85462306a36Sopenharmony_ci * returns true if RDMA is currently supported, false otherwise 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_cibool ice_is_rdma_ena(struct ice_pf *pf) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci return test_bit(ICE_FLAG_RDMA_ENA, pf->flags); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci/** 86262306a36Sopenharmony_ci * ice_vsi_clean_rss_flow_fld - Delete RSS configuration 86362306a36Sopenharmony_ci * @vsi: the VSI being cleaned up 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * This function deletes RSS input set for all flows that were configured 86662306a36Sopenharmony_ci * for this VSI 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_cistatic void ice_vsi_clean_rss_flow_fld(struct ice_vsi *vsi) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 87162306a36Sopenharmony_ci int status; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (ice_is_safe_mode(pf)) 87462306a36Sopenharmony_ci return; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx); 87762306a36Sopenharmony_ci if (status) 87862306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "ice_rem_vsi_rss_cfg failed for vsi = %d, error = %d\n", 87962306a36Sopenharmony_ci vsi->vsi_num, status); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci/** 88362306a36Sopenharmony_ci * ice_rss_clean - Delete RSS related VSI structures and configuration 88462306a36Sopenharmony_ci * @vsi: the VSI being removed 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_cistatic void ice_rss_clean(struct ice_vsi *vsi) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 88962306a36Sopenharmony_ci struct device *dev; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci devm_kfree(dev, vsi->rss_hkey_user); 89462306a36Sopenharmony_ci devm_kfree(dev, vsi->rss_lut_user); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci ice_vsi_clean_rss_flow_fld(vsi); 89762306a36Sopenharmony_ci /* remove RSS replay list */ 89862306a36Sopenharmony_ci if (!ice_is_safe_mode(pf)) 89962306a36Sopenharmony_ci ice_rem_vsi_rss_list(&pf->hw, vsi->idx); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci/** 90362306a36Sopenharmony_ci * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type 90462306a36Sopenharmony_ci * @vsi: the VSI being configured 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_cistatic void ice_vsi_set_rss_params(struct ice_vsi *vsi) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci struct ice_hw_common_caps *cap; 90962306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 91062306a36Sopenharmony_ci u16 max_rss_size; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 91362306a36Sopenharmony_ci vsi->rss_size = 1; 91462306a36Sopenharmony_ci return; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci cap = &pf->hw.func_caps.common_cap; 91862306a36Sopenharmony_ci max_rss_size = BIT(cap->rss_table_entry_width); 91962306a36Sopenharmony_ci switch (vsi->type) { 92062306a36Sopenharmony_ci case ICE_VSI_CHNL: 92162306a36Sopenharmony_ci case ICE_VSI_PF: 92262306a36Sopenharmony_ci /* PF VSI will inherit RSS instance of PF */ 92362306a36Sopenharmony_ci vsi->rss_table_size = (u16)cap->rss_table_size; 92462306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) 92562306a36Sopenharmony_ci vsi->rss_size = min_t(u16, vsi->num_rxq, max_rss_size); 92662306a36Sopenharmony_ci else 92762306a36Sopenharmony_ci vsi->rss_size = min_t(u16, num_online_cpus(), 92862306a36Sopenharmony_ci max_rss_size); 92962306a36Sopenharmony_ci vsi->rss_lut_type = ICE_LUT_PF; 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 93262306a36Sopenharmony_ci vsi->rss_table_size = ICE_LUT_VSI_SIZE; 93362306a36Sopenharmony_ci vsi->rss_size = min_t(u16, num_online_cpus(), max_rss_size); 93462306a36Sopenharmony_ci vsi->rss_lut_type = ICE_LUT_VSI; 93562306a36Sopenharmony_ci break; 93662306a36Sopenharmony_ci case ICE_VSI_VF: 93762306a36Sopenharmony_ci /* VF VSI will get a small RSS table. 93862306a36Sopenharmony_ci * For VSI_LUT, LUT size should be set to 64 bytes. 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci vsi->rss_table_size = ICE_LUT_VSI_SIZE; 94162306a36Sopenharmony_ci vsi->rss_size = ICE_MAX_RSS_QS_PER_VF; 94262306a36Sopenharmony_ci vsi->rss_lut_type = ICE_LUT_VSI; 94362306a36Sopenharmony_ci break; 94462306a36Sopenharmony_ci case ICE_VSI_LB: 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci default: 94762306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Unsupported VSI type %s\n", 94862306a36Sopenharmony_ci ice_vsi_type_str(vsi->type)); 94962306a36Sopenharmony_ci break; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci/** 95462306a36Sopenharmony_ci * ice_set_dflt_vsi_ctx - Set default VSI context before adding a VSI 95562306a36Sopenharmony_ci * @hw: HW structure used to determine the VLAN mode of the device 95662306a36Sopenharmony_ci * @ctxt: the VSI context being set 95762306a36Sopenharmony_ci * 95862306a36Sopenharmony_ci * This initializes a default VSI context for all sections except the Queues. 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_cistatic void ice_set_dflt_vsi_ctx(struct ice_hw *hw, struct ice_vsi_ctx *ctxt) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci u32 table = 0; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci memset(&ctxt->info, 0, sizeof(ctxt->info)); 96562306a36Sopenharmony_ci /* VSI's should be allocated from shared pool */ 96662306a36Sopenharmony_ci ctxt->alloc_from_pool = true; 96762306a36Sopenharmony_ci /* Src pruning enabled by default */ 96862306a36Sopenharmony_ci ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; 96962306a36Sopenharmony_ci /* Traffic from VSI can be sent to LAN */ 97062306a36Sopenharmony_ci ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; 97162306a36Sopenharmony_ci /* allow all untagged/tagged packets by default on Tx */ 97262306a36Sopenharmony_ci ctxt->info.inner_vlan_flags = ((ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL & 97362306a36Sopenharmony_ci ICE_AQ_VSI_INNER_VLAN_TX_MODE_M) >> 97462306a36Sopenharmony_ci ICE_AQ_VSI_INNER_VLAN_TX_MODE_S); 97562306a36Sopenharmony_ci /* SVM - by default bits 3 and 4 in inner_vlan_flags are 0's which 97662306a36Sopenharmony_ci * results in legacy behavior (show VLAN, DEI, and UP) in descriptor. 97762306a36Sopenharmony_ci * 97862306a36Sopenharmony_ci * DVM - leave inner VLAN in packet by default 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ci if (ice_is_dvm_ena(hw)) { 98162306a36Sopenharmony_ci ctxt->info.inner_vlan_flags |= 98262306a36Sopenharmony_ci FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M, 98362306a36Sopenharmony_ci ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING); 98462306a36Sopenharmony_ci ctxt->info.outer_vlan_flags = 98562306a36Sopenharmony_ci (ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL << 98662306a36Sopenharmony_ci ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) & 98762306a36Sopenharmony_ci ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M; 98862306a36Sopenharmony_ci ctxt->info.outer_vlan_flags |= 98962306a36Sopenharmony_ci (ICE_AQ_VSI_OUTER_TAG_VLAN_8100 << 99062306a36Sopenharmony_ci ICE_AQ_VSI_OUTER_TAG_TYPE_S) & 99162306a36Sopenharmony_ci ICE_AQ_VSI_OUTER_TAG_TYPE_M; 99262306a36Sopenharmony_ci ctxt->info.outer_vlan_flags |= 99362306a36Sopenharmony_ci FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_EMODE_M, 99462306a36Sopenharmony_ci ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING); 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci /* Have 1:1 UP mapping for both ingress/egress tables */ 99762306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(0, 0); 99862306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(1, 1); 99962306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(2, 2); 100062306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(3, 3); 100162306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(4, 4); 100262306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(5, 5); 100362306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(6, 6); 100462306a36Sopenharmony_ci table |= ICE_UP_TABLE_TRANSLATE(7, 7); 100562306a36Sopenharmony_ci ctxt->info.ingress_table = cpu_to_le32(table); 100662306a36Sopenharmony_ci ctxt->info.egress_table = cpu_to_le32(table); 100762306a36Sopenharmony_ci /* Have 1:1 UP mapping for outer to inner UP table */ 100862306a36Sopenharmony_ci ctxt->info.outer_up_table = cpu_to_le32(table); 100962306a36Sopenharmony_ci /* No Outer tag support outer_tag_flags remains to zero */ 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci/** 101362306a36Sopenharmony_ci * ice_vsi_setup_q_map - Setup a VSI queue map 101462306a36Sopenharmony_ci * @vsi: the VSI being configured 101562306a36Sopenharmony_ci * @ctxt: VSI context structure 101662306a36Sopenharmony_ci */ 101762306a36Sopenharmony_cistatic int ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci u16 offset = 0, qmap = 0, tx_count = 0, rx_count = 0, pow = 0; 102062306a36Sopenharmony_ci u16 num_txq_per_tc, num_rxq_per_tc; 102162306a36Sopenharmony_ci u16 qcount_tx = vsi->alloc_txq; 102262306a36Sopenharmony_ci u16 qcount_rx = vsi->alloc_rxq; 102362306a36Sopenharmony_ci u8 netdev_tc = 0; 102462306a36Sopenharmony_ci int i; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (!vsi->tc_cfg.numtc) { 102762306a36Sopenharmony_ci /* at least TC0 should be enabled by default */ 102862306a36Sopenharmony_ci vsi->tc_cfg.numtc = 1; 102962306a36Sopenharmony_ci vsi->tc_cfg.ena_tc = 1; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci num_rxq_per_tc = min_t(u16, qcount_rx / vsi->tc_cfg.numtc, ICE_MAX_RXQS_PER_TC); 103362306a36Sopenharmony_ci if (!num_rxq_per_tc) 103462306a36Sopenharmony_ci num_rxq_per_tc = 1; 103562306a36Sopenharmony_ci num_txq_per_tc = qcount_tx / vsi->tc_cfg.numtc; 103662306a36Sopenharmony_ci if (!num_txq_per_tc) 103762306a36Sopenharmony_ci num_txq_per_tc = 1; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* find the (rounded up) power-of-2 of qcount */ 104062306a36Sopenharmony_ci pow = (u16)order_base_2(num_rxq_per_tc); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* TC mapping is a function of the number of Rx queues assigned to the 104362306a36Sopenharmony_ci * VSI for each traffic class and the offset of these queues. 104462306a36Sopenharmony_ci * The first 10 bits are for queue offset for TC0, next 4 bits for no:of 104562306a36Sopenharmony_ci * queues allocated to TC0. No:of queues is a power-of-2. 104662306a36Sopenharmony_ci * 104762306a36Sopenharmony_ci * If TC is not enabled, the queue offset is set to 0, and allocate one 104862306a36Sopenharmony_ci * queue, this way, traffic for the given TC will be sent to the default 104962306a36Sopenharmony_ci * queue. 105062306a36Sopenharmony_ci * 105162306a36Sopenharmony_ci * Setup number and offset of Rx queues for all TCs for the VSI 105262306a36Sopenharmony_ci */ 105362306a36Sopenharmony_ci ice_for_each_traffic_class(i) { 105462306a36Sopenharmony_ci if (!(vsi->tc_cfg.ena_tc & BIT(i))) { 105562306a36Sopenharmony_ci /* TC is not enabled */ 105662306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qoffset = 0; 105762306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_rx = 1; 105862306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_tx = 1; 105962306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].netdev_tc = 0; 106062306a36Sopenharmony_ci ctxt->info.tc_mapping[i] = 0; 106162306a36Sopenharmony_ci continue; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci /* TC is enabled */ 106562306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qoffset = offset; 106662306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_rx = num_rxq_per_tc; 106762306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_tx = num_txq_per_tc; 106862306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].netdev_tc = netdev_tc++; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) & 107162306a36Sopenharmony_ci ICE_AQ_VSI_TC_Q_OFFSET_M) | 107262306a36Sopenharmony_ci ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & 107362306a36Sopenharmony_ci ICE_AQ_VSI_TC_Q_NUM_M); 107462306a36Sopenharmony_ci offset += num_rxq_per_tc; 107562306a36Sopenharmony_ci tx_count += num_txq_per_tc; 107662306a36Sopenharmony_ci ctxt->info.tc_mapping[i] = cpu_to_le16(qmap); 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* if offset is non-zero, means it is calculated correctly based on 108062306a36Sopenharmony_ci * enabled TCs for a given VSI otherwise qcount_rx will always 108162306a36Sopenharmony_ci * be correct and non-zero because it is based off - VSI's 108262306a36Sopenharmony_ci * allocated Rx queues which is at least 1 (hence qcount_tx will be 108362306a36Sopenharmony_ci * at least 1) 108462306a36Sopenharmony_ci */ 108562306a36Sopenharmony_ci if (offset) 108662306a36Sopenharmony_ci rx_count = offset; 108762306a36Sopenharmony_ci else 108862306a36Sopenharmony_ci rx_count = num_rxq_per_tc; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (rx_count > vsi->alloc_rxq) { 109162306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Trying to use more Rx queues (%u), than were allocated (%u)!\n", 109262306a36Sopenharmony_ci rx_count, vsi->alloc_rxq); 109362306a36Sopenharmony_ci return -EINVAL; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (tx_count > vsi->alloc_txq) { 109762306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Trying to use more Tx queues (%u), than were allocated (%u)!\n", 109862306a36Sopenharmony_ci tx_count, vsi->alloc_txq); 109962306a36Sopenharmony_ci return -EINVAL; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci vsi->num_txq = tx_count; 110362306a36Sopenharmony_ci vsi->num_rxq = rx_count; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (vsi->type == ICE_VSI_VF && vsi->num_txq != vsi->num_rxq) { 110662306a36Sopenharmony_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"); 110762306a36Sopenharmony_ci /* since there is a chance that num_rxq could have been changed 110862306a36Sopenharmony_ci * in the above for loop, make num_txq equal to num_rxq. 110962306a36Sopenharmony_ci */ 111062306a36Sopenharmony_ci vsi->num_txq = vsi->num_rxq; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* Rx queue mapping */ 111462306a36Sopenharmony_ci ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG); 111562306a36Sopenharmony_ci /* q_mapping buffer holds the info for the first queue allocated for 111662306a36Sopenharmony_ci * this VSI in the PF space and also the number of queues associated 111762306a36Sopenharmony_ci * with this VSI. 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ci ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]); 112062306a36Sopenharmony_ci ctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci/** 112662306a36Sopenharmony_ci * ice_set_fd_vsi_ctx - Set FD VSI context before adding a VSI 112762306a36Sopenharmony_ci * @ctxt: the VSI context being set 112862306a36Sopenharmony_ci * @vsi: the VSI being configured 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_cistatic void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci u8 dflt_q_group, dflt_q_prio; 113362306a36Sopenharmony_ci u16 dflt_q, report_q, val; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_CTRL && 113662306a36Sopenharmony_ci vsi->type != ICE_VSI_VF && vsi->type != ICE_VSI_CHNL) 113762306a36Sopenharmony_ci return; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci val = ICE_AQ_VSI_PROP_FLOW_DIR_VALID; 114062306a36Sopenharmony_ci ctxt->info.valid_sections |= cpu_to_le16(val); 114162306a36Sopenharmony_ci dflt_q = 0; 114262306a36Sopenharmony_ci dflt_q_group = 0; 114362306a36Sopenharmony_ci report_q = 0; 114462306a36Sopenharmony_ci dflt_q_prio = 0; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* enable flow director filtering/programming */ 114762306a36Sopenharmony_ci val = ICE_AQ_VSI_FD_ENABLE | ICE_AQ_VSI_FD_PROG_ENABLE; 114862306a36Sopenharmony_ci ctxt->info.fd_options = cpu_to_le16(val); 114962306a36Sopenharmony_ci /* max of allocated flow director filters */ 115062306a36Sopenharmony_ci ctxt->info.max_fd_fltr_dedicated = 115162306a36Sopenharmony_ci cpu_to_le16(vsi->num_gfltr); 115262306a36Sopenharmony_ci /* max of shared flow director filters any VSI may program */ 115362306a36Sopenharmony_ci ctxt->info.max_fd_fltr_shared = 115462306a36Sopenharmony_ci cpu_to_le16(vsi->num_bfltr); 115562306a36Sopenharmony_ci /* default queue index within the VSI of the default FD */ 115662306a36Sopenharmony_ci val = ((dflt_q << ICE_AQ_VSI_FD_DEF_Q_S) & 115762306a36Sopenharmony_ci ICE_AQ_VSI_FD_DEF_Q_M); 115862306a36Sopenharmony_ci /* target queue or queue group to the FD filter */ 115962306a36Sopenharmony_ci val |= ((dflt_q_group << ICE_AQ_VSI_FD_DEF_GRP_S) & 116062306a36Sopenharmony_ci ICE_AQ_VSI_FD_DEF_GRP_M); 116162306a36Sopenharmony_ci ctxt->info.fd_def_q = cpu_to_le16(val); 116262306a36Sopenharmony_ci /* queue index on which FD filter completion is reported */ 116362306a36Sopenharmony_ci val = ((report_q << ICE_AQ_VSI_FD_REPORT_Q_S) & 116462306a36Sopenharmony_ci ICE_AQ_VSI_FD_REPORT_Q_M); 116562306a36Sopenharmony_ci /* priority of the default qindex action */ 116662306a36Sopenharmony_ci val |= ((dflt_q_prio << ICE_AQ_VSI_FD_DEF_PRIORITY_S) & 116762306a36Sopenharmony_ci ICE_AQ_VSI_FD_DEF_PRIORITY_M); 116862306a36Sopenharmony_ci ctxt->info.fd_report_opt = cpu_to_le16(val); 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci/** 117262306a36Sopenharmony_ci * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI 117362306a36Sopenharmony_ci * @ctxt: the VSI context being set 117462306a36Sopenharmony_ci * @vsi: the VSI being configured 117562306a36Sopenharmony_ci */ 117662306a36Sopenharmony_cistatic void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci u8 lut_type, hash_type; 117962306a36Sopenharmony_ci struct device *dev; 118062306a36Sopenharmony_ci struct ice_pf *pf; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci pf = vsi->back; 118362306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci switch (vsi->type) { 118662306a36Sopenharmony_ci case ICE_VSI_CHNL: 118762306a36Sopenharmony_ci case ICE_VSI_PF: 118862306a36Sopenharmony_ci /* PF VSI will inherit RSS instance of PF */ 118962306a36Sopenharmony_ci lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF; 119062306a36Sopenharmony_ci hash_type = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; 119162306a36Sopenharmony_ci break; 119262306a36Sopenharmony_ci case ICE_VSI_VF: 119362306a36Sopenharmony_ci /* VF VSI will gets a small RSS table which is a VSI LUT type */ 119462306a36Sopenharmony_ci lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI; 119562306a36Sopenharmony_ci hash_type = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; 119662306a36Sopenharmony_ci break; 119762306a36Sopenharmony_ci default: 119862306a36Sopenharmony_ci dev_dbg(dev, "Unsupported VSI type %s\n", 119962306a36Sopenharmony_ci ice_vsi_type_str(vsi->type)); 120062306a36Sopenharmony_ci return; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) & 120462306a36Sopenharmony_ci ICE_AQ_VSI_Q_OPT_RSS_LUT_M) | 120562306a36Sopenharmony_ci (hash_type & ICE_AQ_VSI_Q_OPT_RSS_HASH_M); 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic void 120962306a36Sopenharmony_ciice_chnl_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 121262306a36Sopenharmony_ci u16 qcount, qmap; 121362306a36Sopenharmony_ci u8 offset = 0; 121462306a36Sopenharmony_ci int pow; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci qcount = min_t(int, vsi->num_rxq, pf->num_lan_msix); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci pow = order_base_2(qcount); 121962306a36Sopenharmony_ci qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) & 122062306a36Sopenharmony_ci ICE_AQ_VSI_TC_Q_OFFSET_M) | 122162306a36Sopenharmony_ci ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & 122262306a36Sopenharmony_ci ICE_AQ_VSI_TC_Q_NUM_M); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci ctxt->info.tc_mapping[0] = cpu_to_le16(qmap); 122562306a36Sopenharmony_ci ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG); 122662306a36Sopenharmony_ci ctxt->info.q_mapping[0] = cpu_to_le16(vsi->next_base_q); 122762306a36Sopenharmony_ci ctxt->info.q_mapping[1] = cpu_to_le16(qcount); 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci/** 123162306a36Sopenharmony_ci * ice_vsi_is_vlan_pruning_ena - check if VLAN pruning is enabled or not 123262306a36Sopenharmony_ci * @vsi: VSI to check whether or not VLAN pruning is enabled. 123362306a36Sopenharmony_ci * 123462306a36Sopenharmony_ci * returns true if Rx VLAN pruning is enabled and false otherwise. 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_cistatic bool ice_vsi_is_vlan_pruning_ena(struct ice_vsi *vsi) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci return vsi->info.sw_flags2 & ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci/** 124262306a36Sopenharmony_ci * ice_vsi_init - Create and initialize a VSI 124362306a36Sopenharmony_ci * @vsi: the VSI being configured 124462306a36Sopenharmony_ci * @vsi_flags: VSI configuration flags 124562306a36Sopenharmony_ci * 124662306a36Sopenharmony_ci * Set ICE_FLAG_VSI_INIT to initialize a new VSI context, clear it to 124762306a36Sopenharmony_ci * reconfigure an existing context. 124862306a36Sopenharmony_ci * 124962306a36Sopenharmony_ci * This initializes a VSI context depending on the VSI type to be added and 125062306a36Sopenharmony_ci * passes it down to the add_vsi aq command to create a new VSI. 125162306a36Sopenharmony_ci */ 125262306a36Sopenharmony_cistatic int ice_vsi_init(struct ice_vsi *vsi, u32 vsi_flags) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 125562306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 125662306a36Sopenharmony_ci struct ice_vsi_ctx *ctxt; 125762306a36Sopenharmony_ci struct device *dev; 125862306a36Sopenharmony_ci int ret = 0; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 126162306a36Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 126262306a36Sopenharmony_ci if (!ctxt) 126362306a36Sopenharmony_ci return -ENOMEM; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci switch (vsi->type) { 126662306a36Sopenharmony_ci case ICE_VSI_CTRL: 126762306a36Sopenharmony_ci case ICE_VSI_LB: 126862306a36Sopenharmony_ci case ICE_VSI_PF: 126962306a36Sopenharmony_ci ctxt->flags = ICE_AQ_VSI_TYPE_PF; 127062306a36Sopenharmony_ci break; 127162306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 127262306a36Sopenharmony_ci case ICE_VSI_CHNL: 127362306a36Sopenharmony_ci ctxt->flags = ICE_AQ_VSI_TYPE_VMDQ2; 127462306a36Sopenharmony_ci break; 127562306a36Sopenharmony_ci case ICE_VSI_VF: 127662306a36Sopenharmony_ci ctxt->flags = ICE_AQ_VSI_TYPE_VF; 127762306a36Sopenharmony_ci /* VF number here is the absolute VF number (0-255) */ 127862306a36Sopenharmony_ci ctxt->vf_num = vsi->vf->vf_id + hw->func_caps.vf_base_id; 127962306a36Sopenharmony_ci break; 128062306a36Sopenharmony_ci default: 128162306a36Sopenharmony_ci ret = -ENODEV; 128262306a36Sopenharmony_ci goto out; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* Handle VLAN pruning for channel VSI if main VSI has VLAN 128662306a36Sopenharmony_ci * prune enabled 128762306a36Sopenharmony_ci */ 128862306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) { 128962306a36Sopenharmony_ci struct ice_vsi *main_vsi; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci main_vsi = ice_get_main_vsi(pf); 129262306a36Sopenharmony_ci if (main_vsi && ice_vsi_is_vlan_pruning_ena(main_vsi)) 129362306a36Sopenharmony_ci ctxt->info.sw_flags2 |= 129462306a36Sopenharmony_ci ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; 129562306a36Sopenharmony_ci else 129662306a36Sopenharmony_ci ctxt->info.sw_flags2 &= 129762306a36Sopenharmony_ci ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci ice_set_dflt_vsi_ctx(hw, ctxt); 130162306a36Sopenharmony_ci if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) 130262306a36Sopenharmony_ci ice_set_fd_vsi_ctx(ctxt, vsi); 130362306a36Sopenharmony_ci /* if the switch is in VEB mode, allow VSI loopback */ 130462306a36Sopenharmony_ci if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB) 130562306a36Sopenharmony_ci ctxt->info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* Set LUT type and HASH type if RSS is enabled */ 130862306a36Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags) && 130962306a36Sopenharmony_ci vsi->type != ICE_VSI_CTRL) { 131062306a36Sopenharmony_ci ice_set_rss_vsi_ctx(ctxt, vsi); 131162306a36Sopenharmony_ci /* if updating VSI context, make sure to set valid_section: 131262306a36Sopenharmony_ci * to indicate which section of VSI context being updated 131362306a36Sopenharmony_ci */ 131462306a36Sopenharmony_ci if (!(vsi_flags & ICE_VSI_FLAG_INIT)) 131562306a36Sopenharmony_ci ctxt->info.valid_sections |= 131662306a36Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci ctxt->info.sw_id = vsi->port_info->sw_id; 132062306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) { 132162306a36Sopenharmony_ci ice_chnl_vsi_setup_q_map(vsi, ctxt); 132262306a36Sopenharmony_ci } else { 132362306a36Sopenharmony_ci ret = ice_vsi_setup_q_map(vsi, ctxt); 132462306a36Sopenharmony_ci if (ret) 132562306a36Sopenharmony_ci goto out; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (!(vsi_flags & ICE_VSI_FLAG_INIT)) 132862306a36Sopenharmony_ci /* means VSI being updated */ 132962306a36Sopenharmony_ci /* must to indicate which section of VSI context are 133062306a36Sopenharmony_ci * being modified 133162306a36Sopenharmony_ci */ 133262306a36Sopenharmony_ci ctxt->info.valid_sections |= 133362306a36Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID); 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* Allow control frames out of main VSI */ 133762306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 133862306a36Sopenharmony_ci ctxt->info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD; 133962306a36Sopenharmony_ci ctxt->info.valid_sections |= 134062306a36Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci if (vsi_flags & ICE_VSI_FLAG_INIT) { 134462306a36Sopenharmony_ci ret = ice_add_vsi(hw, vsi->idx, ctxt, NULL); 134562306a36Sopenharmony_ci if (ret) { 134662306a36Sopenharmony_ci dev_err(dev, "Add VSI failed, err %d\n", ret); 134762306a36Sopenharmony_ci ret = -EIO; 134862306a36Sopenharmony_ci goto out; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci } else { 135162306a36Sopenharmony_ci ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL); 135262306a36Sopenharmony_ci if (ret) { 135362306a36Sopenharmony_ci dev_err(dev, "Update VSI failed, err %d\n", ret); 135462306a36Sopenharmony_ci ret = -EIO; 135562306a36Sopenharmony_ci goto out; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci /* keep context for update VSI operations */ 136062306a36Sopenharmony_ci vsi->info = ctxt->info; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* record VSI number returned */ 136362306a36Sopenharmony_ci vsi->vsi_num = ctxt->vsi_num; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ciout: 136662306a36Sopenharmony_ci kfree(ctxt); 136762306a36Sopenharmony_ci return ret; 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci/** 137162306a36Sopenharmony_ci * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI 137262306a36Sopenharmony_ci * @vsi: the VSI having rings deallocated 137362306a36Sopenharmony_ci */ 137462306a36Sopenharmony_cistatic void ice_vsi_clear_rings(struct ice_vsi *vsi) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci int i; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* Avoid stale references by clearing map from vector to ring */ 137962306a36Sopenharmony_ci if (vsi->q_vectors) { 138062306a36Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 138162306a36Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (q_vector) { 138462306a36Sopenharmony_ci q_vector->tx.tx_ring = NULL; 138562306a36Sopenharmony_ci q_vector->rx.rx_ring = NULL; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (vsi->tx_rings) { 139162306a36Sopenharmony_ci ice_for_each_alloc_txq(vsi, i) { 139262306a36Sopenharmony_ci if (vsi->tx_rings[i]) { 139362306a36Sopenharmony_ci kfree_rcu(vsi->tx_rings[i], rcu); 139462306a36Sopenharmony_ci WRITE_ONCE(vsi->tx_rings[i], NULL); 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci if (vsi->rx_rings) { 139962306a36Sopenharmony_ci ice_for_each_alloc_rxq(vsi, i) { 140062306a36Sopenharmony_ci if (vsi->rx_rings[i]) { 140162306a36Sopenharmony_ci kfree_rcu(vsi->rx_rings[i], rcu); 140262306a36Sopenharmony_ci WRITE_ONCE(vsi->rx_rings[i], NULL); 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci/** 140962306a36Sopenharmony_ci * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI 141062306a36Sopenharmony_ci * @vsi: VSI which is having rings allocated 141162306a36Sopenharmony_ci */ 141262306a36Sopenharmony_cistatic int ice_vsi_alloc_rings(struct ice_vsi *vsi) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci bool dvm_ena = ice_is_dvm_ena(&vsi->back->hw); 141562306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 141662306a36Sopenharmony_ci struct device *dev; 141762306a36Sopenharmony_ci u16 i; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 142062306a36Sopenharmony_ci /* Allocate Tx rings */ 142162306a36Sopenharmony_ci ice_for_each_alloc_txq(vsi, i) { 142262306a36Sopenharmony_ci struct ice_tx_ring *ring; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci /* allocate with kzalloc(), free with kfree_rcu() */ 142562306a36Sopenharmony_ci ring = kzalloc(sizeof(*ring), GFP_KERNEL); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci if (!ring) 142862306a36Sopenharmony_ci goto err_out; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci ring->q_index = i; 143162306a36Sopenharmony_ci ring->reg_idx = vsi->txq_map[i]; 143262306a36Sopenharmony_ci ring->vsi = vsi; 143362306a36Sopenharmony_ci ring->tx_tstamps = &pf->ptp.port.tx; 143462306a36Sopenharmony_ci ring->dev = dev; 143562306a36Sopenharmony_ci ring->count = vsi->num_tx_desc; 143662306a36Sopenharmony_ci ring->txq_teid = ICE_INVAL_TEID; 143762306a36Sopenharmony_ci if (dvm_ena) 143862306a36Sopenharmony_ci ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG2; 143962306a36Sopenharmony_ci else 144062306a36Sopenharmony_ci ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG1; 144162306a36Sopenharmony_ci WRITE_ONCE(vsi->tx_rings[i], ring); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci /* Allocate Rx rings */ 144562306a36Sopenharmony_ci ice_for_each_alloc_rxq(vsi, i) { 144662306a36Sopenharmony_ci struct ice_rx_ring *ring; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* allocate with kzalloc(), free with kfree_rcu() */ 144962306a36Sopenharmony_ci ring = kzalloc(sizeof(*ring), GFP_KERNEL); 145062306a36Sopenharmony_ci if (!ring) 145162306a36Sopenharmony_ci goto err_out; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci ring->q_index = i; 145462306a36Sopenharmony_ci ring->reg_idx = vsi->rxq_map[i]; 145562306a36Sopenharmony_ci ring->vsi = vsi; 145662306a36Sopenharmony_ci ring->netdev = vsi->netdev; 145762306a36Sopenharmony_ci ring->dev = dev; 145862306a36Sopenharmony_ci ring->count = vsi->num_rx_desc; 145962306a36Sopenharmony_ci ring->cached_phctime = pf->ptp.cached_phc_time; 146062306a36Sopenharmony_ci WRITE_ONCE(vsi->rx_rings[i], ring); 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci return 0; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cierr_out: 146662306a36Sopenharmony_ci ice_vsi_clear_rings(vsi); 146762306a36Sopenharmony_ci return -ENOMEM; 146862306a36Sopenharmony_ci} 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci/** 147162306a36Sopenharmony_ci * ice_vsi_manage_rss_lut - disable/enable RSS 147262306a36Sopenharmony_ci * @vsi: the VSI being changed 147362306a36Sopenharmony_ci * @ena: boolean value indicating if this is an enable or disable request 147462306a36Sopenharmony_ci * 147562306a36Sopenharmony_ci * In the event of disable request for RSS, this function will zero out RSS 147662306a36Sopenharmony_ci * LUT, while in the event of enable request for RSS, it will reconfigure RSS 147762306a36Sopenharmony_ci * LUT. 147862306a36Sopenharmony_ci */ 147962306a36Sopenharmony_civoid ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci u8 *lut; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); 148462306a36Sopenharmony_ci if (!lut) 148562306a36Sopenharmony_ci return; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci if (ena) { 148862306a36Sopenharmony_ci if (vsi->rss_lut_user) 148962306a36Sopenharmony_ci memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); 149062306a36Sopenharmony_ci else 149162306a36Sopenharmony_ci ice_fill_rss_lut(lut, vsi->rss_table_size, 149262306a36Sopenharmony_ci vsi->rss_size); 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci ice_set_rss_lut(vsi, lut, vsi->rss_table_size); 149662306a36Sopenharmony_ci kfree(lut); 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci/** 150062306a36Sopenharmony_ci * ice_vsi_cfg_crc_strip - Configure CRC stripping for a VSI 150162306a36Sopenharmony_ci * @vsi: VSI to be configured 150262306a36Sopenharmony_ci * @disable: set to true to have FCS / CRC in the frame data 150362306a36Sopenharmony_ci */ 150462306a36Sopenharmony_civoid ice_vsi_cfg_crc_strip(struct ice_vsi *vsi, bool disable) 150562306a36Sopenharmony_ci{ 150662306a36Sopenharmony_ci int i; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) 150962306a36Sopenharmony_ci if (disable) 151062306a36Sopenharmony_ci vsi->rx_rings[i]->flags |= ICE_RX_FLAGS_CRC_STRIP_DIS; 151162306a36Sopenharmony_ci else 151262306a36Sopenharmony_ci vsi->rx_rings[i]->flags &= ~ICE_RX_FLAGS_CRC_STRIP_DIS; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci/** 151662306a36Sopenharmony_ci * ice_vsi_cfg_rss_lut_key - Configure RSS params for a VSI 151762306a36Sopenharmony_ci * @vsi: VSI to be configured 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_ciint ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 152262306a36Sopenharmony_ci struct device *dev; 152362306a36Sopenharmony_ci u8 *lut, *key; 152462306a36Sopenharmony_ci int err; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 152762306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF && vsi->ch_rss_size && 152862306a36Sopenharmony_ci (test_bit(ICE_FLAG_TC_MQPRIO, pf->flags))) { 152962306a36Sopenharmony_ci vsi->rss_size = min_t(u16, vsi->rss_size, vsi->ch_rss_size); 153062306a36Sopenharmony_ci } else { 153162306a36Sopenharmony_ci vsi->rss_size = min_t(u16, vsi->rss_size, vsi->num_rxq); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci /* If orig_rss_size is valid and it is less than determined 153462306a36Sopenharmony_ci * main VSI's rss_size, update main VSI's rss_size to be 153562306a36Sopenharmony_ci * orig_rss_size so that when tc-qdisc is deleted, main VSI 153662306a36Sopenharmony_ci * RSS table gets programmed to be correct (whatever it was 153762306a36Sopenharmony_ci * to begin with (prior to setup-tc for ADQ config) 153862306a36Sopenharmony_ci */ 153962306a36Sopenharmony_ci if (vsi->orig_rss_size && vsi->rss_size < vsi->orig_rss_size && 154062306a36Sopenharmony_ci vsi->orig_rss_size <= vsi->num_rxq) { 154162306a36Sopenharmony_ci vsi->rss_size = vsi->orig_rss_size; 154262306a36Sopenharmony_ci /* now orig_rss_size is used, reset it to zero */ 154362306a36Sopenharmony_ci vsi->orig_rss_size = 0; 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); 154862306a36Sopenharmony_ci if (!lut) 154962306a36Sopenharmony_ci return -ENOMEM; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (vsi->rss_lut_user) 155262306a36Sopenharmony_ci memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); 155362306a36Sopenharmony_ci else 155462306a36Sopenharmony_ci ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci err = ice_set_rss_lut(vsi, lut, vsi->rss_table_size); 155762306a36Sopenharmony_ci if (err) { 155862306a36Sopenharmony_ci dev_err(dev, "set_rss_lut failed, error %d\n", err); 155962306a36Sopenharmony_ci goto ice_vsi_cfg_rss_exit; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci key = kzalloc(ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE, GFP_KERNEL); 156362306a36Sopenharmony_ci if (!key) { 156462306a36Sopenharmony_ci err = -ENOMEM; 156562306a36Sopenharmony_ci goto ice_vsi_cfg_rss_exit; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci if (vsi->rss_hkey_user) 156962306a36Sopenharmony_ci memcpy(key, vsi->rss_hkey_user, ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE); 157062306a36Sopenharmony_ci else 157162306a36Sopenharmony_ci netdev_rss_key_fill((void *)key, ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci err = ice_set_rss_key(vsi, key); 157462306a36Sopenharmony_ci if (err) 157562306a36Sopenharmony_ci dev_err(dev, "set_rss_key failed, error %d\n", err); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci kfree(key); 157862306a36Sopenharmony_ciice_vsi_cfg_rss_exit: 157962306a36Sopenharmony_ci kfree(lut); 158062306a36Sopenharmony_ci return err; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci/** 158462306a36Sopenharmony_ci * ice_vsi_set_vf_rss_flow_fld - Sets VF VSI RSS input set for different flows 158562306a36Sopenharmony_ci * @vsi: VSI to be configured 158662306a36Sopenharmony_ci * 158762306a36Sopenharmony_ci * This function will only be called during the VF VSI setup. Upon successful 158862306a36Sopenharmony_ci * completion of package download, this function will configure default RSS 158962306a36Sopenharmony_ci * input sets for VF VSI. 159062306a36Sopenharmony_ci */ 159162306a36Sopenharmony_cistatic void ice_vsi_set_vf_rss_flow_fld(struct ice_vsi *vsi) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 159462306a36Sopenharmony_ci struct device *dev; 159562306a36Sopenharmony_ci int status; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 159862306a36Sopenharmony_ci if (ice_is_safe_mode(pf)) { 159962306a36Sopenharmony_ci dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", 160062306a36Sopenharmony_ci vsi->vsi_num); 160162306a36Sopenharmony_ci return; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci status = ice_add_avf_rss_cfg(&pf->hw, vsi->idx, ICE_DEFAULT_RSS_HENA); 160562306a36Sopenharmony_ci if (status) 160662306a36Sopenharmony_ci dev_dbg(dev, "ice_add_avf_rss_cfg failed for vsi = %d, error = %d\n", 160762306a36Sopenharmony_ci vsi->vsi_num, status); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci/** 161162306a36Sopenharmony_ci * ice_vsi_set_rss_flow_fld - Sets RSS input set for different flows 161262306a36Sopenharmony_ci * @vsi: VSI to be configured 161362306a36Sopenharmony_ci * 161462306a36Sopenharmony_ci * This function will only be called after successful download package call 161562306a36Sopenharmony_ci * during initialization of PF. Since the downloaded package will erase the 161662306a36Sopenharmony_ci * RSS section, this function will configure RSS input sets for different 161762306a36Sopenharmony_ci * flow types. The last profile added has the highest priority, therefore 2 161862306a36Sopenharmony_ci * tuple profiles (i.e. IPv4 src/dst) are added before 4 tuple profiles 161962306a36Sopenharmony_ci * (i.e. IPv4 src/dst TCP src/dst port). 162062306a36Sopenharmony_ci */ 162162306a36Sopenharmony_cistatic void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci u16 vsi_handle = vsi->idx, vsi_num = vsi->vsi_num; 162462306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 162562306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 162662306a36Sopenharmony_ci struct device *dev; 162762306a36Sopenharmony_ci int status; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 163062306a36Sopenharmony_ci if (ice_is_safe_mode(pf)) { 163162306a36Sopenharmony_ci dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", 163262306a36Sopenharmony_ci vsi_num); 163362306a36Sopenharmony_ci return; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci /* configure RSS for IPv4 with input set IP src/dst */ 163662306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4, 163762306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_IPV4); 163862306a36Sopenharmony_ci if (status) 163962306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for ipv4 flow, vsi = %d, error = %d\n", 164062306a36Sopenharmony_ci vsi_num, status); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci /* configure RSS for IPv6 with input set IPv6 src/dst */ 164362306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6, 164462306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_IPV6); 164562306a36Sopenharmony_ci if (status) 164662306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for ipv6 flow, vsi = %d, error = %d\n", 164762306a36Sopenharmony_ci vsi_num, status); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci /* configure RSS for tcp4 with input set IP src/dst, TCP src/dst */ 165062306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV4, 165162306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4); 165262306a36Sopenharmony_ci if (status) 165362306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for tcp4 flow, vsi = %d, error = %d\n", 165462306a36Sopenharmony_ci vsi_num, status); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci /* configure RSS for udp4 with input set IP src/dst, UDP src/dst */ 165762306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV4, 165862306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4); 165962306a36Sopenharmony_ci if (status) 166062306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for udp4 flow, vsi = %d, error = %d\n", 166162306a36Sopenharmony_ci vsi_num, status); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci /* configure RSS for sctp4 with input set IP src/dst */ 166462306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4, 166562306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4); 166662306a36Sopenharmony_ci if (status) 166762306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for sctp4 flow, vsi = %d, error = %d\n", 166862306a36Sopenharmony_ci vsi_num, status); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* configure RSS for tcp6 with input set IPv6 src/dst, TCP src/dst */ 167162306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV6, 167262306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6); 167362306a36Sopenharmony_ci if (status) 167462306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for tcp6 flow, vsi = %d, error = %d\n", 167562306a36Sopenharmony_ci vsi_num, status); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci /* configure RSS for udp6 with input set IPv6 src/dst, UDP src/dst */ 167862306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV6, 167962306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6); 168062306a36Sopenharmony_ci if (status) 168162306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for udp6 flow, vsi = %d, error = %d\n", 168262306a36Sopenharmony_ci vsi_num, status); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci /* configure RSS for sctp6 with input set IPv6 src/dst */ 168562306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6, 168662306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6); 168762306a36Sopenharmony_ci if (status) 168862306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for sctp6 flow, vsi = %d, error = %d\n", 168962306a36Sopenharmony_ci vsi_num, status); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_ESP_SPI, 169262306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_ESP); 169362306a36Sopenharmony_ci if (status) 169462306a36Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed for esp/spi flow, vsi = %d, error = %d\n", 169562306a36Sopenharmony_ci vsi_num, status); 169662306a36Sopenharmony_ci} 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci/** 169962306a36Sopenharmony_ci * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length 170062306a36Sopenharmony_ci * @vsi: VSI 170162306a36Sopenharmony_ci */ 170262306a36Sopenharmony_cistatic void ice_vsi_cfg_frame_size(struct ice_vsi *vsi) 170362306a36Sopenharmony_ci{ 170462306a36Sopenharmony_ci if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) { 170562306a36Sopenharmony_ci vsi->max_frame = ICE_MAX_FRAME_LEGACY_RX; 170662306a36Sopenharmony_ci vsi->rx_buf_len = ICE_RXBUF_1664; 170762306a36Sopenharmony_ci#if (PAGE_SIZE < 8192) 170862306a36Sopenharmony_ci } else if (!ICE_2K_TOO_SMALL_WITH_PADDING && 170962306a36Sopenharmony_ci (vsi->netdev->mtu <= ETH_DATA_LEN)) { 171062306a36Sopenharmony_ci vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; 171162306a36Sopenharmony_ci vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; 171262306a36Sopenharmony_ci#endif 171362306a36Sopenharmony_ci } else { 171462306a36Sopenharmony_ci vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; 171562306a36Sopenharmony_ci vsi->rx_buf_len = ICE_RXBUF_3072; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci} 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci/** 172062306a36Sopenharmony_ci * ice_pf_state_is_nominal - checks the PF for nominal state 172162306a36Sopenharmony_ci * @pf: pointer to PF to check 172262306a36Sopenharmony_ci * 172362306a36Sopenharmony_ci * Check the PF's state for a collection of bits that would indicate 172462306a36Sopenharmony_ci * the PF is in a state that would inhibit normal operation for 172562306a36Sopenharmony_ci * driver functionality. 172662306a36Sopenharmony_ci * 172762306a36Sopenharmony_ci * Returns true if PF is in a nominal state, false otherwise 172862306a36Sopenharmony_ci */ 172962306a36Sopenharmony_cibool ice_pf_state_is_nominal(struct ice_pf *pf) 173062306a36Sopenharmony_ci{ 173162306a36Sopenharmony_ci DECLARE_BITMAP(check_bits, ICE_STATE_NBITS) = { 0 }; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci if (!pf) 173462306a36Sopenharmony_ci return false; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci bitmap_set(check_bits, 0, ICE_STATE_NOMINAL_CHECK_BITS); 173762306a36Sopenharmony_ci if (bitmap_intersects(pf->state, check_bits, ICE_STATE_NBITS)) 173862306a36Sopenharmony_ci return false; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci return true; 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci/** 174462306a36Sopenharmony_ci * ice_update_eth_stats - Update VSI-specific ethernet statistics counters 174562306a36Sopenharmony_ci * @vsi: the VSI to be updated 174662306a36Sopenharmony_ci */ 174762306a36Sopenharmony_civoid ice_update_eth_stats(struct ice_vsi *vsi) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci struct ice_eth_stats *prev_es, *cur_es; 175062306a36Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 175162306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 175262306a36Sopenharmony_ci u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */ 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci prev_es = &vsi->eth_stats_prev; 175562306a36Sopenharmony_ci cur_es = &vsi->eth_stats; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) 175862306a36Sopenharmony_ci vsi->stat_offsets_loaded = false; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci ice_stat_update40(hw, GLV_GORCL(vsi_num), vsi->stat_offsets_loaded, 176162306a36Sopenharmony_ci &prev_es->rx_bytes, &cur_es->rx_bytes); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci ice_stat_update40(hw, GLV_UPRCL(vsi_num), vsi->stat_offsets_loaded, 176462306a36Sopenharmony_ci &prev_es->rx_unicast, &cur_es->rx_unicast); 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci ice_stat_update40(hw, GLV_MPRCL(vsi_num), vsi->stat_offsets_loaded, 176762306a36Sopenharmony_ci &prev_es->rx_multicast, &cur_es->rx_multicast); 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci ice_stat_update40(hw, GLV_BPRCL(vsi_num), vsi->stat_offsets_loaded, 177062306a36Sopenharmony_ci &prev_es->rx_broadcast, &cur_es->rx_broadcast); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci ice_stat_update32(hw, GLV_RDPC(vsi_num), vsi->stat_offsets_loaded, 177362306a36Sopenharmony_ci &prev_es->rx_discards, &cur_es->rx_discards); 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci ice_stat_update40(hw, GLV_GOTCL(vsi_num), vsi->stat_offsets_loaded, 177662306a36Sopenharmony_ci &prev_es->tx_bytes, &cur_es->tx_bytes); 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci ice_stat_update40(hw, GLV_UPTCL(vsi_num), vsi->stat_offsets_loaded, 177962306a36Sopenharmony_ci &prev_es->tx_unicast, &cur_es->tx_unicast); 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci ice_stat_update40(hw, GLV_MPTCL(vsi_num), vsi->stat_offsets_loaded, 178262306a36Sopenharmony_ci &prev_es->tx_multicast, &cur_es->tx_multicast); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci ice_stat_update40(hw, GLV_BPTCL(vsi_num), vsi->stat_offsets_loaded, 178562306a36Sopenharmony_ci &prev_es->tx_broadcast, &cur_es->tx_broadcast); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci ice_stat_update32(hw, GLV_TEPC(vsi_num), vsi->stat_offsets_loaded, 178862306a36Sopenharmony_ci &prev_es->tx_errors, &cur_es->tx_errors); 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci vsi->stat_offsets_loaded = true; 179162306a36Sopenharmony_ci} 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci/** 179462306a36Sopenharmony_ci * ice_write_qrxflxp_cntxt - write/configure QRXFLXP_CNTXT register 179562306a36Sopenharmony_ci * @hw: HW pointer 179662306a36Sopenharmony_ci * @pf_q: index of the Rx queue in the PF's queue space 179762306a36Sopenharmony_ci * @rxdid: flexible descriptor RXDID 179862306a36Sopenharmony_ci * @prio: priority for the RXDID for this queue 179962306a36Sopenharmony_ci * @ena_ts: true to enable timestamp and false to disable timestamp 180062306a36Sopenharmony_ci */ 180162306a36Sopenharmony_civoid 180262306a36Sopenharmony_ciice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio, 180362306a36Sopenharmony_ci bool ena_ts) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci int regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci /* clear any previous values */ 180862306a36Sopenharmony_ci regval &= ~(QRXFLXP_CNTXT_RXDID_IDX_M | 180962306a36Sopenharmony_ci QRXFLXP_CNTXT_RXDID_PRIO_M | 181062306a36Sopenharmony_ci QRXFLXP_CNTXT_TS_M); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & 181362306a36Sopenharmony_ci QRXFLXP_CNTXT_RXDID_IDX_M; 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci regval |= (prio << QRXFLXP_CNTXT_RXDID_PRIO_S) & 181662306a36Sopenharmony_ci QRXFLXP_CNTXT_RXDID_PRIO_M; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci if (ena_ts) 181962306a36Sopenharmony_ci /* Enable TimeSync on this queue */ 182062306a36Sopenharmony_ci regval |= QRXFLXP_CNTXT_TS_M; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci wr32(hw, QRXFLXP_CNTXT(pf_q), regval); 182362306a36Sopenharmony_ci} 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ciint ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx) 182662306a36Sopenharmony_ci{ 182762306a36Sopenharmony_ci if (q_idx >= vsi->num_rxq) 182862306a36Sopenharmony_ci return -EINVAL; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci return ice_vsi_cfg_rxq(vsi->rx_rings[q_idx]); 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ciint ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, u16 q_idx) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci struct ice_aqc_add_tx_qgrp *qg_buf; 183662306a36Sopenharmony_ci int err; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci if (q_idx >= vsi->alloc_txq || !tx_rings || !tx_rings[q_idx]) 183962306a36Sopenharmony_ci return -EINVAL; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci qg_buf = kzalloc(struct_size(qg_buf, txqs, 1), GFP_KERNEL); 184262306a36Sopenharmony_ci if (!qg_buf) 184362306a36Sopenharmony_ci return -ENOMEM; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci qg_buf->num_txqs = 1; 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci err = ice_vsi_cfg_txq(vsi, tx_rings[q_idx], qg_buf); 184862306a36Sopenharmony_ci kfree(qg_buf); 184962306a36Sopenharmony_ci return err; 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci/** 185362306a36Sopenharmony_ci * ice_vsi_cfg_rxqs - Configure the VSI for Rx 185462306a36Sopenharmony_ci * @vsi: the VSI being configured 185562306a36Sopenharmony_ci * 185662306a36Sopenharmony_ci * Return 0 on success and a negative value on error 185762306a36Sopenharmony_ci * Configure the Rx VSI for operation. 185862306a36Sopenharmony_ci */ 185962306a36Sopenharmony_ciint ice_vsi_cfg_rxqs(struct ice_vsi *vsi) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci u16 i; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 186462306a36Sopenharmony_ci goto setup_rings; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci ice_vsi_cfg_frame_size(vsi); 186762306a36Sopenharmony_cisetup_rings: 186862306a36Sopenharmony_ci /* set up individual rings */ 186962306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) { 187062306a36Sopenharmony_ci int err = ice_vsi_cfg_rxq(vsi->rx_rings[i]); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci if (err) 187362306a36Sopenharmony_ci return err; 187462306a36Sopenharmony_ci } 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci return 0; 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci/** 188062306a36Sopenharmony_ci * ice_vsi_cfg_txqs - Configure the VSI for Tx 188162306a36Sopenharmony_ci * @vsi: the VSI being configured 188262306a36Sopenharmony_ci * @rings: Tx ring array to be configured 188362306a36Sopenharmony_ci * @count: number of Tx ring array elements 188462306a36Sopenharmony_ci * 188562306a36Sopenharmony_ci * Return 0 on success and a negative value on error 188662306a36Sopenharmony_ci * Configure the Tx VSI for operation. 188762306a36Sopenharmony_ci */ 188862306a36Sopenharmony_cistatic int 188962306a36Sopenharmony_ciice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_tx_ring **rings, u16 count) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci struct ice_aqc_add_tx_qgrp *qg_buf; 189262306a36Sopenharmony_ci u16 q_idx = 0; 189362306a36Sopenharmony_ci int err = 0; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci qg_buf = kzalloc(struct_size(qg_buf, txqs, 1), GFP_KERNEL); 189662306a36Sopenharmony_ci if (!qg_buf) 189762306a36Sopenharmony_ci return -ENOMEM; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci qg_buf->num_txqs = 1; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci for (q_idx = 0; q_idx < count; q_idx++) { 190262306a36Sopenharmony_ci err = ice_vsi_cfg_txq(vsi, rings[q_idx], qg_buf); 190362306a36Sopenharmony_ci if (err) 190462306a36Sopenharmony_ci goto err_cfg_txqs; 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_cierr_cfg_txqs: 190862306a36Sopenharmony_ci kfree(qg_buf); 190962306a36Sopenharmony_ci return err; 191062306a36Sopenharmony_ci} 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci/** 191362306a36Sopenharmony_ci * ice_vsi_cfg_lan_txqs - Configure the VSI for Tx 191462306a36Sopenharmony_ci * @vsi: the VSI being configured 191562306a36Sopenharmony_ci * 191662306a36Sopenharmony_ci * Return 0 on success and a negative value on error 191762306a36Sopenharmony_ci * Configure the Tx VSI for operation. 191862306a36Sopenharmony_ci */ 191962306a36Sopenharmony_ciint ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) 192062306a36Sopenharmony_ci{ 192162306a36Sopenharmony_ci return ice_vsi_cfg_txqs(vsi, vsi->tx_rings, vsi->num_txq); 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci/** 192562306a36Sopenharmony_ci * ice_vsi_cfg_xdp_txqs - Configure Tx queues dedicated for XDP in given VSI 192662306a36Sopenharmony_ci * @vsi: the VSI being configured 192762306a36Sopenharmony_ci * 192862306a36Sopenharmony_ci * Return 0 on success and a negative value on error 192962306a36Sopenharmony_ci * Configure the Tx queues dedicated for XDP in given VSI for operation. 193062306a36Sopenharmony_ci */ 193162306a36Sopenharmony_ciint ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi) 193262306a36Sopenharmony_ci{ 193362306a36Sopenharmony_ci int ret; 193462306a36Sopenharmony_ci int i; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci ret = ice_vsi_cfg_txqs(vsi, vsi->xdp_rings, vsi->num_xdp_txq); 193762306a36Sopenharmony_ci if (ret) 193862306a36Sopenharmony_ci return ret; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) 194162306a36Sopenharmony_ci ice_tx_xsk_pool(vsi, i); 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci return 0; 194462306a36Sopenharmony_ci} 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci/** 194762306a36Sopenharmony_ci * ice_intrl_usec_to_reg - convert interrupt rate limit to register value 194862306a36Sopenharmony_ci * @intrl: interrupt rate limit in usecs 194962306a36Sopenharmony_ci * @gran: interrupt rate limit granularity in usecs 195062306a36Sopenharmony_ci * 195162306a36Sopenharmony_ci * This function converts a decimal interrupt rate limit in usecs to the format 195262306a36Sopenharmony_ci * expected by firmware. 195362306a36Sopenharmony_ci */ 195462306a36Sopenharmony_cistatic u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran) 195562306a36Sopenharmony_ci{ 195662306a36Sopenharmony_ci u32 val = intrl / gran; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (val) 195962306a36Sopenharmony_ci return val | GLINT_RATE_INTRL_ENA_M; 196062306a36Sopenharmony_ci return 0; 196162306a36Sopenharmony_ci} 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci/** 196462306a36Sopenharmony_ci * ice_write_intrl - write throttle rate limit to interrupt specific register 196562306a36Sopenharmony_ci * @q_vector: pointer to interrupt specific structure 196662306a36Sopenharmony_ci * @intrl: throttle rate limit in microseconds to write 196762306a36Sopenharmony_ci */ 196862306a36Sopenharmony_civoid ice_write_intrl(struct ice_q_vector *q_vector, u8 intrl) 196962306a36Sopenharmony_ci{ 197062306a36Sopenharmony_ci struct ice_hw *hw = &q_vector->vsi->back->hw; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci wr32(hw, GLINT_RATE(q_vector->reg_idx), 197362306a36Sopenharmony_ci ice_intrl_usec_to_reg(intrl, ICE_INTRL_GRAN_ABOVE_25)); 197462306a36Sopenharmony_ci} 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_cistatic struct ice_q_vector *ice_pull_qvec_from_rc(struct ice_ring_container *rc) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci switch (rc->type) { 197962306a36Sopenharmony_ci case ICE_RX_CONTAINER: 198062306a36Sopenharmony_ci if (rc->rx_ring) 198162306a36Sopenharmony_ci return rc->rx_ring->q_vector; 198262306a36Sopenharmony_ci break; 198362306a36Sopenharmony_ci case ICE_TX_CONTAINER: 198462306a36Sopenharmony_ci if (rc->tx_ring) 198562306a36Sopenharmony_ci return rc->tx_ring->q_vector; 198662306a36Sopenharmony_ci break; 198762306a36Sopenharmony_ci default: 198862306a36Sopenharmony_ci break; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci return NULL; 199262306a36Sopenharmony_ci} 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci/** 199562306a36Sopenharmony_ci * __ice_write_itr - write throttle rate to register 199662306a36Sopenharmony_ci * @q_vector: pointer to interrupt data structure 199762306a36Sopenharmony_ci * @rc: pointer to ring container 199862306a36Sopenharmony_ci * @itr: throttle rate in microseconds to write 199962306a36Sopenharmony_ci */ 200062306a36Sopenharmony_cistatic void __ice_write_itr(struct ice_q_vector *q_vector, 200162306a36Sopenharmony_ci struct ice_ring_container *rc, u16 itr) 200262306a36Sopenharmony_ci{ 200362306a36Sopenharmony_ci struct ice_hw *hw = &q_vector->vsi->back->hw; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci wr32(hw, GLINT_ITR(rc->itr_idx, q_vector->reg_idx), 200662306a36Sopenharmony_ci ITR_REG_ALIGN(itr) >> ICE_ITR_GRAN_S); 200762306a36Sopenharmony_ci} 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci/** 201062306a36Sopenharmony_ci * ice_write_itr - write throttle rate to queue specific register 201162306a36Sopenharmony_ci * @rc: pointer to ring container 201262306a36Sopenharmony_ci * @itr: throttle rate in microseconds to write 201362306a36Sopenharmony_ci */ 201462306a36Sopenharmony_civoid ice_write_itr(struct ice_ring_container *rc, u16 itr) 201562306a36Sopenharmony_ci{ 201662306a36Sopenharmony_ci struct ice_q_vector *q_vector; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci q_vector = ice_pull_qvec_from_rc(rc); 201962306a36Sopenharmony_ci if (!q_vector) 202062306a36Sopenharmony_ci return; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci __ice_write_itr(q_vector, rc, itr); 202362306a36Sopenharmony_ci} 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci/** 202662306a36Sopenharmony_ci * ice_set_q_vector_intrl - set up interrupt rate limiting 202762306a36Sopenharmony_ci * @q_vector: the vector to be configured 202862306a36Sopenharmony_ci * 202962306a36Sopenharmony_ci * Interrupt rate limiting is local to the vector, not per-queue so we must 203062306a36Sopenharmony_ci * detect if either ring container has dynamic moderation enabled to decide 203162306a36Sopenharmony_ci * what to set the interrupt rate limit to via INTRL settings. In the case that 203262306a36Sopenharmony_ci * dynamic moderation is disabled on both, write the value with the cached 203362306a36Sopenharmony_ci * setting to make sure INTRL register matches the user visible value. 203462306a36Sopenharmony_ci */ 203562306a36Sopenharmony_civoid ice_set_q_vector_intrl(struct ice_q_vector *q_vector) 203662306a36Sopenharmony_ci{ 203762306a36Sopenharmony_ci if (ITR_IS_DYNAMIC(&q_vector->tx) || ITR_IS_DYNAMIC(&q_vector->rx)) { 203862306a36Sopenharmony_ci /* in the case of dynamic enabled, cap each vector to no more 203962306a36Sopenharmony_ci * than (4 us) 250,000 ints/sec, which allows low latency 204062306a36Sopenharmony_ci * but still less than 500,000 interrupts per second, which 204162306a36Sopenharmony_ci * reduces CPU a bit in the case of the lowest latency 204262306a36Sopenharmony_ci * setting. The 4 here is a value in microseconds. 204362306a36Sopenharmony_ci */ 204462306a36Sopenharmony_ci ice_write_intrl(q_vector, 4); 204562306a36Sopenharmony_ci } else { 204662306a36Sopenharmony_ci ice_write_intrl(q_vector, q_vector->intrl); 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci} 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci/** 205162306a36Sopenharmony_ci * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW 205262306a36Sopenharmony_ci * @vsi: the VSI being configured 205362306a36Sopenharmony_ci * 205462306a36Sopenharmony_ci * This configures MSIX mode interrupts for the PF VSI, and should not be used 205562306a36Sopenharmony_ci * for the VF VSI. 205662306a36Sopenharmony_ci */ 205762306a36Sopenharmony_civoid ice_vsi_cfg_msix(struct ice_vsi *vsi) 205862306a36Sopenharmony_ci{ 205962306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 206062306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 206162306a36Sopenharmony_ci u16 txq = 0, rxq = 0; 206262306a36Sopenharmony_ci int i, q; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 206562306a36Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 206662306a36Sopenharmony_ci u16 reg_idx = q_vector->reg_idx; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci ice_cfg_itr(hw, q_vector); 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci /* Both Transmit Queue Interrupt Cause Control register 207162306a36Sopenharmony_ci * and Receive Queue Interrupt Cause control register 207262306a36Sopenharmony_ci * expects MSIX_INDX field to be the vector index 207362306a36Sopenharmony_ci * within the function space and not the absolute 207462306a36Sopenharmony_ci * vector index across PF or across device. 207562306a36Sopenharmony_ci * For SR-IOV VF VSIs queue vector index always starts 207662306a36Sopenharmony_ci * with 1 since first vector index(0) is used for OICR 207762306a36Sopenharmony_ci * in VF space. Since VMDq and other PF VSIs are within 207862306a36Sopenharmony_ci * the PF function space, use the vector index that is 207962306a36Sopenharmony_ci * tracked for this PF. 208062306a36Sopenharmony_ci */ 208162306a36Sopenharmony_ci for (q = 0; q < q_vector->num_ring_tx; q++) { 208262306a36Sopenharmony_ci ice_cfg_txq_interrupt(vsi, txq, reg_idx, 208362306a36Sopenharmony_ci q_vector->tx.itr_idx); 208462306a36Sopenharmony_ci txq++; 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci for (q = 0; q < q_vector->num_ring_rx; q++) { 208862306a36Sopenharmony_ci ice_cfg_rxq_interrupt(vsi, rxq, reg_idx, 208962306a36Sopenharmony_ci q_vector->rx.itr_idx); 209062306a36Sopenharmony_ci rxq++; 209162306a36Sopenharmony_ci } 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci/** 209662306a36Sopenharmony_ci * ice_vsi_start_all_rx_rings - start/enable all of a VSI's Rx rings 209762306a36Sopenharmony_ci * @vsi: the VSI whose rings are to be enabled 209862306a36Sopenharmony_ci * 209962306a36Sopenharmony_ci * Returns 0 on success and a negative value on error 210062306a36Sopenharmony_ci */ 210162306a36Sopenharmony_ciint ice_vsi_start_all_rx_rings(struct ice_vsi *vsi) 210262306a36Sopenharmony_ci{ 210362306a36Sopenharmony_ci return ice_vsi_ctrl_all_rx_rings(vsi, true); 210462306a36Sopenharmony_ci} 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci/** 210762306a36Sopenharmony_ci * ice_vsi_stop_all_rx_rings - stop/disable all of a VSI's Rx rings 210862306a36Sopenharmony_ci * @vsi: the VSI whose rings are to be disabled 210962306a36Sopenharmony_ci * 211062306a36Sopenharmony_ci * Returns 0 on success and a negative value on error 211162306a36Sopenharmony_ci */ 211262306a36Sopenharmony_ciint ice_vsi_stop_all_rx_rings(struct ice_vsi *vsi) 211362306a36Sopenharmony_ci{ 211462306a36Sopenharmony_ci return ice_vsi_ctrl_all_rx_rings(vsi, false); 211562306a36Sopenharmony_ci} 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci/** 211862306a36Sopenharmony_ci * ice_vsi_stop_tx_rings - Disable Tx rings 211962306a36Sopenharmony_ci * @vsi: the VSI being configured 212062306a36Sopenharmony_ci * @rst_src: reset source 212162306a36Sopenharmony_ci * @rel_vmvf_num: Relative ID of VF/VM 212262306a36Sopenharmony_ci * @rings: Tx ring array to be stopped 212362306a36Sopenharmony_ci * @count: number of Tx ring array elements 212462306a36Sopenharmony_ci */ 212562306a36Sopenharmony_cistatic int 212662306a36Sopenharmony_ciice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, 212762306a36Sopenharmony_ci u16 rel_vmvf_num, struct ice_tx_ring **rings, u16 count) 212862306a36Sopenharmony_ci{ 212962306a36Sopenharmony_ci u16 q_idx; 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS) 213262306a36Sopenharmony_ci return -EINVAL; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci for (q_idx = 0; q_idx < count; q_idx++) { 213562306a36Sopenharmony_ci struct ice_txq_meta txq_meta = { }; 213662306a36Sopenharmony_ci int status; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci if (!rings || !rings[q_idx]) 213962306a36Sopenharmony_ci return -EINVAL; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci ice_fill_txq_meta(vsi, rings[q_idx], &txq_meta); 214262306a36Sopenharmony_ci status = ice_vsi_stop_tx_ring(vsi, rst_src, rel_vmvf_num, 214362306a36Sopenharmony_ci rings[q_idx], &txq_meta); 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (status) 214662306a36Sopenharmony_ci return status; 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci return 0; 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci/** 215362306a36Sopenharmony_ci * ice_vsi_stop_lan_tx_rings - Disable LAN Tx rings 215462306a36Sopenharmony_ci * @vsi: the VSI being configured 215562306a36Sopenharmony_ci * @rst_src: reset source 215662306a36Sopenharmony_ci * @rel_vmvf_num: Relative ID of VF/VM 215762306a36Sopenharmony_ci */ 215862306a36Sopenharmony_ciint 215962306a36Sopenharmony_ciice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, 216062306a36Sopenharmony_ci u16 rel_vmvf_num) 216162306a36Sopenharmony_ci{ 216262306a36Sopenharmony_ci return ice_vsi_stop_tx_rings(vsi, rst_src, rel_vmvf_num, vsi->tx_rings, vsi->num_txq); 216362306a36Sopenharmony_ci} 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci/** 216662306a36Sopenharmony_ci * ice_vsi_stop_xdp_tx_rings - Disable XDP Tx rings 216762306a36Sopenharmony_ci * @vsi: the VSI being configured 216862306a36Sopenharmony_ci */ 216962306a36Sopenharmony_ciint ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi) 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci return ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0, vsi->xdp_rings, vsi->num_xdp_txq); 217262306a36Sopenharmony_ci} 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci/** 217562306a36Sopenharmony_ci * ice_vsi_is_rx_queue_active 217662306a36Sopenharmony_ci * @vsi: the VSI being configured 217762306a36Sopenharmony_ci * 217862306a36Sopenharmony_ci * Return true if at least one queue is active. 217962306a36Sopenharmony_ci */ 218062306a36Sopenharmony_cibool ice_vsi_is_rx_queue_active(struct ice_vsi *vsi) 218162306a36Sopenharmony_ci{ 218262306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 218362306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 218462306a36Sopenharmony_ci int i; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) { 218762306a36Sopenharmony_ci u32 rx_reg; 218862306a36Sopenharmony_ci int pf_q; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci pf_q = vsi->rxq_map[i]; 219162306a36Sopenharmony_ci rx_reg = rd32(hw, QRX_CTRL(pf_q)); 219262306a36Sopenharmony_ci if (rx_reg & QRX_CTRL_QENA_STAT_M) 219362306a36Sopenharmony_ci return true; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci return false; 219762306a36Sopenharmony_ci} 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cistatic void ice_vsi_set_tc_cfg(struct ice_vsi *vsi) 220062306a36Sopenharmony_ci{ 220162306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_DCB_ENA, vsi->back->flags)) { 220262306a36Sopenharmony_ci vsi->tc_cfg.ena_tc = ICE_DFLT_TRAFFIC_CLASS; 220362306a36Sopenharmony_ci vsi->tc_cfg.numtc = 1; 220462306a36Sopenharmony_ci return; 220562306a36Sopenharmony_ci } 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci /* set VSI TC information based on DCB config */ 220862306a36Sopenharmony_ci ice_vsi_set_dcb_tc_cfg(vsi); 220962306a36Sopenharmony_ci} 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci/** 221262306a36Sopenharmony_ci * ice_cfg_sw_lldp - Config switch rules for LLDP packet handling 221362306a36Sopenharmony_ci * @vsi: the VSI being configured 221462306a36Sopenharmony_ci * @tx: bool to determine Tx or Rx rule 221562306a36Sopenharmony_ci * @create: bool to determine create or remove Rule 221662306a36Sopenharmony_ci */ 221762306a36Sopenharmony_civoid ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create) 221862306a36Sopenharmony_ci{ 221962306a36Sopenharmony_ci int (*eth_fltr)(struct ice_vsi *v, u16 type, u16 flag, 222062306a36Sopenharmony_ci enum ice_sw_fwd_act_type act); 222162306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 222262306a36Sopenharmony_ci struct device *dev; 222362306a36Sopenharmony_ci int status; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 222662306a36Sopenharmony_ci eth_fltr = create ? ice_fltr_add_eth : ice_fltr_remove_eth; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (tx) { 222962306a36Sopenharmony_ci status = eth_fltr(vsi, ETH_P_LLDP, ICE_FLTR_TX, 223062306a36Sopenharmony_ci ICE_DROP_PACKET); 223162306a36Sopenharmony_ci } else { 223262306a36Sopenharmony_ci if (ice_fw_supports_lldp_fltr_ctrl(&pf->hw)) { 223362306a36Sopenharmony_ci status = ice_lldp_fltr_add_remove(&pf->hw, vsi->vsi_num, 223462306a36Sopenharmony_ci create); 223562306a36Sopenharmony_ci } else { 223662306a36Sopenharmony_ci status = eth_fltr(vsi, ETH_P_LLDP, ICE_FLTR_RX, 223762306a36Sopenharmony_ci ICE_FWD_TO_VSI); 223862306a36Sopenharmony_ci } 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci if (status) 224262306a36Sopenharmony_ci dev_dbg(dev, "Fail %s %s LLDP rule on VSI %i error: %d\n", 224362306a36Sopenharmony_ci create ? "adding" : "removing", tx ? "TX" : "RX", 224462306a36Sopenharmony_ci vsi->vsi_num, status); 224562306a36Sopenharmony_ci} 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci/** 224862306a36Sopenharmony_ci * ice_set_agg_vsi - sets up scheduler aggregator node and move VSI into it 224962306a36Sopenharmony_ci * @vsi: pointer to the VSI 225062306a36Sopenharmony_ci * 225162306a36Sopenharmony_ci * This function will allocate new scheduler aggregator now if needed and will 225262306a36Sopenharmony_ci * move specified VSI into it. 225362306a36Sopenharmony_ci */ 225462306a36Sopenharmony_cistatic void ice_set_agg_vsi(struct ice_vsi *vsi) 225562306a36Sopenharmony_ci{ 225662306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(vsi->back); 225762306a36Sopenharmony_ci struct ice_agg_node *agg_node_iter = NULL; 225862306a36Sopenharmony_ci u32 agg_id = ICE_INVALID_AGG_NODE_ID; 225962306a36Sopenharmony_ci struct ice_agg_node *agg_node = NULL; 226062306a36Sopenharmony_ci int node_offset, max_agg_nodes = 0; 226162306a36Sopenharmony_ci struct ice_port_info *port_info; 226262306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 226362306a36Sopenharmony_ci u32 agg_node_id_start = 0; 226462306a36Sopenharmony_ci int status; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci /* create (as needed) scheduler aggregator node and move VSI into 226762306a36Sopenharmony_ci * corresponding aggregator node 226862306a36Sopenharmony_ci * - PF aggregator node to contains VSIs of type _PF and _CTRL 226962306a36Sopenharmony_ci * - VF aggregator nodes will contain VF VSI 227062306a36Sopenharmony_ci */ 227162306a36Sopenharmony_ci port_info = pf->hw.port_info; 227262306a36Sopenharmony_ci if (!port_info) 227362306a36Sopenharmony_ci return; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci switch (vsi->type) { 227662306a36Sopenharmony_ci case ICE_VSI_CTRL: 227762306a36Sopenharmony_ci case ICE_VSI_CHNL: 227862306a36Sopenharmony_ci case ICE_VSI_LB: 227962306a36Sopenharmony_ci case ICE_VSI_PF: 228062306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 228162306a36Sopenharmony_ci max_agg_nodes = ICE_MAX_PF_AGG_NODES; 228262306a36Sopenharmony_ci agg_node_id_start = ICE_PF_AGG_NODE_ID_START; 228362306a36Sopenharmony_ci agg_node_iter = &pf->pf_agg_node[0]; 228462306a36Sopenharmony_ci break; 228562306a36Sopenharmony_ci case ICE_VSI_VF: 228662306a36Sopenharmony_ci /* user can create 'n' VFs on a given PF, but since max children 228762306a36Sopenharmony_ci * per aggregator node can be only 64. Following code handles 228862306a36Sopenharmony_ci * aggregator(s) for VF VSIs, either selects a agg_node which 228962306a36Sopenharmony_ci * was already created provided num_vsis < 64, otherwise 229062306a36Sopenharmony_ci * select next available node, which will be created 229162306a36Sopenharmony_ci */ 229262306a36Sopenharmony_ci max_agg_nodes = ICE_MAX_VF_AGG_NODES; 229362306a36Sopenharmony_ci agg_node_id_start = ICE_VF_AGG_NODE_ID_START; 229462306a36Sopenharmony_ci agg_node_iter = &pf->vf_agg_node[0]; 229562306a36Sopenharmony_ci break; 229662306a36Sopenharmony_ci default: 229762306a36Sopenharmony_ci /* other VSI type, handle later if needed */ 229862306a36Sopenharmony_ci dev_dbg(dev, "unexpected VSI type %s\n", 229962306a36Sopenharmony_ci ice_vsi_type_str(vsi->type)); 230062306a36Sopenharmony_ci return; 230162306a36Sopenharmony_ci } 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci /* find the appropriate aggregator node */ 230462306a36Sopenharmony_ci for (node_offset = 0; node_offset < max_agg_nodes; node_offset++) { 230562306a36Sopenharmony_ci /* see if we can find space in previously created 230662306a36Sopenharmony_ci * node if num_vsis < 64, otherwise skip 230762306a36Sopenharmony_ci */ 230862306a36Sopenharmony_ci if (agg_node_iter->num_vsis && 230962306a36Sopenharmony_ci agg_node_iter->num_vsis == ICE_MAX_VSIS_IN_AGG_NODE) { 231062306a36Sopenharmony_ci agg_node_iter++; 231162306a36Sopenharmony_ci continue; 231262306a36Sopenharmony_ci } 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci if (agg_node_iter->valid && 231562306a36Sopenharmony_ci agg_node_iter->agg_id != ICE_INVALID_AGG_NODE_ID) { 231662306a36Sopenharmony_ci agg_id = agg_node_iter->agg_id; 231762306a36Sopenharmony_ci agg_node = agg_node_iter; 231862306a36Sopenharmony_ci break; 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci /* find unclaimed agg_id */ 232262306a36Sopenharmony_ci if (agg_node_iter->agg_id == ICE_INVALID_AGG_NODE_ID) { 232362306a36Sopenharmony_ci agg_id = node_offset + agg_node_id_start; 232462306a36Sopenharmony_ci agg_node = agg_node_iter; 232562306a36Sopenharmony_ci break; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci /* move to next agg_node */ 232862306a36Sopenharmony_ci agg_node_iter++; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci if (!agg_node) 233262306a36Sopenharmony_ci return; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci /* if selected aggregator node was not created, create it */ 233562306a36Sopenharmony_ci if (!agg_node->valid) { 233662306a36Sopenharmony_ci status = ice_cfg_agg(port_info, agg_id, ICE_AGG_TYPE_AGG, 233762306a36Sopenharmony_ci (u8)vsi->tc_cfg.ena_tc); 233862306a36Sopenharmony_ci if (status) { 233962306a36Sopenharmony_ci dev_err(dev, "unable to create aggregator node with agg_id %u\n", 234062306a36Sopenharmony_ci agg_id); 234162306a36Sopenharmony_ci return; 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci /* aggregator node is created, store the needed info */ 234462306a36Sopenharmony_ci agg_node->valid = true; 234562306a36Sopenharmony_ci agg_node->agg_id = agg_id; 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci /* move VSI to corresponding aggregator node */ 234962306a36Sopenharmony_ci status = ice_move_vsi_to_agg(port_info, agg_id, vsi->idx, 235062306a36Sopenharmony_ci (u8)vsi->tc_cfg.ena_tc); 235162306a36Sopenharmony_ci if (status) { 235262306a36Sopenharmony_ci dev_err(dev, "unable to move VSI idx %u into aggregator %u node", 235362306a36Sopenharmony_ci vsi->idx, agg_id); 235462306a36Sopenharmony_ci return; 235562306a36Sopenharmony_ci } 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci /* keep active children count for aggregator node */ 235862306a36Sopenharmony_ci agg_node->num_vsis++; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci /* cache the 'agg_id' in VSI, so that after reset - VSI will be moved 236162306a36Sopenharmony_ci * to aggregator node 236262306a36Sopenharmony_ci */ 236362306a36Sopenharmony_ci vsi->agg_node = agg_node; 236462306a36Sopenharmony_ci dev_dbg(dev, "successfully moved VSI idx %u tc_bitmap 0x%x) into aggregator node %d which has num_vsis %u\n", 236562306a36Sopenharmony_ci vsi->idx, vsi->tc_cfg.ena_tc, vsi->agg_node->agg_id, 236662306a36Sopenharmony_ci vsi->agg_node->num_vsis); 236762306a36Sopenharmony_ci} 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_cistatic int ice_vsi_cfg_tc_lan(struct ice_pf *pf, struct ice_vsi *vsi) 237062306a36Sopenharmony_ci{ 237162306a36Sopenharmony_ci u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 237262306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 237362306a36Sopenharmony_ci int ret, i; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci /* configure VSI nodes based on number of queues and TC's */ 237662306a36Sopenharmony_ci ice_for_each_traffic_class(i) { 237762306a36Sopenharmony_ci if (!(vsi->tc_cfg.ena_tc & BIT(i))) 237862306a36Sopenharmony_ci continue; 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) { 238162306a36Sopenharmony_ci if (!vsi->alloc_txq && vsi->num_txq) 238262306a36Sopenharmony_ci max_txqs[i] = vsi->num_txq; 238362306a36Sopenharmony_ci else 238462306a36Sopenharmony_ci max_txqs[i] = pf->num_lan_tx; 238562306a36Sopenharmony_ci } else { 238662306a36Sopenharmony_ci max_txqs[i] = vsi->alloc_txq; 238762306a36Sopenharmony_ci } 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF) 239062306a36Sopenharmony_ci max_txqs[i] += vsi->num_xdp_txq; 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci dev_dbg(dev, "vsi->tc_cfg.ena_tc = %d\n", vsi->tc_cfg.ena_tc); 239462306a36Sopenharmony_ci ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, 239562306a36Sopenharmony_ci max_txqs); 239662306a36Sopenharmony_ci if (ret) { 239762306a36Sopenharmony_ci dev_err(dev, "VSI %d failed lan queue config, error %d\n", 239862306a36Sopenharmony_ci vsi->vsi_num, ret); 239962306a36Sopenharmony_ci return ret; 240062306a36Sopenharmony_ci } 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci return 0; 240362306a36Sopenharmony_ci} 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci/** 240662306a36Sopenharmony_ci * ice_vsi_cfg_def - configure default VSI based on the type 240762306a36Sopenharmony_ci * @vsi: pointer to VSI 240862306a36Sopenharmony_ci * @params: the parameters to configure this VSI with 240962306a36Sopenharmony_ci */ 241062306a36Sopenharmony_cistatic int 241162306a36Sopenharmony_ciice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) 241262306a36Sopenharmony_ci{ 241362306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(vsi->back); 241462306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 241562306a36Sopenharmony_ci int ret; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci vsi->vsw = pf->first_sw; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci ret = ice_vsi_alloc_def(vsi, params->ch); 242062306a36Sopenharmony_ci if (ret) 242162306a36Sopenharmony_ci return ret; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci /* allocate memory for Tx/Rx ring stat pointers */ 242462306a36Sopenharmony_ci ret = ice_vsi_alloc_stat_arrays(vsi); 242562306a36Sopenharmony_ci if (ret) 242662306a36Sopenharmony_ci goto unroll_vsi_alloc; 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci ice_alloc_fd_res(vsi); 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci ret = ice_vsi_get_qs(vsi); 243162306a36Sopenharmony_ci if (ret) { 243262306a36Sopenharmony_ci dev_err(dev, "Failed to allocate queues. vsi->idx = %d\n", 243362306a36Sopenharmony_ci vsi->idx); 243462306a36Sopenharmony_ci goto unroll_vsi_alloc_stat; 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci /* set RSS capabilities */ 243862306a36Sopenharmony_ci ice_vsi_set_rss_params(vsi); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci /* set TC configuration */ 244162306a36Sopenharmony_ci ice_vsi_set_tc_cfg(vsi); 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci /* create the VSI */ 244462306a36Sopenharmony_ci ret = ice_vsi_init(vsi, params->flags); 244562306a36Sopenharmony_ci if (ret) 244662306a36Sopenharmony_ci goto unroll_get_qs; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci ice_vsi_init_vlan_ops(vsi); 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci switch (vsi->type) { 245162306a36Sopenharmony_ci case ICE_VSI_CTRL: 245262306a36Sopenharmony_ci case ICE_VSI_SWITCHDEV_CTRL: 245362306a36Sopenharmony_ci case ICE_VSI_PF: 245462306a36Sopenharmony_ci ret = ice_vsi_alloc_q_vectors(vsi); 245562306a36Sopenharmony_ci if (ret) 245662306a36Sopenharmony_ci goto unroll_vsi_init; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 245962306a36Sopenharmony_ci if (ret) 246062306a36Sopenharmony_ci goto unroll_vector_base; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci ret = ice_vsi_alloc_ring_stats(vsi); 246362306a36Sopenharmony_ci if (ret) 246462306a36Sopenharmony_ci goto unroll_vector_base; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci ice_vsi_map_rings_to_vectors(vsi); 246762306a36Sopenharmony_ci vsi->stat_offsets_loaded = false; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) { 247062306a36Sopenharmony_ci ret = ice_vsi_determine_xdp_res(vsi); 247162306a36Sopenharmony_ci if (ret) 247262306a36Sopenharmony_ci goto unroll_vector_base; 247362306a36Sopenharmony_ci ret = ice_prepare_xdp_rings(vsi, vsi->xdp_prog); 247462306a36Sopenharmony_ci if (ret) 247562306a36Sopenharmony_ci goto unroll_vector_base; 247662306a36Sopenharmony_ci } 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci /* ICE_VSI_CTRL does not need RSS so skip RSS processing */ 247962306a36Sopenharmony_ci if (vsi->type != ICE_VSI_CTRL) 248062306a36Sopenharmony_ci /* Do not exit if configuring RSS had an issue, at 248162306a36Sopenharmony_ci * least receive traffic on first queue. Hence no 248262306a36Sopenharmony_ci * need to capture return value 248362306a36Sopenharmony_ci */ 248462306a36Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 248562306a36Sopenharmony_ci ice_vsi_cfg_rss_lut_key(vsi); 248662306a36Sopenharmony_ci ice_vsi_set_rss_flow_fld(vsi); 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci ice_init_arfs(vsi); 248962306a36Sopenharmony_ci break; 249062306a36Sopenharmony_ci case ICE_VSI_CHNL: 249162306a36Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 249262306a36Sopenharmony_ci ice_vsi_cfg_rss_lut_key(vsi); 249362306a36Sopenharmony_ci ice_vsi_set_rss_flow_fld(vsi); 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci break; 249662306a36Sopenharmony_ci case ICE_VSI_VF: 249762306a36Sopenharmony_ci /* VF driver will take care of creating netdev for this type and 249862306a36Sopenharmony_ci * map queues to vectors through Virtchnl, PF driver only 249962306a36Sopenharmony_ci * creates a VSI and corresponding structures for bookkeeping 250062306a36Sopenharmony_ci * purpose 250162306a36Sopenharmony_ci */ 250262306a36Sopenharmony_ci ret = ice_vsi_alloc_q_vectors(vsi); 250362306a36Sopenharmony_ci if (ret) 250462306a36Sopenharmony_ci goto unroll_vsi_init; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 250762306a36Sopenharmony_ci if (ret) 250862306a36Sopenharmony_ci goto unroll_alloc_q_vector; 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci ret = ice_vsi_alloc_ring_stats(vsi); 251162306a36Sopenharmony_ci if (ret) 251262306a36Sopenharmony_ci goto unroll_vector_base; 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci vsi->stat_offsets_loaded = false; 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci /* Do not exit if configuring RSS had an issue, at least 251762306a36Sopenharmony_ci * receive traffic on first queue. Hence no need to capture 251862306a36Sopenharmony_ci * return value 251962306a36Sopenharmony_ci */ 252062306a36Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 252162306a36Sopenharmony_ci ice_vsi_cfg_rss_lut_key(vsi); 252262306a36Sopenharmony_ci ice_vsi_set_vf_rss_flow_fld(vsi); 252362306a36Sopenharmony_ci } 252462306a36Sopenharmony_ci break; 252562306a36Sopenharmony_ci case ICE_VSI_LB: 252662306a36Sopenharmony_ci ret = ice_vsi_alloc_rings(vsi); 252762306a36Sopenharmony_ci if (ret) 252862306a36Sopenharmony_ci goto unroll_vsi_init; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci ret = ice_vsi_alloc_ring_stats(vsi); 253162306a36Sopenharmony_ci if (ret) 253262306a36Sopenharmony_ci goto unroll_vector_base; 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci break; 253562306a36Sopenharmony_ci default: 253662306a36Sopenharmony_ci /* clean up the resources and exit */ 253762306a36Sopenharmony_ci ret = -EINVAL; 253862306a36Sopenharmony_ci goto unroll_vsi_init; 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci return 0; 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ciunroll_vector_base: 254462306a36Sopenharmony_ci /* reclaim SW interrupts back to the common pool */ 254562306a36Sopenharmony_ciunroll_alloc_q_vector: 254662306a36Sopenharmony_ci ice_vsi_free_q_vectors(vsi); 254762306a36Sopenharmony_ciunroll_vsi_init: 254862306a36Sopenharmony_ci ice_vsi_delete_from_hw(vsi); 254962306a36Sopenharmony_ciunroll_get_qs: 255062306a36Sopenharmony_ci ice_vsi_put_qs(vsi); 255162306a36Sopenharmony_ciunroll_vsi_alloc_stat: 255262306a36Sopenharmony_ci ice_vsi_free_stats(vsi); 255362306a36Sopenharmony_ciunroll_vsi_alloc: 255462306a36Sopenharmony_ci ice_vsi_free_arrays(vsi); 255562306a36Sopenharmony_ci return ret; 255662306a36Sopenharmony_ci} 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci/** 255962306a36Sopenharmony_ci * ice_vsi_cfg - configure a previously allocated VSI 256062306a36Sopenharmony_ci * @vsi: pointer to VSI 256162306a36Sopenharmony_ci * @params: parameters used to configure this VSI 256262306a36Sopenharmony_ci */ 256362306a36Sopenharmony_ciint ice_vsi_cfg(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 256662306a36Sopenharmony_ci int ret; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci if (WARN_ON(params->type == ICE_VSI_VF && !params->vf)) 256962306a36Sopenharmony_ci return -EINVAL; 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci vsi->type = params->type; 257262306a36Sopenharmony_ci vsi->port_info = params->pi; 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci /* For VSIs which don't have a connected VF, this will be NULL */ 257562306a36Sopenharmony_ci vsi->vf = params->vf; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci ret = ice_vsi_cfg_def(vsi, params); 257862306a36Sopenharmony_ci if (ret) 257962306a36Sopenharmony_ci return ret; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci ret = ice_vsi_cfg_tc_lan(vsi->back, vsi); 258262306a36Sopenharmony_ci if (ret) 258362306a36Sopenharmony_ci ice_vsi_decfg(vsi); 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CTRL) { 258662306a36Sopenharmony_ci if (vsi->vf) { 258762306a36Sopenharmony_ci WARN_ON(vsi->vf->ctrl_vsi_idx != ICE_NO_VSI); 258862306a36Sopenharmony_ci vsi->vf->ctrl_vsi_idx = vsi->idx; 258962306a36Sopenharmony_ci } else { 259062306a36Sopenharmony_ci WARN_ON(pf->ctrl_vsi_idx != ICE_NO_VSI); 259162306a36Sopenharmony_ci pf->ctrl_vsi_idx = vsi->idx; 259262306a36Sopenharmony_ci } 259362306a36Sopenharmony_ci } 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci return ret; 259662306a36Sopenharmony_ci} 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci/** 259962306a36Sopenharmony_ci * ice_vsi_decfg - remove all VSI configuration 260062306a36Sopenharmony_ci * @vsi: pointer to VSI 260162306a36Sopenharmony_ci */ 260262306a36Sopenharmony_civoid ice_vsi_decfg(struct ice_vsi *vsi) 260362306a36Sopenharmony_ci{ 260462306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 260562306a36Sopenharmony_ci int err; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci /* The Rx rule will only exist to remove if the LLDP FW 260862306a36Sopenharmony_ci * engine is currently stopped 260962306a36Sopenharmony_ci */ 261062306a36Sopenharmony_ci if (!ice_is_safe_mode(pf) && vsi->type == ICE_VSI_PF && 261162306a36Sopenharmony_ci !test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) 261262306a36Sopenharmony_ci ice_cfg_sw_lldp(vsi, false, false); 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx); 261562306a36Sopenharmony_ci err = ice_rm_vsi_rdma_cfg(vsi->port_info, vsi->idx); 261662306a36Sopenharmony_ci if (err) 261762306a36Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Failed to remove RDMA scheduler config for VSI %u, err %d\n", 261862306a36Sopenharmony_ci vsi->vsi_num, err); 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) 262162306a36Sopenharmony_ci /* return value check can be skipped here, it always returns 262262306a36Sopenharmony_ci * 0 if reset is in progress 262362306a36Sopenharmony_ci */ 262462306a36Sopenharmony_ci ice_destroy_xdp_rings(vsi); 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci ice_vsi_clear_rings(vsi); 262762306a36Sopenharmony_ci ice_vsi_free_q_vectors(vsi); 262862306a36Sopenharmony_ci ice_vsi_put_qs(vsi); 262962306a36Sopenharmony_ci ice_vsi_free_arrays(vsi); 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_ci /* SR-IOV determines needed MSIX resources all at once instead of per 263262306a36Sopenharmony_ci * VSI since when VFs are spawned we know how many VFs there are and how 263362306a36Sopenharmony_ci * many interrupts each VF needs. SR-IOV MSIX resources are also 263462306a36Sopenharmony_ci * cleared in the same manner. 263562306a36Sopenharmony_ci */ 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci if (vsi->type == ICE_VSI_VF && 263862306a36Sopenharmony_ci vsi->agg_node && vsi->agg_node->valid) 263962306a36Sopenharmony_ci vsi->agg_node->num_vsis--; 264062306a36Sopenharmony_ci} 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci/** 264362306a36Sopenharmony_ci * ice_vsi_setup - Set up a VSI by a given type 264462306a36Sopenharmony_ci * @pf: board private structure 264562306a36Sopenharmony_ci * @params: parameters to use when creating the VSI 264662306a36Sopenharmony_ci * 264762306a36Sopenharmony_ci * This allocates the sw VSI structure and its queue resources. 264862306a36Sopenharmony_ci * 264962306a36Sopenharmony_ci * Returns pointer to the successfully allocated and configured VSI sw struct on 265062306a36Sopenharmony_ci * success, NULL on failure. 265162306a36Sopenharmony_ci */ 265262306a36Sopenharmony_cistruct ice_vsi * 265362306a36Sopenharmony_ciice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params) 265462306a36Sopenharmony_ci{ 265562306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 265662306a36Sopenharmony_ci struct ice_vsi *vsi; 265762306a36Sopenharmony_ci int ret; 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci /* ice_vsi_setup can only initialize a new VSI, and we must have 266062306a36Sopenharmony_ci * a port_info structure for it. 266162306a36Sopenharmony_ci */ 266262306a36Sopenharmony_ci if (WARN_ON(!(params->flags & ICE_VSI_FLAG_INIT)) || 266362306a36Sopenharmony_ci WARN_ON(!params->pi)) 266462306a36Sopenharmony_ci return NULL; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci vsi = ice_vsi_alloc(pf); 266762306a36Sopenharmony_ci if (!vsi) { 266862306a36Sopenharmony_ci dev_err(dev, "could not allocate VSI\n"); 266962306a36Sopenharmony_ci return NULL; 267062306a36Sopenharmony_ci } 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci ret = ice_vsi_cfg(vsi, params); 267362306a36Sopenharmony_ci if (ret) 267462306a36Sopenharmony_ci goto err_vsi_cfg; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci /* Add switch rule to drop all Tx Flow Control Frames, of look up 267762306a36Sopenharmony_ci * type ETHERTYPE from VSIs, and restrict malicious VF from sending 267862306a36Sopenharmony_ci * out PAUSE or PFC frames. If enabled, FW can still send FC frames. 267962306a36Sopenharmony_ci * The rule is added once for PF VSI in order to create appropriate 268062306a36Sopenharmony_ci * recipe, since VSI/VSI list is ignored with drop action... 268162306a36Sopenharmony_ci * Also add rules to handle LLDP Tx packets. Tx LLDP packets need to 268262306a36Sopenharmony_ci * be dropped so that VFs cannot send LLDP packets to reconfig DCB 268362306a36Sopenharmony_ci * settings in the HW. 268462306a36Sopenharmony_ci */ 268562306a36Sopenharmony_ci if (!ice_is_safe_mode(pf) && vsi->type == ICE_VSI_PF) { 268662306a36Sopenharmony_ci ice_fltr_add_eth(vsi, ETH_P_PAUSE, ICE_FLTR_TX, 268762306a36Sopenharmony_ci ICE_DROP_PACKET); 268862306a36Sopenharmony_ci ice_cfg_sw_lldp(vsi, true, true); 268962306a36Sopenharmony_ci } 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci if (!vsi->agg_node) 269262306a36Sopenharmony_ci ice_set_agg_vsi(vsi); 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci return vsi; 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_cierr_vsi_cfg: 269762306a36Sopenharmony_ci ice_vsi_free(vsi); 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci return NULL; 270062306a36Sopenharmony_ci} 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci/** 270362306a36Sopenharmony_ci * ice_vsi_release_msix - Clear the queue to Interrupt mapping in HW 270462306a36Sopenharmony_ci * @vsi: the VSI being cleaned up 270562306a36Sopenharmony_ci */ 270662306a36Sopenharmony_cistatic void ice_vsi_release_msix(struct ice_vsi *vsi) 270762306a36Sopenharmony_ci{ 270862306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 270962306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 271062306a36Sopenharmony_ci u32 txq = 0; 271162306a36Sopenharmony_ci u32 rxq = 0; 271262306a36Sopenharmony_ci int i, q; 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 271562306a36Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci ice_write_intrl(q_vector, 0); 271862306a36Sopenharmony_ci for (q = 0; q < q_vector->num_ring_tx; q++) { 271962306a36Sopenharmony_ci ice_write_itr(&q_vector->tx, 0); 272062306a36Sopenharmony_ci wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0); 272162306a36Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) { 272262306a36Sopenharmony_ci u32 xdp_txq = txq + vsi->num_xdp_txq; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci wr32(hw, QINT_TQCTL(vsi->txq_map[xdp_txq]), 0); 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci txq++; 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci for (q = 0; q < q_vector->num_ring_rx; q++) { 273062306a36Sopenharmony_ci ice_write_itr(&q_vector->rx, 0); 273162306a36Sopenharmony_ci wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), 0); 273262306a36Sopenharmony_ci rxq++; 273362306a36Sopenharmony_ci } 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci ice_flush(hw); 273762306a36Sopenharmony_ci} 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci/** 274062306a36Sopenharmony_ci * ice_vsi_free_irq - Free the IRQ association with the OS 274162306a36Sopenharmony_ci * @vsi: the VSI being configured 274262306a36Sopenharmony_ci */ 274362306a36Sopenharmony_civoid ice_vsi_free_irq(struct ice_vsi *vsi) 274462306a36Sopenharmony_ci{ 274562306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 274662306a36Sopenharmony_ci int i; 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci if (!vsi->q_vectors || !vsi->irqs_ready) 274962306a36Sopenharmony_ci return; 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci ice_vsi_release_msix(vsi); 275262306a36Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 275362306a36Sopenharmony_ci return; 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci vsi->irqs_ready = false; 275662306a36Sopenharmony_ci ice_free_cpu_rx_rmap(vsi); 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 275962306a36Sopenharmony_ci int irq_num; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci irq_num = vsi->q_vectors[i]->irq.virq; 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci /* free only the irqs that were actually requested */ 276462306a36Sopenharmony_ci if (!vsi->q_vectors[i] || 276562306a36Sopenharmony_ci !(vsi->q_vectors[i]->num_ring_tx || 276662306a36Sopenharmony_ci vsi->q_vectors[i]->num_ring_rx)) 276762306a36Sopenharmony_ci continue; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci /* clear the affinity notifier in the IRQ descriptor */ 277062306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_RFS_ACCEL)) 277162306a36Sopenharmony_ci irq_set_affinity_notifier(irq_num, NULL); 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci /* clear the affinity_mask in the IRQ descriptor */ 277462306a36Sopenharmony_ci irq_set_affinity_hint(irq_num, NULL); 277562306a36Sopenharmony_ci synchronize_irq(irq_num); 277662306a36Sopenharmony_ci devm_free_irq(ice_pf_to_dev(pf), irq_num, vsi->q_vectors[i]); 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci} 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci/** 278162306a36Sopenharmony_ci * ice_vsi_free_tx_rings - Free Tx resources for VSI queues 278262306a36Sopenharmony_ci * @vsi: the VSI having resources freed 278362306a36Sopenharmony_ci */ 278462306a36Sopenharmony_civoid ice_vsi_free_tx_rings(struct ice_vsi *vsi) 278562306a36Sopenharmony_ci{ 278662306a36Sopenharmony_ci int i; 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci if (!vsi->tx_rings) 278962306a36Sopenharmony_ci return; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci ice_for_each_txq(vsi, i) 279262306a36Sopenharmony_ci if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) 279362306a36Sopenharmony_ci ice_free_tx_ring(vsi->tx_rings[i]); 279462306a36Sopenharmony_ci} 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci/** 279762306a36Sopenharmony_ci * ice_vsi_free_rx_rings - Free Rx resources for VSI queues 279862306a36Sopenharmony_ci * @vsi: the VSI having resources freed 279962306a36Sopenharmony_ci */ 280062306a36Sopenharmony_civoid ice_vsi_free_rx_rings(struct ice_vsi *vsi) 280162306a36Sopenharmony_ci{ 280262306a36Sopenharmony_ci int i; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci if (!vsi->rx_rings) 280562306a36Sopenharmony_ci return; 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) 280862306a36Sopenharmony_ci if (vsi->rx_rings[i] && vsi->rx_rings[i]->desc) 280962306a36Sopenharmony_ci ice_free_rx_ring(vsi->rx_rings[i]); 281062306a36Sopenharmony_ci} 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci/** 281362306a36Sopenharmony_ci * ice_vsi_close - Shut down a VSI 281462306a36Sopenharmony_ci * @vsi: the VSI being shut down 281562306a36Sopenharmony_ci */ 281662306a36Sopenharmony_civoid ice_vsi_close(struct ice_vsi *vsi) 281762306a36Sopenharmony_ci{ 281862306a36Sopenharmony_ci if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state)) 281962306a36Sopenharmony_ci ice_down(vsi); 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci ice_vsi_free_irq(vsi); 282262306a36Sopenharmony_ci ice_vsi_free_tx_rings(vsi); 282362306a36Sopenharmony_ci ice_vsi_free_rx_rings(vsi); 282462306a36Sopenharmony_ci} 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci/** 282762306a36Sopenharmony_ci * ice_ena_vsi - resume a VSI 282862306a36Sopenharmony_ci * @vsi: the VSI being resume 282962306a36Sopenharmony_ci * @locked: is the rtnl_lock already held 283062306a36Sopenharmony_ci */ 283162306a36Sopenharmony_ciint ice_ena_vsi(struct ice_vsi *vsi, bool locked) 283262306a36Sopenharmony_ci{ 283362306a36Sopenharmony_ci int err = 0; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci if (!test_bit(ICE_VSI_NEEDS_RESTART, vsi->state)) 283662306a36Sopenharmony_ci return 0; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci clear_bit(ICE_VSI_NEEDS_RESTART, vsi->state); 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci if (vsi->netdev && vsi->type == ICE_VSI_PF) { 284162306a36Sopenharmony_ci if (netif_running(vsi->netdev)) { 284262306a36Sopenharmony_ci if (!locked) 284362306a36Sopenharmony_ci rtnl_lock(); 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci err = ice_open_internal(vsi->netdev); 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (!locked) 284862306a36Sopenharmony_ci rtnl_unlock(); 284962306a36Sopenharmony_ci } 285062306a36Sopenharmony_ci } else if (vsi->type == ICE_VSI_CTRL) { 285162306a36Sopenharmony_ci err = ice_vsi_open_ctrl(vsi); 285262306a36Sopenharmony_ci } 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci return err; 285562306a36Sopenharmony_ci} 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci/** 285862306a36Sopenharmony_ci * ice_dis_vsi - pause a VSI 285962306a36Sopenharmony_ci * @vsi: the VSI being paused 286062306a36Sopenharmony_ci * @locked: is the rtnl_lock already held 286162306a36Sopenharmony_ci */ 286262306a36Sopenharmony_civoid ice_dis_vsi(struct ice_vsi *vsi, bool locked) 286362306a36Sopenharmony_ci{ 286462306a36Sopenharmony_ci if (test_bit(ICE_VSI_DOWN, vsi->state)) 286562306a36Sopenharmony_ci return; 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci set_bit(ICE_VSI_NEEDS_RESTART, vsi->state); 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF && vsi->netdev) { 287062306a36Sopenharmony_ci if (netif_running(vsi->netdev)) { 287162306a36Sopenharmony_ci if (!locked) 287262306a36Sopenharmony_ci rtnl_lock(); 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci ice_vsi_close(vsi); 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci if (!locked) 287762306a36Sopenharmony_ci rtnl_unlock(); 287862306a36Sopenharmony_ci } else { 287962306a36Sopenharmony_ci ice_vsi_close(vsi); 288062306a36Sopenharmony_ci } 288162306a36Sopenharmony_ci } else if (vsi->type == ICE_VSI_CTRL || 288262306a36Sopenharmony_ci vsi->type == ICE_VSI_SWITCHDEV_CTRL) { 288362306a36Sopenharmony_ci ice_vsi_close(vsi); 288462306a36Sopenharmony_ci } 288562306a36Sopenharmony_ci} 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci/** 288862306a36Sopenharmony_ci * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI 288962306a36Sopenharmony_ci * @vsi: the VSI being un-configured 289062306a36Sopenharmony_ci */ 289162306a36Sopenharmony_civoid ice_vsi_dis_irq(struct ice_vsi *vsi) 289262306a36Sopenharmony_ci{ 289362306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 289462306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 289562306a36Sopenharmony_ci u32 val; 289662306a36Sopenharmony_ci int i; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci /* disable interrupt causation from each queue */ 289962306a36Sopenharmony_ci if (vsi->tx_rings) { 290062306a36Sopenharmony_ci ice_for_each_txq(vsi, i) { 290162306a36Sopenharmony_ci if (vsi->tx_rings[i]) { 290262306a36Sopenharmony_ci u16 reg; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci reg = vsi->tx_rings[i]->reg_idx; 290562306a36Sopenharmony_ci val = rd32(hw, QINT_TQCTL(reg)); 290662306a36Sopenharmony_ci val &= ~QINT_TQCTL_CAUSE_ENA_M; 290762306a36Sopenharmony_ci wr32(hw, QINT_TQCTL(reg), val); 290862306a36Sopenharmony_ci } 290962306a36Sopenharmony_ci } 291062306a36Sopenharmony_ci } 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci if (vsi->rx_rings) { 291362306a36Sopenharmony_ci ice_for_each_rxq(vsi, i) { 291462306a36Sopenharmony_ci if (vsi->rx_rings[i]) { 291562306a36Sopenharmony_ci u16 reg; 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci reg = vsi->rx_rings[i]->reg_idx; 291862306a36Sopenharmony_ci val = rd32(hw, QINT_RQCTL(reg)); 291962306a36Sopenharmony_ci val &= ~QINT_RQCTL_CAUSE_ENA_M; 292062306a36Sopenharmony_ci wr32(hw, QINT_RQCTL(reg), val); 292162306a36Sopenharmony_ci } 292262306a36Sopenharmony_ci } 292362306a36Sopenharmony_ci } 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci /* disable each interrupt */ 292662306a36Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 292762306a36Sopenharmony_ci if (!vsi->q_vectors[i]) 292862306a36Sopenharmony_ci continue; 292962306a36Sopenharmony_ci wr32(hw, GLINT_DYN_CTL(vsi->q_vectors[i]->reg_idx), 0); 293062306a36Sopenharmony_ci } 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci ice_flush(hw); 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci /* don't call synchronize_irq() for VF's from the host */ 293562306a36Sopenharmony_ci if (vsi->type == ICE_VSI_VF) 293662306a36Sopenharmony_ci return; 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci ice_for_each_q_vector(vsi, i) 293962306a36Sopenharmony_ci synchronize_irq(vsi->q_vectors[i]->irq.virq); 294062306a36Sopenharmony_ci} 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci/** 294362306a36Sopenharmony_ci * ice_vsi_release - Delete a VSI and free its resources 294462306a36Sopenharmony_ci * @vsi: the VSI being removed 294562306a36Sopenharmony_ci * 294662306a36Sopenharmony_ci * Returns 0 on success or < 0 on error 294762306a36Sopenharmony_ci */ 294862306a36Sopenharmony_ciint ice_vsi_release(struct ice_vsi *vsi) 294962306a36Sopenharmony_ci{ 295062306a36Sopenharmony_ci struct ice_pf *pf; 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci if (!vsi->back) 295362306a36Sopenharmony_ci return -ENODEV; 295462306a36Sopenharmony_ci pf = vsi->back; 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) 295762306a36Sopenharmony_ci ice_rss_clean(vsi); 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci ice_vsi_close(vsi); 296062306a36Sopenharmony_ci ice_vsi_decfg(vsi); 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci /* retain SW VSI data structure since it is needed to unregister and 296362306a36Sopenharmony_ci * free VSI netdev when PF is not in reset recovery pending state,\ 296462306a36Sopenharmony_ci * for ex: during rmmod. 296562306a36Sopenharmony_ci */ 296662306a36Sopenharmony_ci if (!ice_is_reset_in_progress(pf->state)) 296762306a36Sopenharmony_ci ice_vsi_delete(vsi); 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci return 0; 297062306a36Sopenharmony_ci} 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci/** 297362306a36Sopenharmony_ci * ice_vsi_rebuild_get_coalesce - get coalesce from all q_vectors 297462306a36Sopenharmony_ci * @vsi: VSI connected with q_vectors 297562306a36Sopenharmony_ci * @coalesce: array of struct with stored coalesce 297662306a36Sopenharmony_ci * 297762306a36Sopenharmony_ci * Returns array size. 297862306a36Sopenharmony_ci */ 297962306a36Sopenharmony_cistatic int 298062306a36Sopenharmony_ciice_vsi_rebuild_get_coalesce(struct ice_vsi *vsi, 298162306a36Sopenharmony_ci struct ice_coalesce_stored *coalesce) 298262306a36Sopenharmony_ci{ 298362306a36Sopenharmony_ci int i; 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci ice_for_each_q_vector(vsi, i) { 298662306a36Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[i]; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci coalesce[i].itr_tx = q_vector->tx.itr_settings; 298962306a36Sopenharmony_ci coalesce[i].itr_rx = q_vector->rx.itr_settings; 299062306a36Sopenharmony_ci coalesce[i].intrl = q_vector->intrl; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci if (i < vsi->num_txq) 299362306a36Sopenharmony_ci coalesce[i].tx_valid = true; 299462306a36Sopenharmony_ci if (i < vsi->num_rxq) 299562306a36Sopenharmony_ci coalesce[i].rx_valid = true; 299662306a36Sopenharmony_ci } 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci return vsi->num_q_vectors; 299962306a36Sopenharmony_ci} 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci/** 300262306a36Sopenharmony_ci * ice_vsi_rebuild_set_coalesce - set coalesce from earlier saved arrays 300362306a36Sopenharmony_ci * @vsi: VSI connected with q_vectors 300462306a36Sopenharmony_ci * @coalesce: pointer to array of struct with stored coalesce 300562306a36Sopenharmony_ci * @size: size of coalesce array 300662306a36Sopenharmony_ci * 300762306a36Sopenharmony_ci * Before this function, ice_vsi_rebuild_get_coalesce should be called to save 300862306a36Sopenharmony_ci * ITR params in arrays. If size is 0 or coalesce wasn't stored set coalesce 300962306a36Sopenharmony_ci * to default value. 301062306a36Sopenharmony_ci */ 301162306a36Sopenharmony_cistatic void 301262306a36Sopenharmony_ciice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, 301362306a36Sopenharmony_ci struct ice_coalesce_stored *coalesce, int size) 301462306a36Sopenharmony_ci{ 301562306a36Sopenharmony_ci struct ice_ring_container *rc; 301662306a36Sopenharmony_ci int i; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci if ((size && !coalesce) || !vsi) 301962306a36Sopenharmony_ci return; 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci /* There are a couple of cases that have to be handled here: 302262306a36Sopenharmony_ci * 1. The case where the number of queue vectors stays the same, but 302362306a36Sopenharmony_ci * the number of Tx or Rx rings changes (the first for loop) 302462306a36Sopenharmony_ci * 2. The case where the number of queue vectors increased (the 302562306a36Sopenharmony_ci * second for loop) 302662306a36Sopenharmony_ci */ 302762306a36Sopenharmony_ci for (i = 0; i < size && i < vsi->num_q_vectors; i++) { 302862306a36Sopenharmony_ci /* There are 2 cases to handle here and they are the same for 302962306a36Sopenharmony_ci * both Tx and Rx: 303062306a36Sopenharmony_ci * if the entry was valid previously (coalesce[i].[tr]x_valid 303162306a36Sopenharmony_ci * and the loop variable is less than the number of rings 303262306a36Sopenharmony_ci * allocated, then write the previous values 303362306a36Sopenharmony_ci * 303462306a36Sopenharmony_ci * if the entry was not valid previously, but the number of 303562306a36Sopenharmony_ci * rings is less than are allocated (this means the number of 303662306a36Sopenharmony_ci * rings increased from previously), then write out the 303762306a36Sopenharmony_ci * values in the first element 303862306a36Sopenharmony_ci * 303962306a36Sopenharmony_ci * Also, always write the ITR, even if in ITR_IS_DYNAMIC 304062306a36Sopenharmony_ci * as there is no harm because the dynamic algorithm 304162306a36Sopenharmony_ci * will just overwrite. 304262306a36Sopenharmony_ci */ 304362306a36Sopenharmony_ci if (i < vsi->alloc_rxq && coalesce[i].rx_valid) { 304462306a36Sopenharmony_ci rc = &vsi->q_vectors[i]->rx; 304562306a36Sopenharmony_ci rc->itr_settings = coalesce[i].itr_rx; 304662306a36Sopenharmony_ci ice_write_itr(rc, rc->itr_setting); 304762306a36Sopenharmony_ci } else if (i < vsi->alloc_rxq) { 304862306a36Sopenharmony_ci rc = &vsi->q_vectors[i]->rx; 304962306a36Sopenharmony_ci rc->itr_settings = coalesce[0].itr_rx; 305062306a36Sopenharmony_ci ice_write_itr(rc, rc->itr_setting); 305162306a36Sopenharmony_ci } 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci if (i < vsi->alloc_txq && coalesce[i].tx_valid) { 305462306a36Sopenharmony_ci rc = &vsi->q_vectors[i]->tx; 305562306a36Sopenharmony_ci rc->itr_settings = coalesce[i].itr_tx; 305662306a36Sopenharmony_ci ice_write_itr(rc, rc->itr_setting); 305762306a36Sopenharmony_ci } else if (i < vsi->alloc_txq) { 305862306a36Sopenharmony_ci rc = &vsi->q_vectors[i]->tx; 305962306a36Sopenharmony_ci rc->itr_settings = coalesce[0].itr_tx; 306062306a36Sopenharmony_ci ice_write_itr(rc, rc->itr_setting); 306162306a36Sopenharmony_ci } 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci vsi->q_vectors[i]->intrl = coalesce[i].intrl; 306462306a36Sopenharmony_ci ice_set_q_vector_intrl(vsi->q_vectors[i]); 306562306a36Sopenharmony_ci } 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_ci /* the number of queue vectors increased so write whatever is in 306862306a36Sopenharmony_ci * the first element 306962306a36Sopenharmony_ci */ 307062306a36Sopenharmony_ci for (; i < vsi->num_q_vectors; i++) { 307162306a36Sopenharmony_ci /* transmit */ 307262306a36Sopenharmony_ci rc = &vsi->q_vectors[i]->tx; 307362306a36Sopenharmony_ci rc->itr_settings = coalesce[0].itr_tx; 307462306a36Sopenharmony_ci ice_write_itr(rc, rc->itr_setting); 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci /* receive */ 307762306a36Sopenharmony_ci rc = &vsi->q_vectors[i]->rx; 307862306a36Sopenharmony_ci rc->itr_settings = coalesce[0].itr_rx; 307962306a36Sopenharmony_ci ice_write_itr(rc, rc->itr_setting); 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci vsi->q_vectors[i]->intrl = coalesce[0].intrl; 308262306a36Sopenharmony_ci ice_set_q_vector_intrl(vsi->q_vectors[i]); 308362306a36Sopenharmony_ci } 308462306a36Sopenharmony_ci} 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci/** 308762306a36Sopenharmony_ci * ice_vsi_realloc_stat_arrays - Frees unused stat structures 308862306a36Sopenharmony_ci * @vsi: VSI pointer 308962306a36Sopenharmony_ci * @prev_txq: Number of Tx rings before ring reallocation 309062306a36Sopenharmony_ci * @prev_rxq: Number of Rx rings before ring reallocation 309162306a36Sopenharmony_ci */ 309262306a36Sopenharmony_cistatic void 309362306a36Sopenharmony_ciice_vsi_realloc_stat_arrays(struct ice_vsi *vsi, int prev_txq, int prev_rxq) 309462306a36Sopenharmony_ci{ 309562306a36Sopenharmony_ci struct ice_vsi_stats *vsi_stat; 309662306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 309762306a36Sopenharmony_ci int i; 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci if (!prev_txq || !prev_rxq) 310062306a36Sopenharmony_ci return; 310162306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) 310262306a36Sopenharmony_ci return; 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci vsi_stat = pf->vsi_stats[vsi->idx]; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci if (vsi->num_txq < prev_txq) { 310762306a36Sopenharmony_ci for (i = vsi->num_txq; i < prev_txq; i++) { 310862306a36Sopenharmony_ci if (vsi_stat->tx_ring_stats[i]) { 310962306a36Sopenharmony_ci kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); 311062306a36Sopenharmony_ci WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); 311162306a36Sopenharmony_ci } 311262306a36Sopenharmony_ci } 311362306a36Sopenharmony_ci } 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci if (vsi->num_rxq < prev_rxq) { 311662306a36Sopenharmony_ci for (i = vsi->num_rxq; i < prev_rxq; i++) { 311762306a36Sopenharmony_ci if (vsi_stat->rx_ring_stats[i]) { 311862306a36Sopenharmony_ci kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); 311962306a36Sopenharmony_ci WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); 312062306a36Sopenharmony_ci } 312162306a36Sopenharmony_ci } 312262306a36Sopenharmony_ci } 312362306a36Sopenharmony_ci} 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci/** 312662306a36Sopenharmony_ci * ice_vsi_rebuild - Rebuild VSI after reset 312762306a36Sopenharmony_ci * @vsi: VSI to be rebuild 312862306a36Sopenharmony_ci * @vsi_flags: flags used for VSI rebuild flow 312962306a36Sopenharmony_ci * 313062306a36Sopenharmony_ci * Set vsi_flags to ICE_VSI_FLAG_INIT to initialize a new VSI, or 313162306a36Sopenharmony_ci * ICE_VSI_FLAG_NO_INIT to rebuild an existing VSI in hardware. 313262306a36Sopenharmony_ci * 313362306a36Sopenharmony_ci * Returns 0 on success and negative value on failure 313462306a36Sopenharmony_ci */ 313562306a36Sopenharmony_ciint ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags) 313662306a36Sopenharmony_ci{ 313762306a36Sopenharmony_ci struct ice_vsi_cfg_params params = {}; 313862306a36Sopenharmony_ci struct ice_coalesce_stored *coalesce; 313962306a36Sopenharmony_ci int ret, prev_txq, prev_rxq; 314062306a36Sopenharmony_ci int prev_num_q_vectors = 0; 314162306a36Sopenharmony_ci struct ice_pf *pf; 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci if (!vsi) 314462306a36Sopenharmony_ci return -EINVAL; 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci params = ice_vsi_to_params(vsi); 314762306a36Sopenharmony_ci params.flags = vsi_flags; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci pf = vsi->back; 315062306a36Sopenharmony_ci if (WARN_ON(vsi->type == ICE_VSI_VF && !vsi->vf)) 315162306a36Sopenharmony_ci return -EINVAL; 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci coalesce = kcalloc(vsi->num_q_vectors, 315462306a36Sopenharmony_ci sizeof(struct ice_coalesce_stored), GFP_KERNEL); 315562306a36Sopenharmony_ci if (!coalesce) 315662306a36Sopenharmony_ci return -ENOMEM; 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi, coalesce); 315962306a36Sopenharmony_ci 316062306a36Sopenharmony_ci prev_txq = vsi->num_txq; 316162306a36Sopenharmony_ci prev_rxq = vsi->num_rxq; 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci ice_vsi_decfg(vsi); 316462306a36Sopenharmony_ci ret = ice_vsi_cfg_def(vsi, ¶ms); 316562306a36Sopenharmony_ci if (ret) 316662306a36Sopenharmony_ci goto err_vsi_cfg; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci ret = ice_vsi_cfg_tc_lan(pf, vsi); 316962306a36Sopenharmony_ci if (ret) { 317062306a36Sopenharmony_ci if (vsi_flags & ICE_VSI_FLAG_INIT) { 317162306a36Sopenharmony_ci ret = -EIO; 317262306a36Sopenharmony_ci goto err_vsi_cfg_tc_lan; 317362306a36Sopenharmony_ci } 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci kfree(coalesce); 317662306a36Sopenharmony_ci return ice_schedule_reset(pf, ICE_RESET_PFR); 317762306a36Sopenharmony_ci } 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci ice_vsi_realloc_stat_arrays(vsi, prev_txq, prev_rxq); 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_ci ice_vsi_rebuild_set_coalesce(vsi, coalesce, prev_num_q_vectors); 318262306a36Sopenharmony_ci kfree(coalesce); 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci return 0; 318562306a36Sopenharmony_ci 318662306a36Sopenharmony_cierr_vsi_cfg_tc_lan: 318762306a36Sopenharmony_ci ice_vsi_decfg(vsi); 318862306a36Sopenharmony_cierr_vsi_cfg: 318962306a36Sopenharmony_ci kfree(coalesce); 319062306a36Sopenharmony_ci return ret; 319162306a36Sopenharmony_ci} 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci/** 319462306a36Sopenharmony_ci * ice_is_reset_in_progress - check for a reset in progress 319562306a36Sopenharmony_ci * @state: PF state field 319662306a36Sopenharmony_ci */ 319762306a36Sopenharmony_cibool ice_is_reset_in_progress(unsigned long *state) 319862306a36Sopenharmony_ci{ 319962306a36Sopenharmony_ci return test_bit(ICE_RESET_OICR_RECV, state) || 320062306a36Sopenharmony_ci test_bit(ICE_PFR_REQ, state) || 320162306a36Sopenharmony_ci test_bit(ICE_CORER_REQ, state) || 320262306a36Sopenharmony_ci test_bit(ICE_GLOBR_REQ, state); 320362306a36Sopenharmony_ci} 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci/** 320662306a36Sopenharmony_ci * ice_wait_for_reset - Wait for driver to finish reset and rebuild 320762306a36Sopenharmony_ci * @pf: pointer to the PF structure 320862306a36Sopenharmony_ci * @timeout: length of time to wait, in jiffies 320962306a36Sopenharmony_ci * 321062306a36Sopenharmony_ci * Wait (sleep) for a short time until the driver finishes cleaning up from 321162306a36Sopenharmony_ci * a device reset. The caller must be able to sleep. Use this to delay 321262306a36Sopenharmony_ci * operations that could fail while the driver is cleaning up after a device 321362306a36Sopenharmony_ci * reset. 321462306a36Sopenharmony_ci * 321562306a36Sopenharmony_ci * Returns 0 on success, -EBUSY if the reset is not finished within the 321662306a36Sopenharmony_ci * timeout, and -ERESTARTSYS if the thread was interrupted. 321762306a36Sopenharmony_ci */ 321862306a36Sopenharmony_ciint ice_wait_for_reset(struct ice_pf *pf, unsigned long timeout) 321962306a36Sopenharmony_ci{ 322062306a36Sopenharmony_ci long ret; 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci ret = wait_event_interruptible_timeout(pf->reset_wait_queue, 322362306a36Sopenharmony_ci !ice_is_reset_in_progress(pf->state), 322462306a36Sopenharmony_ci timeout); 322562306a36Sopenharmony_ci if (ret < 0) 322662306a36Sopenharmony_ci return ret; 322762306a36Sopenharmony_ci else if (!ret) 322862306a36Sopenharmony_ci return -EBUSY; 322962306a36Sopenharmony_ci else 323062306a36Sopenharmony_ci return 0; 323162306a36Sopenharmony_ci} 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci/** 323462306a36Sopenharmony_ci * ice_vsi_update_q_map - update our copy of the VSI info with new queue map 323562306a36Sopenharmony_ci * @vsi: VSI being configured 323662306a36Sopenharmony_ci * @ctx: the context buffer returned from AQ VSI update command 323762306a36Sopenharmony_ci */ 323862306a36Sopenharmony_cistatic void ice_vsi_update_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctx) 323962306a36Sopenharmony_ci{ 324062306a36Sopenharmony_ci vsi->info.mapping_flags = ctx->info.mapping_flags; 324162306a36Sopenharmony_ci memcpy(&vsi->info.q_mapping, &ctx->info.q_mapping, 324262306a36Sopenharmony_ci sizeof(vsi->info.q_mapping)); 324362306a36Sopenharmony_ci memcpy(&vsi->info.tc_mapping, ctx->info.tc_mapping, 324462306a36Sopenharmony_ci sizeof(vsi->info.tc_mapping)); 324562306a36Sopenharmony_ci} 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci/** 324862306a36Sopenharmony_ci * ice_vsi_cfg_netdev_tc - Setup the netdev TC configuration 324962306a36Sopenharmony_ci * @vsi: the VSI being configured 325062306a36Sopenharmony_ci * @ena_tc: TC map to be enabled 325162306a36Sopenharmony_ci */ 325262306a36Sopenharmony_civoid ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc) 325362306a36Sopenharmony_ci{ 325462306a36Sopenharmony_ci struct net_device *netdev = vsi->netdev; 325562306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 325662306a36Sopenharmony_ci int numtc = vsi->tc_cfg.numtc; 325762306a36Sopenharmony_ci struct ice_dcbx_cfg *dcbcfg; 325862306a36Sopenharmony_ci u8 netdev_tc; 325962306a36Sopenharmony_ci int i; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci if (!netdev) 326262306a36Sopenharmony_ci return; 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci /* CHNL VSI doesn't have it's own netdev, hence, no netdev_tc */ 326562306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL) 326662306a36Sopenharmony_ci return; 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci if (!ena_tc) { 326962306a36Sopenharmony_ci netdev_reset_tc(netdev); 327062306a36Sopenharmony_ci return; 327162306a36Sopenharmony_ci } 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF && ice_is_adq_active(pf)) 327462306a36Sopenharmony_ci numtc = vsi->all_numtc; 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci if (netdev_set_num_tc(netdev, numtc)) 327762306a36Sopenharmony_ci return; 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci dcbcfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci ice_for_each_traffic_class(i) 328262306a36Sopenharmony_ci if (vsi->tc_cfg.ena_tc & BIT(i)) 328362306a36Sopenharmony_ci netdev_set_tc_queue(netdev, 328462306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].netdev_tc, 328562306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_tx, 328662306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qoffset); 328762306a36Sopenharmony_ci /* setup TC queue map for CHNL TCs */ 328862306a36Sopenharmony_ci ice_for_each_chnl_tc(i) { 328962306a36Sopenharmony_ci if (!(vsi->all_enatc & BIT(i))) 329062306a36Sopenharmony_ci break; 329162306a36Sopenharmony_ci if (!vsi->mqprio_qopt.qopt.count[i]) 329262306a36Sopenharmony_ci break; 329362306a36Sopenharmony_ci netdev_set_tc_queue(netdev, i, 329462306a36Sopenharmony_ci vsi->mqprio_qopt.qopt.count[i], 329562306a36Sopenharmony_ci vsi->mqprio_qopt.qopt.offset[i]); 329662306a36Sopenharmony_ci } 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci if (test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) 329962306a36Sopenharmony_ci return; 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { 330262306a36Sopenharmony_ci u8 ets_tc = dcbcfg->etscfg.prio_table[i]; 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci /* Get the mapped netdev TC# for the UP */ 330562306a36Sopenharmony_ci netdev_tc = vsi->tc_cfg.tc_info[ets_tc].netdev_tc; 330662306a36Sopenharmony_ci netdev_set_prio_tc_map(netdev, i, netdev_tc); 330762306a36Sopenharmony_ci } 330862306a36Sopenharmony_ci} 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci/** 331162306a36Sopenharmony_ci * ice_vsi_setup_q_map_mqprio - Prepares mqprio based tc_config 331262306a36Sopenharmony_ci * @vsi: the VSI being configured, 331362306a36Sopenharmony_ci * @ctxt: VSI context structure 331462306a36Sopenharmony_ci * @ena_tc: number of traffic classes to enable 331562306a36Sopenharmony_ci * 331662306a36Sopenharmony_ci * Prepares VSI tc_config to have queue configurations based on MQPRIO options. 331762306a36Sopenharmony_ci */ 331862306a36Sopenharmony_cistatic int 331962306a36Sopenharmony_ciice_vsi_setup_q_map_mqprio(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt, 332062306a36Sopenharmony_ci u8 ena_tc) 332162306a36Sopenharmony_ci{ 332262306a36Sopenharmony_ci u16 pow, offset = 0, qcount_tx = 0, qcount_rx = 0, qmap; 332362306a36Sopenharmony_ci u16 tc0_offset = vsi->mqprio_qopt.qopt.offset[0]; 332462306a36Sopenharmony_ci int tc0_qcount = vsi->mqprio_qopt.qopt.count[0]; 332562306a36Sopenharmony_ci u16 new_txq, new_rxq; 332662306a36Sopenharmony_ci u8 netdev_tc = 0; 332762306a36Sopenharmony_ci int i; 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci vsi->tc_cfg.ena_tc = ena_tc ? ena_tc : 1; 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci pow = order_base_2(tc0_qcount); 333262306a36Sopenharmony_ci qmap = ((tc0_offset << ICE_AQ_VSI_TC_Q_OFFSET_S) & 333362306a36Sopenharmony_ci ICE_AQ_VSI_TC_Q_OFFSET_M) | 333462306a36Sopenharmony_ci ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & ICE_AQ_VSI_TC_Q_NUM_M); 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci ice_for_each_traffic_class(i) { 333762306a36Sopenharmony_ci if (!(vsi->tc_cfg.ena_tc & BIT(i))) { 333862306a36Sopenharmony_ci /* TC is not enabled */ 333962306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qoffset = 0; 334062306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_rx = 1; 334162306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_tx = 1; 334262306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].netdev_tc = 0; 334362306a36Sopenharmony_ci ctxt->info.tc_mapping[i] = 0; 334462306a36Sopenharmony_ci continue; 334562306a36Sopenharmony_ci } 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci offset = vsi->mqprio_qopt.qopt.offset[i]; 334862306a36Sopenharmony_ci qcount_rx = vsi->mqprio_qopt.qopt.count[i]; 334962306a36Sopenharmony_ci qcount_tx = vsi->mqprio_qopt.qopt.count[i]; 335062306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qoffset = offset; 335162306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_rx = qcount_rx; 335262306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].qcount_tx = qcount_tx; 335362306a36Sopenharmony_ci vsi->tc_cfg.tc_info[i].netdev_tc = netdev_tc++; 335462306a36Sopenharmony_ci } 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci if (vsi->all_numtc && vsi->all_numtc != vsi->tc_cfg.numtc) { 335762306a36Sopenharmony_ci ice_for_each_chnl_tc(i) { 335862306a36Sopenharmony_ci if (!(vsi->all_enatc & BIT(i))) 335962306a36Sopenharmony_ci continue; 336062306a36Sopenharmony_ci offset = vsi->mqprio_qopt.qopt.offset[i]; 336162306a36Sopenharmony_ci qcount_rx = vsi->mqprio_qopt.qopt.count[i]; 336262306a36Sopenharmony_ci qcount_tx = vsi->mqprio_qopt.qopt.count[i]; 336362306a36Sopenharmony_ci } 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci new_txq = offset + qcount_tx; 336762306a36Sopenharmony_ci if (new_txq > vsi->alloc_txq) { 336862306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Trying to use more Tx queues (%u), than were allocated (%u)!\n", 336962306a36Sopenharmony_ci new_txq, vsi->alloc_txq); 337062306a36Sopenharmony_ci return -EINVAL; 337162306a36Sopenharmony_ci } 337262306a36Sopenharmony_ci 337362306a36Sopenharmony_ci new_rxq = offset + qcount_rx; 337462306a36Sopenharmony_ci if (new_rxq > vsi->alloc_rxq) { 337562306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Trying to use more Rx queues (%u), than were allocated (%u)!\n", 337662306a36Sopenharmony_ci new_rxq, vsi->alloc_rxq); 337762306a36Sopenharmony_ci return -EINVAL; 337862306a36Sopenharmony_ci } 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci /* Set actual Tx/Rx queue pairs */ 338162306a36Sopenharmony_ci vsi->num_txq = new_txq; 338262306a36Sopenharmony_ci vsi->num_rxq = new_rxq; 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci /* Setup queue TC[0].qmap for given VSI context */ 338562306a36Sopenharmony_ci ctxt->info.tc_mapping[0] = cpu_to_le16(qmap); 338662306a36Sopenharmony_ci ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]); 338762306a36Sopenharmony_ci ctxt->info.q_mapping[1] = cpu_to_le16(tc0_qcount); 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci /* Find queue count available for channel VSIs and starting offset 339062306a36Sopenharmony_ci * for channel VSIs 339162306a36Sopenharmony_ci */ 339262306a36Sopenharmony_ci if (tc0_qcount && tc0_qcount < vsi->num_rxq) { 339362306a36Sopenharmony_ci vsi->cnt_q_avail = vsi->num_rxq - tc0_qcount; 339462306a36Sopenharmony_ci vsi->next_base_q = tc0_qcount; 339562306a36Sopenharmony_ci } 339662306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(vsi->back), "vsi->num_txq = %d\n", vsi->num_txq); 339762306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(vsi->back), "vsi->num_rxq = %d\n", vsi->num_rxq); 339862306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(vsi->back), "all_numtc %u, all_enatc: 0x%04x, tc_cfg.numtc %u\n", 339962306a36Sopenharmony_ci vsi->all_numtc, vsi->all_enatc, vsi->tc_cfg.numtc); 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci return 0; 340262306a36Sopenharmony_ci} 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci/** 340562306a36Sopenharmony_ci * ice_vsi_cfg_tc - Configure VSI Tx Sched for given TC map 340662306a36Sopenharmony_ci * @vsi: VSI to be configured 340762306a36Sopenharmony_ci * @ena_tc: TC bitmap 340862306a36Sopenharmony_ci * 340962306a36Sopenharmony_ci * VSI queues expected to be quiesced before calling this function 341062306a36Sopenharmony_ci */ 341162306a36Sopenharmony_ciint ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc) 341262306a36Sopenharmony_ci{ 341362306a36Sopenharmony_ci u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 341462306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 341562306a36Sopenharmony_ci struct ice_tc_cfg old_tc_cfg; 341662306a36Sopenharmony_ci struct ice_vsi_ctx *ctx; 341762306a36Sopenharmony_ci struct device *dev; 341862306a36Sopenharmony_ci int i, ret = 0; 341962306a36Sopenharmony_ci u8 num_tc = 0; 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 342262306a36Sopenharmony_ci if (vsi->tc_cfg.ena_tc == ena_tc && 342362306a36Sopenharmony_ci vsi->mqprio_qopt.mode != TC_MQPRIO_MODE_CHANNEL) 342462306a36Sopenharmony_ci return 0; 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_ci ice_for_each_traffic_class(i) { 342762306a36Sopenharmony_ci /* build bitmap of enabled TCs */ 342862306a36Sopenharmony_ci if (ena_tc & BIT(i)) 342962306a36Sopenharmony_ci num_tc++; 343062306a36Sopenharmony_ci /* populate max_txqs per TC */ 343162306a36Sopenharmony_ci max_txqs[i] = vsi->alloc_txq; 343262306a36Sopenharmony_ci /* Update max_txqs if it is CHNL VSI, because alloc_t[r]xq are 343362306a36Sopenharmony_ci * zero for CHNL VSI, hence use num_txq instead as max_txqs 343462306a36Sopenharmony_ci */ 343562306a36Sopenharmony_ci if (vsi->type == ICE_VSI_CHNL && 343662306a36Sopenharmony_ci test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) 343762306a36Sopenharmony_ci max_txqs[i] = vsi->num_txq; 343862306a36Sopenharmony_ci } 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci memcpy(&old_tc_cfg, &vsi->tc_cfg, sizeof(old_tc_cfg)); 344162306a36Sopenharmony_ci vsi->tc_cfg.ena_tc = ena_tc; 344262306a36Sopenharmony_ci vsi->tc_cfg.numtc = num_tc; 344362306a36Sopenharmony_ci 344462306a36Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 344562306a36Sopenharmony_ci if (!ctx) 344662306a36Sopenharmony_ci return -ENOMEM; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci ctx->vf_num = 0; 344962306a36Sopenharmony_ci ctx->info = vsi->info; 345062306a36Sopenharmony_ci 345162306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF && 345262306a36Sopenharmony_ci test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) 345362306a36Sopenharmony_ci ret = ice_vsi_setup_q_map_mqprio(vsi, ctx, ena_tc); 345462306a36Sopenharmony_ci else 345562306a36Sopenharmony_ci ret = ice_vsi_setup_q_map(vsi, ctx); 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci if (ret) { 345862306a36Sopenharmony_ci memcpy(&vsi->tc_cfg, &old_tc_cfg, sizeof(vsi->tc_cfg)); 345962306a36Sopenharmony_ci goto out; 346062306a36Sopenharmony_ci } 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci /* must to indicate which section of VSI context are being modified */ 346362306a36Sopenharmony_ci ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID); 346462306a36Sopenharmony_ci ret = ice_update_vsi(&pf->hw, vsi->idx, ctx, NULL); 346562306a36Sopenharmony_ci if (ret) { 346662306a36Sopenharmony_ci dev_info(dev, "Failed VSI Update\n"); 346762306a36Sopenharmony_ci goto out; 346862306a36Sopenharmony_ci } 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci if (vsi->type == ICE_VSI_PF && 347162306a36Sopenharmony_ci test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) 347262306a36Sopenharmony_ci ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, 1, max_txqs); 347362306a36Sopenharmony_ci else 347462306a36Sopenharmony_ci ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, 347562306a36Sopenharmony_ci vsi->tc_cfg.ena_tc, max_txqs); 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci if (ret) { 347862306a36Sopenharmony_ci dev_err(dev, "VSI %d failed TC config, error %d\n", 347962306a36Sopenharmony_ci vsi->vsi_num, ret); 348062306a36Sopenharmony_ci goto out; 348162306a36Sopenharmony_ci } 348262306a36Sopenharmony_ci ice_vsi_update_q_map(vsi, ctx); 348362306a36Sopenharmony_ci vsi->info.valid_sections = 0; 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci ice_vsi_cfg_netdev_tc(vsi, ena_tc); 348662306a36Sopenharmony_ciout: 348762306a36Sopenharmony_ci kfree(ctx); 348862306a36Sopenharmony_ci return ret; 348962306a36Sopenharmony_ci} 349062306a36Sopenharmony_ci 349162306a36Sopenharmony_ci/** 349262306a36Sopenharmony_ci * ice_update_ring_stats - Update ring statistics 349362306a36Sopenharmony_ci * @stats: stats to be updated 349462306a36Sopenharmony_ci * @pkts: number of processed packets 349562306a36Sopenharmony_ci * @bytes: number of processed bytes 349662306a36Sopenharmony_ci * 349762306a36Sopenharmony_ci * This function assumes that caller has acquired a u64_stats_sync lock. 349862306a36Sopenharmony_ci */ 349962306a36Sopenharmony_cistatic void ice_update_ring_stats(struct ice_q_stats *stats, u64 pkts, u64 bytes) 350062306a36Sopenharmony_ci{ 350162306a36Sopenharmony_ci stats->bytes += bytes; 350262306a36Sopenharmony_ci stats->pkts += pkts; 350362306a36Sopenharmony_ci} 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci/** 350662306a36Sopenharmony_ci * ice_update_tx_ring_stats - Update Tx ring specific counters 350762306a36Sopenharmony_ci * @tx_ring: ring to update 350862306a36Sopenharmony_ci * @pkts: number of processed packets 350962306a36Sopenharmony_ci * @bytes: number of processed bytes 351062306a36Sopenharmony_ci */ 351162306a36Sopenharmony_civoid ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes) 351262306a36Sopenharmony_ci{ 351362306a36Sopenharmony_ci u64_stats_update_begin(&tx_ring->ring_stats->syncp); 351462306a36Sopenharmony_ci ice_update_ring_stats(&tx_ring->ring_stats->stats, pkts, bytes); 351562306a36Sopenharmony_ci u64_stats_update_end(&tx_ring->ring_stats->syncp); 351662306a36Sopenharmony_ci} 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci/** 351962306a36Sopenharmony_ci * ice_update_rx_ring_stats - Update Rx ring specific counters 352062306a36Sopenharmony_ci * @rx_ring: ring to update 352162306a36Sopenharmony_ci * @pkts: number of processed packets 352262306a36Sopenharmony_ci * @bytes: number of processed bytes 352362306a36Sopenharmony_ci */ 352462306a36Sopenharmony_civoid ice_update_rx_ring_stats(struct ice_rx_ring *rx_ring, u64 pkts, u64 bytes) 352562306a36Sopenharmony_ci{ 352662306a36Sopenharmony_ci u64_stats_update_begin(&rx_ring->ring_stats->syncp); 352762306a36Sopenharmony_ci ice_update_ring_stats(&rx_ring->ring_stats->stats, pkts, bytes); 352862306a36Sopenharmony_ci u64_stats_update_end(&rx_ring->ring_stats->syncp); 352962306a36Sopenharmony_ci} 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci/** 353262306a36Sopenharmony_ci * ice_is_dflt_vsi_in_use - check if the default forwarding VSI is being used 353362306a36Sopenharmony_ci * @pi: port info of the switch with default VSI 353462306a36Sopenharmony_ci * 353562306a36Sopenharmony_ci * Return true if the there is a single VSI in default forwarding VSI list 353662306a36Sopenharmony_ci */ 353762306a36Sopenharmony_cibool ice_is_dflt_vsi_in_use(struct ice_port_info *pi) 353862306a36Sopenharmony_ci{ 353962306a36Sopenharmony_ci bool exists = false; 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci ice_check_if_dflt_vsi(pi, 0, &exists); 354262306a36Sopenharmony_ci return exists; 354362306a36Sopenharmony_ci} 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ci/** 354662306a36Sopenharmony_ci * ice_is_vsi_dflt_vsi - check if the VSI passed in is the default VSI 354762306a36Sopenharmony_ci * @vsi: VSI to compare against default forwarding VSI 354862306a36Sopenharmony_ci * 354962306a36Sopenharmony_ci * If this VSI passed in is the default forwarding VSI then return true, else 355062306a36Sopenharmony_ci * return false 355162306a36Sopenharmony_ci */ 355262306a36Sopenharmony_cibool ice_is_vsi_dflt_vsi(struct ice_vsi *vsi) 355362306a36Sopenharmony_ci{ 355462306a36Sopenharmony_ci return ice_check_if_dflt_vsi(vsi->port_info, vsi->idx, NULL); 355562306a36Sopenharmony_ci} 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci/** 355862306a36Sopenharmony_ci * ice_set_dflt_vsi - set the default forwarding VSI 355962306a36Sopenharmony_ci * @vsi: VSI getting set as the default forwarding VSI on the switch 356062306a36Sopenharmony_ci * 356162306a36Sopenharmony_ci * If the VSI passed in is already the default VSI and it's enabled just return 356262306a36Sopenharmony_ci * success. 356362306a36Sopenharmony_ci * 356462306a36Sopenharmony_ci * Otherwise try to set the VSI passed in as the switch's default VSI and 356562306a36Sopenharmony_ci * return the result. 356662306a36Sopenharmony_ci */ 356762306a36Sopenharmony_ciint ice_set_dflt_vsi(struct ice_vsi *vsi) 356862306a36Sopenharmony_ci{ 356962306a36Sopenharmony_ci struct device *dev; 357062306a36Sopenharmony_ci int status; 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci if (!vsi) 357362306a36Sopenharmony_ci return -EINVAL; 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci if (ice_lag_is_switchdev_running(vsi->back)) { 357862306a36Sopenharmony_ci dev_dbg(dev, "VSI %d passed is a part of LAG containing interfaces in switchdev mode, nothing to do\n", 357962306a36Sopenharmony_ci vsi->vsi_num); 358062306a36Sopenharmony_ci return 0; 358162306a36Sopenharmony_ci } 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci /* the VSI passed in is already the default VSI */ 358462306a36Sopenharmony_ci if (ice_is_vsi_dflt_vsi(vsi)) { 358562306a36Sopenharmony_ci dev_dbg(dev, "VSI %d passed in is already the default forwarding VSI, nothing to do\n", 358662306a36Sopenharmony_ci vsi->vsi_num); 358762306a36Sopenharmony_ci return 0; 358862306a36Sopenharmony_ci } 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_ci status = ice_cfg_dflt_vsi(vsi->port_info, vsi->idx, true, ICE_FLTR_RX); 359162306a36Sopenharmony_ci if (status) { 359262306a36Sopenharmony_ci dev_err(dev, "Failed to set VSI %d as the default forwarding VSI, error %d\n", 359362306a36Sopenharmony_ci vsi->vsi_num, status); 359462306a36Sopenharmony_ci return status; 359562306a36Sopenharmony_ci } 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci return 0; 359862306a36Sopenharmony_ci} 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci/** 360162306a36Sopenharmony_ci * ice_clear_dflt_vsi - clear the default forwarding VSI 360262306a36Sopenharmony_ci * @vsi: VSI to remove from filter list 360362306a36Sopenharmony_ci * 360462306a36Sopenharmony_ci * If the switch has no default VSI or it's not enabled then return error. 360562306a36Sopenharmony_ci * 360662306a36Sopenharmony_ci * Otherwise try to clear the default VSI and return the result. 360762306a36Sopenharmony_ci */ 360862306a36Sopenharmony_ciint ice_clear_dflt_vsi(struct ice_vsi *vsi) 360962306a36Sopenharmony_ci{ 361062306a36Sopenharmony_ci struct device *dev; 361162306a36Sopenharmony_ci int status; 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci if (!vsi) 361462306a36Sopenharmony_ci return -EINVAL; 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci /* there is no default VSI configured */ 361962306a36Sopenharmony_ci if (!ice_is_dflt_vsi_in_use(vsi->port_info)) 362062306a36Sopenharmony_ci return -ENODEV; 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci status = ice_cfg_dflt_vsi(vsi->port_info, vsi->idx, false, 362362306a36Sopenharmony_ci ICE_FLTR_RX); 362462306a36Sopenharmony_ci if (status) { 362562306a36Sopenharmony_ci dev_err(dev, "Failed to clear the default forwarding VSI %d, error %d\n", 362662306a36Sopenharmony_ci vsi->vsi_num, status); 362762306a36Sopenharmony_ci return -EIO; 362862306a36Sopenharmony_ci } 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci return 0; 363162306a36Sopenharmony_ci} 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci/** 363462306a36Sopenharmony_ci * ice_get_link_speed_mbps - get link speed in Mbps 363562306a36Sopenharmony_ci * @vsi: the VSI whose link speed is being queried 363662306a36Sopenharmony_ci * 363762306a36Sopenharmony_ci * Return current VSI link speed and 0 if the speed is unknown. 363862306a36Sopenharmony_ci */ 363962306a36Sopenharmony_ciint ice_get_link_speed_mbps(struct ice_vsi *vsi) 364062306a36Sopenharmony_ci{ 364162306a36Sopenharmony_ci unsigned int link_speed; 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci link_speed = vsi->port_info->phy.link_info.link_speed; 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci return (int)ice_get_link_speed(fls(link_speed) - 1); 364662306a36Sopenharmony_ci} 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci/** 364962306a36Sopenharmony_ci * ice_get_link_speed_kbps - get link speed in Kbps 365062306a36Sopenharmony_ci * @vsi: the VSI whose link speed is being queried 365162306a36Sopenharmony_ci * 365262306a36Sopenharmony_ci * Return current VSI link speed and 0 if the speed is unknown. 365362306a36Sopenharmony_ci */ 365462306a36Sopenharmony_ciint ice_get_link_speed_kbps(struct ice_vsi *vsi) 365562306a36Sopenharmony_ci{ 365662306a36Sopenharmony_ci int speed_mbps; 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci speed_mbps = ice_get_link_speed_mbps(vsi); 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci return speed_mbps * 1000; 366162306a36Sopenharmony_ci} 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci/** 366462306a36Sopenharmony_ci * ice_set_min_bw_limit - setup minimum BW limit for Tx based on min_tx_rate 366562306a36Sopenharmony_ci * @vsi: VSI to be configured 366662306a36Sopenharmony_ci * @min_tx_rate: min Tx rate in Kbps to be configured as BW limit 366762306a36Sopenharmony_ci * 366862306a36Sopenharmony_ci * If the min_tx_rate is specified as 0 that means to clear the minimum BW limit 366962306a36Sopenharmony_ci * profile, otherwise a non-zero value will force a minimum BW limit for the VSI 367062306a36Sopenharmony_ci * on TC 0. 367162306a36Sopenharmony_ci */ 367262306a36Sopenharmony_ciint ice_set_min_bw_limit(struct ice_vsi *vsi, u64 min_tx_rate) 367362306a36Sopenharmony_ci{ 367462306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 367562306a36Sopenharmony_ci struct device *dev; 367662306a36Sopenharmony_ci int status; 367762306a36Sopenharmony_ci int speed; 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 368062306a36Sopenharmony_ci if (!vsi->port_info) { 368162306a36Sopenharmony_ci dev_dbg(dev, "VSI %d, type %u specified doesn't have valid port_info\n", 368262306a36Sopenharmony_ci vsi->idx, vsi->type); 368362306a36Sopenharmony_ci return -EINVAL; 368462306a36Sopenharmony_ci } 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci speed = ice_get_link_speed_kbps(vsi); 368762306a36Sopenharmony_ci if (min_tx_rate > (u64)speed) { 368862306a36Sopenharmony_ci dev_err(dev, "invalid min Tx rate %llu Kbps specified for %s %d is greater than current link speed %u Kbps\n", 368962306a36Sopenharmony_ci min_tx_rate, ice_vsi_type_str(vsi->type), vsi->idx, 369062306a36Sopenharmony_ci speed); 369162306a36Sopenharmony_ci return -EINVAL; 369262306a36Sopenharmony_ci } 369362306a36Sopenharmony_ci 369462306a36Sopenharmony_ci /* Configure min BW for VSI limit */ 369562306a36Sopenharmony_ci if (min_tx_rate) { 369662306a36Sopenharmony_ci status = ice_cfg_vsi_bw_lmt_per_tc(vsi->port_info, vsi->idx, 0, 369762306a36Sopenharmony_ci ICE_MIN_BW, min_tx_rate); 369862306a36Sopenharmony_ci if (status) { 369962306a36Sopenharmony_ci dev_err(dev, "failed to set min Tx rate(%llu Kbps) for %s %d\n", 370062306a36Sopenharmony_ci min_tx_rate, ice_vsi_type_str(vsi->type), 370162306a36Sopenharmony_ci vsi->idx); 370262306a36Sopenharmony_ci return status; 370362306a36Sopenharmony_ci } 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci dev_dbg(dev, "set min Tx rate(%llu Kbps) for %s\n", 370662306a36Sopenharmony_ci min_tx_rate, ice_vsi_type_str(vsi->type)); 370762306a36Sopenharmony_ci } else { 370862306a36Sopenharmony_ci status = ice_cfg_vsi_bw_dflt_lmt_per_tc(vsi->port_info, 370962306a36Sopenharmony_ci vsi->idx, 0, 371062306a36Sopenharmony_ci ICE_MIN_BW); 371162306a36Sopenharmony_ci if (status) { 371262306a36Sopenharmony_ci dev_err(dev, "failed to clear min Tx rate configuration for %s %d\n", 371362306a36Sopenharmony_ci ice_vsi_type_str(vsi->type), vsi->idx); 371462306a36Sopenharmony_ci return status; 371562306a36Sopenharmony_ci } 371662306a36Sopenharmony_ci 371762306a36Sopenharmony_ci dev_dbg(dev, "cleared min Tx rate configuration for %s %d\n", 371862306a36Sopenharmony_ci ice_vsi_type_str(vsi->type), vsi->idx); 371962306a36Sopenharmony_ci } 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci return 0; 372262306a36Sopenharmony_ci} 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci/** 372562306a36Sopenharmony_ci * ice_set_max_bw_limit - setup maximum BW limit for Tx based on max_tx_rate 372662306a36Sopenharmony_ci * @vsi: VSI to be configured 372762306a36Sopenharmony_ci * @max_tx_rate: max Tx rate in Kbps to be configured as BW limit 372862306a36Sopenharmony_ci * 372962306a36Sopenharmony_ci * If the max_tx_rate is specified as 0 that means to clear the maximum BW limit 373062306a36Sopenharmony_ci * profile, otherwise a non-zero value will force a maximum BW limit for the VSI 373162306a36Sopenharmony_ci * on TC 0. 373262306a36Sopenharmony_ci */ 373362306a36Sopenharmony_ciint ice_set_max_bw_limit(struct ice_vsi *vsi, u64 max_tx_rate) 373462306a36Sopenharmony_ci{ 373562306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 373662306a36Sopenharmony_ci struct device *dev; 373762306a36Sopenharmony_ci int status; 373862306a36Sopenharmony_ci int speed; 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 374162306a36Sopenharmony_ci if (!vsi->port_info) { 374262306a36Sopenharmony_ci dev_dbg(dev, "VSI %d, type %u specified doesn't have valid port_info\n", 374362306a36Sopenharmony_ci vsi->idx, vsi->type); 374462306a36Sopenharmony_ci return -EINVAL; 374562306a36Sopenharmony_ci } 374662306a36Sopenharmony_ci 374762306a36Sopenharmony_ci speed = ice_get_link_speed_kbps(vsi); 374862306a36Sopenharmony_ci if (max_tx_rate > (u64)speed) { 374962306a36Sopenharmony_ci dev_err(dev, "invalid max Tx rate %llu Kbps specified for %s %d is greater than current link speed %u Kbps\n", 375062306a36Sopenharmony_ci max_tx_rate, ice_vsi_type_str(vsi->type), vsi->idx, 375162306a36Sopenharmony_ci speed); 375262306a36Sopenharmony_ci return -EINVAL; 375362306a36Sopenharmony_ci } 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ci /* Configure max BW for VSI limit */ 375662306a36Sopenharmony_ci if (max_tx_rate) { 375762306a36Sopenharmony_ci status = ice_cfg_vsi_bw_lmt_per_tc(vsi->port_info, vsi->idx, 0, 375862306a36Sopenharmony_ci ICE_MAX_BW, max_tx_rate); 375962306a36Sopenharmony_ci if (status) { 376062306a36Sopenharmony_ci dev_err(dev, "failed setting max Tx rate(%llu Kbps) for %s %d\n", 376162306a36Sopenharmony_ci max_tx_rate, ice_vsi_type_str(vsi->type), 376262306a36Sopenharmony_ci vsi->idx); 376362306a36Sopenharmony_ci return status; 376462306a36Sopenharmony_ci } 376562306a36Sopenharmony_ci 376662306a36Sopenharmony_ci dev_dbg(dev, "set max Tx rate(%llu Kbps) for %s %d\n", 376762306a36Sopenharmony_ci max_tx_rate, ice_vsi_type_str(vsi->type), vsi->idx); 376862306a36Sopenharmony_ci } else { 376962306a36Sopenharmony_ci status = ice_cfg_vsi_bw_dflt_lmt_per_tc(vsi->port_info, 377062306a36Sopenharmony_ci vsi->idx, 0, 377162306a36Sopenharmony_ci ICE_MAX_BW); 377262306a36Sopenharmony_ci if (status) { 377362306a36Sopenharmony_ci dev_err(dev, "failed clearing max Tx rate configuration for %s %d\n", 377462306a36Sopenharmony_ci ice_vsi_type_str(vsi->type), vsi->idx); 377562306a36Sopenharmony_ci return status; 377662306a36Sopenharmony_ci } 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci dev_dbg(dev, "cleared max Tx rate configuration for %s %d\n", 377962306a36Sopenharmony_ci ice_vsi_type_str(vsi->type), vsi->idx); 378062306a36Sopenharmony_ci } 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci return 0; 378362306a36Sopenharmony_ci} 378462306a36Sopenharmony_ci 378562306a36Sopenharmony_ci/** 378662306a36Sopenharmony_ci * ice_set_link - turn on/off physical link 378762306a36Sopenharmony_ci * @vsi: VSI to modify physical link on 378862306a36Sopenharmony_ci * @ena: turn on/off physical link 378962306a36Sopenharmony_ci */ 379062306a36Sopenharmony_ciint ice_set_link(struct ice_vsi *vsi, bool ena) 379162306a36Sopenharmony_ci{ 379262306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(vsi->back); 379362306a36Sopenharmony_ci struct ice_port_info *pi = vsi->port_info; 379462306a36Sopenharmony_ci struct ice_hw *hw = pi->hw; 379562306a36Sopenharmony_ci int status; 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci if (vsi->type != ICE_VSI_PF) 379862306a36Sopenharmony_ci return -EINVAL; 379962306a36Sopenharmony_ci 380062306a36Sopenharmony_ci status = ice_aq_set_link_restart_an(pi, ena, NULL); 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci /* if link is owned by manageability, FW will return ICE_AQ_RC_EMODE. 380362306a36Sopenharmony_ci * this is not a fatal error, so print a warning message and return 380462306a36Sopenharmony_ci * a success code. Return an error if FW returns an error code other 380562306a36Sopenharmony_ci * than ICE_AQ_RC_EMODE 380662306a36Sopenharmony_ci */ 380762306a36Sopenharmony_ci if (status == -EIO) { 380862306a36Sopenharmony_ci if (hw->adminq.sq_last_status == ICE_AQ_RC_EMODE) 380962306a36Sopenharmony_ci dev_dbg(dev, "can't set link to %s, err %d aq_err %s. not fatal, continuing\n", 381062306a36Sopenharmony_ci (ena ? "ON" : "OFF"), status, 381162306a36Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 381262306a36Sopenharmony_ci } else if (status) { 381362306a36Sopenharmony_ci dev_err(dev, "can't set link to %s, err %d aq_err %s\n", 381462306a36Sopenharmony_ci (ena ? "ON" : "OFF"), status, 381562306a36Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 381662306a36Sopenharmony_ci return status; 381762306a36Sopenharmony_ci } 381862306a36Sopenharmony_ci 381962306a36Sopenharmony_ci return 0; 382062306a36Sopenharmony_ci} 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci/** 382362306a36Sopenharmony_ci * ice_vsi_add_vlan_zero - add VLAN 0 filter(s) for this VSI 382462306a36Sopenharmony_ci * @vsi: VSI used to add VLAN filters 382562306a36Sopenharmony_ci * 382662306a36Sopenharmony_ci * In Single VLAN Mode (SVM), single VLAN filters via ICE_SW_LKUP_VLAN are based 382762306a36Sopenharmony_ci * on the inner VLAN ID, so the VLAN TPID (i.e. 0x8100 or 0x888a8) doesn't 382862306a36Sopenharmony_ci * matter. In Double VLAN Mode (DVM), outer/single VLAN filters via 382962306a36Sopenharmony_ci * ICE_SW_LKUP_VLAN are based on the outer/single VLAN ID + VLAN TPID. 383062306a36Sopenharmony_ci * 383162306a36Sopenharmony_ci * For both modes add a VLAN 0 + no VLAN TPID filter to handle untagged traffic 383262306a36Sopenharmony_ci * when VLAN pruning is enabled. Also, this handles VLAN 0 priority tagged 383362306a36Sopenharmony_ci * traffic in SVM, since the VLAN TPID isn't part of filtering. 383462306a36Sopenharmony_ci * 383562306a36Sopenharmony_ci * If DVM is enabled then an explicit VLAN 0 + VLAN TPID filter needs to be 383662306a36Sopenharmony_ci * added to allow VLAN 0 priority tagged traffic in DVM, since the VLAN TPID is 383762306a36Sopenharmony_ci * part of filtering. 383862306a36Sopenharmony_ci */ 383962306a36Sopenharmony_ciint ice_vsi_add_vlan_zero(struct ice_vsi *vsi) 384062306a36Sopenharmony_ci{ 384162306a36Sopenharmony_ci struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi); 384262306a36Sopenharmony_ci struct ice_vlan vlan; 384362306a36Sopenharmony_ci int err; 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci vlan = ICE_VLAN(0, 0, 0); 384662306a36Sopenharmony_ci err = vlan_ops->add_vlan(vsi, &vlan); 384762306a36Sopenharmony_ci if (err && err != -EEXIST) 384862306a36Sopenharmony_ci return err; 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci /* in SVM both VLAN 0 filters are identical */ 385162306a36Sopenharmony_ci if (!ice_is_dvm_ena(&vsi->back->hw)) 385262306a36Sopenharmony_ci return 0; 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_ci vlan = ICE_VLAN(ETH_P_8021Q, 0, 0); 385562306a36Sopenharmony_ci err = vlan_ops->add_vlan(vsi, &vlan); 385662306a36Sopenharmony_ci if (err && err != -EEXIST) 385762306a36Sopenharmony_ci return err; 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_ci return 0; 386062306a36Sopenharmony_ci} 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci/** 386362306a36Sopenharmony_ci * ice_vsi_del_vlan_zero - delete VLAN 0 filter(s) for this VSI 386462306a36Sopenharmony_ci * @vsi: VSI used to add VLAN filters 386562306a36Sopenharmony_ci * 386662306a36Sopenharmony_ci * Delete the VLAN 0 filters in the same manner that they were added in 386762306a36Sopenharmony_ci * ice_vsi_add_vlan_zero. 386862306a36Sopenharmony_ci */ 386962306a36Sopenharmony_ciint ice_vsi_del_vlan_zero(struct ice_vsi *vsi) 387062306a36Sopenharmony_ci{ 387162306a36Sopenharmony_ci struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi); 387262306a36Sopenharmony_ci struct ice_vlan vlan; 387362306a36Sopenharmony_ci int err; 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci vlan = ICE_VLAN(0, 0, 0); 387662306a36Sopenharmony_ci err = vlan_ops->del_vlan(vsi, &vlan); 387762306a36Sopenharmony_ci if (err && err != -EEXIST) 387862306a36Sopenharmony_ci return err; 387962306a36Sopenharmony_ci 388062306a36Sopenharmony_ci /* in SVM both VLAN 0 filters are identical */ 388162306a36Sopenharmony_ci if (!ice_is_dvm_ena(&vsi->back->hw)) 388262306a36Sopenharmony_ci return 0; 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci vlan = ICE_VLAN(ETH_P_8021Q, 0, 0); 388562306a36Sopenharmony_ci err = vlan_ops->del_vlan(vsi, &vlan); 388662306a36Sopenharmony_ci if (err && err != -EEXIST) 388762306a36Sopenharmony_ci return err; 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci /* when deleting the last VLAN filter, make sure to disable the VLAN 389062306a36Sopenharmony_ci * promisc mode so the filter isn't left by accident 389162306a36Sopenharmony_ci */ 389262306a36Sopenharmony_ci return ice_clear_vsi_promisc(&vsi->back->hw, vsi->idx, 389362306a36Sopenharmony_ci ICE_MCAST_VLAN_PROMISC_BITS, 0); 389462306a36Sopenharmony_ci} 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci/** 389762306a36Sopenharmony_ci * ice_vsi_num_zero_vlans - get number of VLAN 0 filters based on VLAN mode 389862306a36Sopenharmony_ci * @vsi: VSI used to get the VLAN mode 389962306a36Sopenharmony_ci * 390062306a36Sopenharmony_ci * If DVM is enabled then 2 VLAN 0 filters are added, else if SVM is enabled 390162306a36Sopenharmony_ci * then 1 VLAN 0 filter is added. See ice_vsi_add_vlan_zero for more details. 390262306a36Sopenharmony_ci */ 390362306a36Sopenharmony_cistatic u16 ice_vsi_num_zero_vlans(struct ice_vsi *vsi) 390462306a36Sopenharmony_ci{ 390562306a36Sopenharmony_ci#define ICE_DVM_NUM_ZERO_VLAN_FLTRS 2 390662306a36Sopenharmony_ci#define ICE_SVM_NUM_ZERO_VLAN_FLTRS 1 390762306a36Sopenharmony_ci /* no VLAN 0 filter is created when a port VLAN is active */ 390862306a36Sopenharmony_ci if (vsi->type == ICE_VSI_VF) { 390962306a36Sopenharmony_ci if (WARN_ON(!vsi->vf)) 391062306a36Sopenharmony_ci return 0; 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci if (ice_vf_is_port_vlan_ena(vsi->vf)) 391362306a36Sopenharmony_ci return 0; 391462306a36Sopenharmony_ci } 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci if (ice_is_dvm_ena(&vsi->back->hw)) 391762306a36Sopenharmony_ci return ICE_DVM_NUM_ZERO_VLAN_FLTRS; 391862306a36Sopenharmony_ci else 391962306a36Sopenharmony_ci return ICE_SVM_NUM_ZERO_VLAN_FLTRS; 392062306a36Sopenharmony_ci} 392162306a36Sopenharmony_ci 392262306a36Sopenharmony_ci/** 392362306a36Sopenharmony_ci * ice_vsi_has_non_zero_vlans - check if VSI has any non-zero VLANs 392462306a36Sopenharmony_ci * @vsi: VSI used to determine if any non-zero VLANs have been added 392562306a36Sopenharmony_ci */ 392662306a36Sopenharmony_cibool ice_vsi_has_non_zero_vlans(struct ice_vsi *vsi) 392762306a36Sopenharmony_ci{ 392862306a36Sopenharmony_ci return (vsi->num_vlan > ice_vsi_num_zero_vlans(vsi)); 392962306a36Sopenharmony_ci} 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci/** 393262306a36Sopenharmony_ci * ice_vsi_num_non_zero_vlans - get the number of non-zero VLANs for this VSI 393362306a36Sopenharmony_ci * @vsi: VSI used to get the number of non-zero VLANs added 393462306a36Sopenharmony_ci */ 393562306a36Sopenharmony_ciu16 ice_vsi_num_non_zero_vlans(struct ice_vsi *vsi) 393662306a36Sopenharmony_ci{ 393762306a36Sopenharmony_ci return (vsi->num_vlan - ice_vsi_num_zero_vlans(vsi)); 393862306a36Sopenharmony_ci} 393962306a36Sopenharmony_ci 394062306a36Sopenharmony_ci/** 394162306a36Sopenharmony_ci * ice_is_feature_supported 394262306a36Sopenharmony_ci * @pf: pointer to the struct ice_pf instance 394362306a36Sopenharmony_ci * @f: feature enum to be checked 394462306a36Sopenharmony_ci * 394562306a36Sopenharmony_ci * returns true if feature is supported, false otherwise 394662306a36Sopenharmony_ci */ 394762306a36Sopenharmony_cibool ice_is_feature_supported(struct ice_pf *pf, enum ice_feature f) 394862306a36Sopenharmony_ci{ 394962306a36Sopenharmony_ci if (f < 0 || f >= ICE_F_MAX) 395062306a36Sopenharmony_ci return false; 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ci return test_bit(f, pf->features); 395362306a36Sopenharmony_ci} 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci/** 395662306a36Sopenharmony_ci * ice_set_feature_support 395762306a36Sopenharmony_ci * @pf: pointer to the struct ice_pf instance 395862306a36Sopenharmony_ci * @f: feature enum to set 395962306a36Sopenharmony_ci */ 396062306a36Sopenharmony_civoid ice_set_feature_support(struct ice_pf *pf, enum ice_feature f) 396162306a36Sopenharmony_ci{ 396262306a36Sopenharmony_ci if (f < 0 || f >= ICE_F_MAX) 396362306a36Sopenharmony_ci return; 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_ci set_bit(f, pf->features); 396662306a36Sopenharmony_ci} 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci/** 396962306a36Sopenharmony_ci * ice_clear_feature_support 397062306a36Sopenharmony_ci * @pf: pointer to the struct ice_pf instance 397162306a36Sopenharmony_ci * @f: feature enum to clear 397262306a36Sopenharmony_ci */ 397362306a36Sopenharmony_civoid ice_clear_feature_support(struct ice_pf *pf, enum ice_feature f) 397462306a36Sopenharmony_ci{ 397562306a36Sopenharmony_ci if (f < 0 || f >= ICE_F_MAX) 397662306a36Sopenharmony_ci return; 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci clear_bit(f, pf->features); 397962306a36Sopenharmony_ci} 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci/** 398262306a36Sopenharmony_ci * ice_init_feature_support 398362306a36Sopenharmony_ci * @pf: pointer to the struct ice_pf instance 398462306a36Sopenharmony_ci * 398562306a36Sopenharmony_ci * called during init to setup supported feature 398662306a36Sopenharmony_ci */ 398762306a36Sopenharmony_civoid ice_init_feature_support(struct ice_pf *pf) 398862306a36Sopenharmony_ci{ 398962306a36Sopenharmony_ci switch (pf->hw.device_id) { 399062306a36Sopenharmony_ci case ICE_DEV_ID_E810C_BACKPLANE: 399162306a36Sopenharmony_ci case ICE_DEV_ID_E810C_QSFP: 399262306a36Sopenharmony_ci case ICE_DEV_ID_E810C_SFP: 399362306a36Sopenharmony_ci ice_set_feature_support(pf, ICE_F_DSCP); 399462306a36Sopenharmony_ci ice_set_feature_support(pf, ICE_F_PTP_EXTTS); 399562306a36Sopenharmony_ci if (ice_is_e810t(&pf->hw)) { 399662306a36Sopenharmony_ci ice_set_feature_support(pf, ICE_F_SMA_CTRL); 399762306a36Sopenharmony_ci if (ice_gnss_is_gps_present(&pf->hw)) 399862306a36Sopenharmony_ci ice_set_feature_support(pf, ICE_F_GNSS); 399962306a36Sopenharmony_ci } 400062306a36Sopenharmony_ci break; 400162306a36Sopenharmony_ci default: 400262306a36Sopenharmony_ci break; 400362306a36Sopenharmony_ci } 400462306a36Sopenharmony_ci} 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_ci/** 400762306a36Sopenharmony_ci * ice_vsi_update_security - update security block in VSI 400862306a36Sopenharmony_ci * @vsi: pointer to VSI structure 400962306a36Sopenharmony_ci * @fill: function pointer to fill ctx 401062306a36Sopenharmony_ci */ 401162306a36Sopenharmony_ciint 401262306a36Sopenharmony_ciice_vsi_update_security(struct ice_vsi *vsi, void (*fill)(struct ice_vsi_ctx *)) 401362306a36Sopenharmony_ci{ 401462306a36Sopenharmony_ci struct ice_vsi_ctx ctx = { 0 }; 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ci ctx.info = vsi->info; 401762306a36Sopenharmony_ci ctx.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); 401862306a36Sopenharmony_ci fill(&ctx); 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci if (ice_update_vsi(&vsi->back->hw, vsi->idx, &ctx, NULL)) 402162306a36Sopenharmony_ci return -ENODEV; 402262306a36Sopenharmony_ci 402362306a36Sopenharmony_ci vsi->info = ctx.info; 402462306a36Sopenharmony_ci return 0; 402562306a36Sopenharmony_ci} 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci/** 402862306a36Sopenharmony_ci * ice_vsi_ctx_set_antispoof - set antispoof function in VSI ctx 402962306a36Sopenharmony_ci * @ctx: pointer to VSI ctx structure 403062306a36Sopenharmony_ci */ 403162306a36Sopenharmony_civoid ice_vsi_ctx_set_antispoof(struct ice_vsi_ctx *ctx) 403262306a36Sopenharmony_ci{ 403362306a36Sopenharmony_ci ctx->info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF | 403462306a36Sopenharmony_ci (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << 403562306a36Sopenharmony_ci ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); 403662306a36Sopenharmony_ci} 403762306a36Sopenharmony_ci 403862306a36Sopenharmony_ci/** 403962306a36Sopenharmony_ci * ice_vsi_ctx_clear_antispoof - clear antispoof function in VSI ctx 404062306a36Sopenharmony_ci * @ctx: pointer to VSI ctx structure 404162306a36Sopenharmony_ci */ 404262306a36Sopenharmony_civoid ice_vsi_ctx_clear_antispoof(struct ice_vsi_ctx *ctx) 404362306a36Sopenharmony_ci{ 404462306a36Sopenharmony_ci ctx->info.sec_flags &= ~ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF & 404562306a36Sopenharmony_ci ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << 404662306a36Sopenharmony_ci ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); 404762306a36Sopenharmony_ci} 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci/** 405062306a36Sopenharmony_ci * ice_vsi_ctx_set_allow_override - allow destination override on VSI 405162306a36Sopenharmony_ci * @ctx: pointer to VSI ctx structure 405262306a36Sopenharmony_ci */ 405362306a36Sopenharmony_civoid ice_vsi_ctx_set_allow_override(struct ice_vsi_ctx *ctx) 405462306a36Sopenharmony_ci{ 405562306a36Sopenharmony_ci ctx->info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD; 405662306a36Sopenharmony_ci} 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci/** 405962306a36Sopenharmony_ci * ice_vsi_ctx_clear_allow_override - turn off destination override on VSI 406062306a36Sopenharmony_ci * @ctx: pointer to VSI ctx structure 406162306a36Sopenharmony_ci */ 406262306a36Sopenharmony_civoid ice_vsi_ctx_clear_allow_override(struct ice_vsi_ctx *ctx) 406362306a36Sopenharmony_ci{ 406462306a36Sopenharmony_ci ctx->info.sec_flags &= ~ICE_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD; 406562306a36Sopenharmony_ci} 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ci/** 406862306a36Sopenharmony_ci * ice_vsi_update_local_lb - update sw block in VSI with local loopback bit 406962306a36Sopenharmony_ci * @vsi: pointer to VSI structure 407062306a36Sopenharmony_ci * @set: set or unset the bit 407162306a36Sopenharmony_ci */ 407262306a36Sopenharmony_ciint 407362306a36Sopenharmony_ciice_vsi_update_local_lb(struct ice_vsi *vsi, bool set) 407462306a36Sopenharmony_ci{ 407562306a36Sopenharmony_ci struct ice_vsi_ctx ctx = { 407662306a36Sopenharmony_ci .info = vsi->info, 407762306a36Sopenharmony_ci }; 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci ctx.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID); 408062306a36Sopenharmony_ci if (set) 408162306a36Sopenharmony_ci ctx.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_LOCAL_LB; 408262306a36Sopenharmony_ci else 408362306a36Sopenharmony_ci ctx.info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_LOCAL_LB; 408462306a36Sopenharmony_ci 408562306a36Sopenharmony_ci if (ice_update_vsi(&vsi->back->hw, vsi->idx, &ctx, NULL)) 408662306a36Sopenharmony_ci return -ENODEV; 408762306a36Sopenharmony_ci 408862306a36Sopenharmony_ci vsi->info = ctx.info; 408962306a36Sopenharmony_ci return 0; 409062306a36Sopenharmony_ci} 4091