diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_lib.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_lib.c | 354 |
1 files changed, 205 insertions, 149 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 9e08db376d3d..7cd2dd066ef5 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -153,23 +153,61 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi) } } -static u16 ice_get_rxq_count(struct ice_pf *pf) +static u16 ice_get_rxq_count(struct ice_pf *pf, u16 held) { - return min(ice_get_avail_rxq_count(pf), - netif_get_num_default_rss_queues()); + return min_t(u16, ice_get_avail_rxq_count(pf) + held, + netif_get_num_default_rss_queues()); } -static u16 ice_get_txq_count(struct ice_pf *pf) +static u16 ice_get_txq_count(struct ice_pf *pf, u16 held) { - return min(ice_get_avail_txq_count(pf), - netif_get_num_default_rss_queues()); + return min_t(u16, ice_get_avail_txq_count(pf) + held, + netif_get_num_default_rss_queues()); +} + +/* @held_txq, @held_rxq: queues the VSI still owns but is about to return to the + * PF pool, so that the result matches what it will be once they are back there. + */ +static struct ice_vsi_alloc_queues_params +ice_vsi_get_num_qs(struct ice_vsi *vsi, u16 held_txq, u16 held_rxq) +{ + struct ice_vsi_alloc_queues_params qs = {}; + struct ice_pf *pf = vsi->back; + + switch (vsi->type) { + case ICE_VSI_PF: + qs.alloc_txq = vsi->req_txq ?: ice_get_txq_count(pf, held_txq); + + /* only 1 Rx queue unless RSS is enabled */ + if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + qs.alloc_rxq = 1; + else + qs.alloc_rxq = vsi->req_rxq ?: + ice_get_rxq_count(pf, held_rxq); + break; + case ICE_VSI_SF: + case ICE_VSI_CTRL: + case ICE_VSI_LB: + qs.alloc_txq = 1; + qs.alloc_rxq = 1; + break; + case ICE_VSI_VF: + qs.alloc_txq = vsi->vf->num_req_qs ?: vsi->vf->num_vf_qs; + qs.alloc_rxq = qs.alloc_txq; + break; + case ICE_VSI_CHNL: + break; + default: + dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi->type); + return vsi->alloc_txq_rxq; + } + + return qs; } /** * ice_vsi_set_num_qs - Set number of queues, descriptors and vectors for a VSI * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error */ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) { @@ -180,44 +218,27 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) if (WARN_ON(vsi_type == ICE_VSI_VF && !vf)) return; + vsi->alloc_txq_rxq = ice_vsi_get_num_qs(vsi, 0, 0); + switch (vsi_type) { case ICE_VSI_PF: - if (vsi->req_txq) { - vsi->alloc_txq = vsi->req_txq; + if (vsi->req_txq) vsi->num_txq = vsi->req_txq; - } else { - vsi->alloc_txq = ice_get_txq_count(pf); - } + if (vsi->req_rxq && test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + vsi->num_rxq = vsi->req_rxq; pf->num_lan_tx = vsi->alloc_txq; - - /* only 1 Rx queue unless RSS is enabled */ - if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { - vsi->alloc_rxq = 1; - } else { - if (vsi->req_rxq) { - vsi->alloc_rxq = vsi->req_rxq; - vsi->num_rxq = vsi->req_rxq; - } else { - vsi->alloc_rxq = ice_get_rxq_count(pf); - } - } - pf->num_lan_rx = vsi->alloc_rxq; vsi->num_q_vectors = max(vsi->alloc_rxq, vsi->alloc_txq); break; case ICE_VSI_SF: - vsi->alloc_txq = 1; - vsi->alloc_rxq = 1; vsi->num_q_vectors = 1; vsi->irq_dyn_alloc = true; break; case ICE_VSI_VF: if (vf->num_req_qs) vf->num_vf_qs = vf->num_req_qs; - vsi->alloc_txq = vf->num_vf_qs; - vsi->alloc_rxq = vf->num_vf_qs; /* pf->vfs.num_msix_per includes (VF miscellaneous vector + * data queue interrupts). Since vsi->num_q_vectors is number * of queues vectors, subtract 1 (ICE_NONQ_VECS_VF) from the @@ -226,22 +247,15 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) vsi->num_q_vectors = vf->num_msix - ICE_NONQ_VECS_VF; break; case ICE_VSI_CTRL: - vsi->alloc_txq = 1; - vsi->alloc_rxq = 1; vsi->num_q_vectors = 1; break; case ICE_VSI_CHNL: - vsi->alloc_txq = 0; - vsi->alloc_rxq = 0; break; case ICE_VSI_LB: - vsi->alloc_txq = 1; - vsi->alloc_rxq = 1; /* A dummy q_vector, no actual IRQ. */ vsi->num_q_vectors = 1; break; default: - dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi_type); break; } @@ -330,6 +344,32 @@ static void ice_vsi_free_arrays(struct ice_vsi *vsi) vsi->rxq_map = NULL; } +/* free single stats memory */ +static void __ice_vsi_free_stats(struct ice_vsi_stats *vsi_stat, bool free_entries) +{ + if (!vsi_stat) + return; + + if (free_entries) { + for (int i = 0; i < vsi_stat->tx_ring_stats_len; i++) { + if (vsi_stat->tx_ring_stats[i]) { + kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); + } + } + for (int i = 0; i < vsi_stat->rx_ring_stats_len; i++) { + if (vsi_stat->rx_ring_stats[i]) { + kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); + } + } + } + + kfree(vsi_stat->tx_ring_stats); + kfree(vsi_stat->rx_ring_stats); + kfree(vsi_stat); +} + /** * ice_vsi_free_stats - Free the ring statistics structures * @vsi: VSI pointer @@ -338,7 +378,6 @@ static void ice_vsi_free_stats(struct ice_vsi *vsi) { struct ice_vsi_stats *vsi_stat; struct ice_pf *pf = vsi->back; - int i; if (vsi->type == ICE_VSI_CHNL) return; @@ -346,26 +385,7 @@ static void ice_vsi_free_stats(struct ice_vsi *vsi) return; vsi_stat = pf->vsi_stats[vsi->idx]; - if (!vsi_stat) - return; - - ice_for_each_alloc_txq(vsi, i) { - if (vsi_stat->tx_ring_stats[i]) { - kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); - } - } - - ice_for_each_alloc_rxq(vsi, i) { - if (vsi_stat->rx_ring_stats[i]) { - kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); - } - } - - kfree(vsi_stat->tx_ring_stats); - kfree(vsi_stat->rx_ring_stats); - kfree(vsi_stat); + __ice_vsi_free_stats(vsi_stat, true); pf->vsi_stats[vsi->idx] = NULL; } @@ -513,13 +533,116 @@ static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) return IRQ_HANDLED; } +static struct ice_vsi_stats *ice_vsi_new_stat_arrays(int txq, int rxq) +{ + struct ice_ring_stats **tx_ring_stats; + struct ice_ring_stats **rx_ring_stats; + struct ice_vsi_stats *vsi_stat; + + vsi_stat = kzalloc_obj(*vsi_stat); + tx_ring_stats = kzalloc_objs(*tx_ring_stats, txq); + rx_ring_stats = kzalloc_objs(*rx_ring_stats, rxq); + if (!vsi_stat || !tx_ring_stats || !rx_ring_stats) { + kfree(vsi_stat); + kfree(tx_ring_stats); + kfree(rx_ring_stats); + return NULL; + } + + vsi_stat->tx_ring_stats = tx_ring_stats; + vsi_stat->rx_ring_stats = rx_ring_stats; + vsi_stat->tx_ring_stats_len = txq; + vsi_stat->rx_ring_stats_len = rxq; + + return vsi_stat; +} + +static void ice_vsi_free_unused_stat_arrays(struct ice_vsi_stats *vsi_stat, + struct ice_vsi_stats *new_vsi_stat) +{ + int new_txq = new_vsi_stat->tx_ring_stats_len; + int new_rxq = new_vsi_stat->rx_ring_stats_len; + int prev_txq = vsi_stat->tx_ring_stats_len; + int prev_rxq = vsi_stat->rx_ring_stats_len; + + for (int i = new_txq; i < prev_txq; i++) { + if (vsi_stat->tx_ring_stats[i]) { + kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); + } + } + for (int i = new_rxq; i < prev_rxq; i++) { + if (vsi_stat->rx_ring_stats[i]) { + kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); + } + } +} + +static void ice_vsi_set_stat_arrays(struct ice_vsi *vsi, + struct ice_vsi_stats *new_vsi_stat) +{ + u16 new_txq, new_rxq, prev_txq, prev_rxq; + struct ice_vsi_stats *vsi_stat; + struct ice_pf *pf = vsi->back; + + new_txq = new_vsi_stat->tx_ring_stats_len; + new_rxq = new_vsi_stat->rx_ring_stats_len; + vsi_stat = pf->vsi_stats[vsi->idx]; + pf->vsi_stats[vsi->idx] = new_vsi_stat; + if (!vsi_stat) + return; /* don't copy if there is no source */ + + prev_txq = vsi_stat->tx_ring_stats_len; + prev_rxq = vsi_stat->rx_ring_stats_len; + + memcpy(new_vsi_stat->tx_ring_stats, vsi_stat->tx_ring_stats, + sizeof(*vsi_stat->tx_ring_stats) * min(prev_txq, new_txq)); + memcpy(new_vsi_stat->rx_ring_stats, vsi_stat->rx_ring_stats, + sizeof(*vsi_stat->rx_ring_stats) * min(prev_rxq, new_rxq)); +} + +/** + * ice_vsi_install_stat_arrays - swap in freshly sized ring stats arrays + * @vsi: VSI to install the ring stats arrays of + * @txq: number of Tx ring stats entries to make room for + * @rxq: number of Rx ring stats entries to make room for + * + * Surviving entries are carried over, the rest is freed together with the old + * container. + * + * Return: 0 on success and negative value on failure. + */ +static int ice_vsi_install_stat_arrays(struct ice_vsi *vsi, u16 txq, u16 rxq) +{ + struct ice_vsi_stats *old_stat, *new_stat; + + new_stat = ice_vsi_new_stat_arrays(txq, rxq); + if (!new_stat) + return -ENOMEM; + + old_stat = vsi->back->vsi_stats[vsi->idx]; + ice_vsi_set_stat_arrays(vsi, new_stat); + if (old_stat) { + ice_vsi_free_unused_stat_arrays(old_stat, new_stat); + __ice_vsi_free_stats(old_stat, false); + } + + return 0; +} + /** * ice_vsi_alloc_stat_arrays - Allocate statistics arrays * @vsi: VSI pointer + * + * Runs after ice_vsi_set_num_qs(), so this is the first point where the queue + * count is final. Grow the arrays if an earlier sizing guessed too low. + * + * Return: 0 on success, negative error code otherwise. */ static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi) { - struct ice_vsi_stats *vsi_stat; + struct ice_vsi_stats *old_stat; struct ice_pf *pf = vsi->back; if (vsi->type == ICE_VSI_CHNL) @@ -527,35 +650,13 @@ static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi) if (!pf->vsi_stats) return -ENOENT; - if (pf->vsi_stats[vsi->idx]) - /* realloc will happen in rebuild path */ + old_stat = pf->vsi_stats[vsi->idx]; + if (old_stat && old_stat->tx_ring_stats_len >= vsi->alloc_txq && + old_stat->rx_ring_stats_len >= vsi->alloc_rxq) return 0; - vsi_stat = kzalloc_obj(*vsi_stat); - if (!vsi_stat) - return -ENOMEM; - - vsi_stat->tx_ring_stats = - kzalloc_objs(*vsi_stat->tx_ring_stats, vsi->alloc_txq); - if (!vsi_stat->tx_ring_stats) - goto err_alloc_tx; - - vsi_stat->rx_ring_stats = - kzalloc_objs(*vsi_stat->rx_ring_stats, vsi->alloc_rxq); - if (!vsi_stat->rx_ring_stats) - goto err_alloc_rx; - - pf->vsi_stats[vsi->idx] = vsi_stat; - - return 0; - -err_alloc_rx: - kfree(vsi_stat->rx_ring_stats); -err_alloc_tx: - kfree(vsi_stat->tx_ring_stats); - kfree(vsi_stat); - pf->vsi_stats[vsi->idx] = NULL; - return -ENOMEM; + return ice_vsi_install_stat_arrays(vsi, vsi->alloc_txq, + vsi->alloc_rxq); } /** @@ -1705,16 +1806,7 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi) */ bool ice_pf_state_is_nominal(struct ice_pf *pf) { - DECLARE_BITMAP(check_bits, ICE_STATE_NBITS) = { 0 }; - - if (!pf) - return false; - - bitmap_set(check_bits, 0, ICE_STATE_NOMINAL_CHECK_BITS); - if (bitmap_intersects(pf->state, check_bits, ICE_STATE_NBITS)) - return false; - - return true; + return bitmap_empty(pf->state, ICE_STATE_NOMINAL_CHECK_BITS); } #define ICE_FW_MODE_REC_M BIT(1) @@ -3015,63 +3107,27 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, } /** - * ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones - * @vsi: VSI pointer + * ice_vsi_resize_stat_arrays - resize ring stats arrays for new queue count + * @vsi: VSI to swap the ring stats arrays of + * + * Call while @vsi still owns its queues and before ice_vsi_decfg() returns them + * to the PF pool, so that the new size is what ice_vsi_set_num_qs() will compute + * afterwards. Surviving entries are carried over, the rest is freed. + * + * Return: 0 on success and negative value on failure. */ -static int -ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi) +static int ice_vsi_resize_stat_arrays(struct ice_vsi *vsi) { - u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq; - u16 req_rxq = vsi->req_rxq ? vsi->req_rxq : vsi->alloc_rxq; - struct ice_ring_stats **tx_ring_stats; - struct ice_ring_stats **rx_ring_stats; - struct ice_vsi_stats *vsi_stat; - struct ice_pf *pf = vsi->back; - u16 prev_txq = vsi->alloc_txq; - u16 prev_rxq = vsi->alloc_rxq; - int i; - - vsi_stat = pf->vsi_stats[vsi->idx]; - - if (req_txq < prev_txq) { - for (i = req_txq; i < prev_txq; i++) { - if (vsi_stat->tx_ring_stats[i]) { - kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); - } - } - } - - tx_ring_stats = vsi_stat->tx_ring_stats; - vsi_stat->tx_ring_stats = - krealloc_array(vsi_stat->tx_ring_stats, req_txq, - sizeof(*vsi_stat->tx_ring_stats), - GFP_KERNEL | __GFP_ZERO); - if (!vsi_stat->tx_ring_stats) { - vsi_stat->tx_ring_stats = tx_ring_stats; - return -ENOMEM; - } + struct ice_vsi_alloc_queues_params qs; - if (req_rxq < prev_rxq) { - for (i = req_rxq; i < prev_rxq; i++) { - if (vsi_stat->rx_ring_stats[i]) { - kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); - } - } - } + /* channel VSIs have no entry in pf->vsi_stats[] */ + if (vsi->type == ICE_VSI_CHNL) + return 0; - rx_ring_stats = vsi_stat->rx_ring_stats; - vsi_stat->rx_ring_stats = - krealloc_array(vsi_stat->rx_ring_stats, req_rxq, - sizeof(*vsi_stat->rx_ring_stats), - GFP_KERNEL | __GFP_ZERO); - if (!vsi_stat->rx_ring_stats) { - vsi_stat->rx_ring_stats = rx_ring_stats; - return -ENOMEM; - } + qs = ice_vsi_get_num_qs(vsi, vsi->alloc_txq + vsi->num_xdp_txq, + vsi->alloc_rxq); - return 0; + return ice_vsi_install_stat_arrays(vsi, qs.alloc_txq, qs.alloc_rxq); } /** @@ -3101,7 +3157,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags) mutex_lock(&vsi->xdp_state_lock); - ret = ice_vsi_realloc_stat_arrays(vsi); + ret = ice_vsi_resize_stat_arrays(vsi); if (ret) goto unlock; |
