summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/ice/ice_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_lib.c')
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c354
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;