From 1d0e28a9be1fa02309b16dd68db31b4c8e716912 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Mon, 31 Oct 2022 10:09:12 -0700 Subject: ice: Remove and replace ice speed defines with ethtool.h versions The driver is currently using ICE_LINK_SPEED_* defines that mirror what ethtool.h defines, with one exception ICE_LINK_SPEED_UNKNOWN. This issue is fixed by the following changes: 1. replace ICE_LINK_SPEED_UNKNOWN with 0 because SPEED_UNKNOWN in ethtool.h is "-1" and that doesn't match the driver's expected behavior 2. transform ICE_LINK_SPEED_*MBPS to SPEED_* using static tables and fls()-1 to convert from BIT() to an index in a table. Suggested-by: Alexander Lobakin Signed-off-by: Brett Creeley Co-developed-by: Jesse Brandeburg Signed-off-by: Jesse Brandeburg Tested-by: Gurucharan G (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) (limited to 'drivers/net/ethernet/intel/ice/ice_lib.c') diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 7276badfa19e..a2cfa0c614ce 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -3850,33 +3850,11 @@ int ice_clear_dflt_vsi(struct ice_vsi *vsi) */ int ice_get_link_speed_mbps(struct ice_vsi *vsi) { - switch (vsi->port_info->phy.link_info.link_speed) { - case ICE_AQ_LINK_SPEED_100GB: - return SPEED_100000; - case ICE_AQ_LINK_SPEED_50GB: - return SPEED_50000; - case ICE_AQ_LINK_SPEED_40GB: - return SPEED_40000; - case ICE_AQ_LINK_SPEED_25GB: - return SPEED_25000; - case ICE_AQ_LINK_SPEED_20GB: - return SPEED_20000; - case ICE_AQ_LINK_SPEED_10GB: - return SPEED_10000; - case ICE_AQ_LINK_SPEED_5GB: - return SPEED_5000; - case ICE_AQ_LINK_SPEED_2500MB: - return SPEED_2500; - case ICE_AQ_LINK_SPEED_1000MB: - return SPEED_1000; - case ICE_AQ_LINK_SPEED_100MB: - return SPEED_100; - case ICE_AQ_LINK_SPEED_10MB: - return SPEED_10; - case ICE_AQ_LINK_SPEED_UNKNOWN: - default: - return 0; - } + unsigned int link_speed; + + link_speed = vsi->port_info->phy.link_info.link_speed; + + return (int)ice_get_link_speed(fls(link_speed) - 1); } /** -- cgit From 2fd5e433cd2685d4af471209e48be1a951687193 Mon Sep 17 00:00:00 2001 From: Benjamin Mikailenko Date: Fri, 18 Nov 2022 16:20:01 -0500 Subject: ice: Accumulate HW and Netdev statistics over reset Resets happen with or without user interaction. For example, incidents such as TX hang or a reconfiguration of parameters will result in a reset. During reset, hardware and software statistics were set to zero. This created an issue for the user where a reset happens in the background, statistics set to zero, and the user checks statistics expecting them to be populated. To ensure this doesn't happen, keep accumulating stats over reset. 1. Remove function calls which reset hardware and netdev statistics. 2. Do not rollover statistics in ice_stat_update40 during reset. Signed-off-by: Benjamin Mikailenko Tested-by: Gurucharan G (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/ethernet/intel/ice/ice_lib.c') diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index a2cfa0c614ce..ffb455e1f3dc 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1795,11 +1795,15 @@ void ice_update_eth_stats(struct ice_vsi *vsi) { struct ice_eth_stats *prev_es, *cur_es; struct ice_hw *hw = &vsi->back->hw; + struct ice_pf *pf = vsi->back; u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */ prev_es = &vsi->eth_stats_prev; cur_es = &vsi->eth_stats; + if (ice_is_reset_in_progress(pf->state)) + vsi->stat_offsets_loaded = false; + ice_stat_update40(hw, GLV_GORCL(vsi_num), vsi->stat_offsets_loaded, &prev_es->rx_bytes, &cur_es->rx_bytes); @@ -3304,6 +3308,8 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) goto err_vectors; ice_vsi_map_rings_to_vectors(vsi); + + vsi->stat_offsets_loaded = false; if (ice_is_xdp_ena_vsi(vsi)) { ret = ice_vsi_determine_xdp_res(vsi); if (ret) @@ -3340,6 +3346,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) if (ret) goto err_vectors; + vsi->stat_offsets_loaded = false; break; case ICE_VSI_CHNL: if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { -- cgit From 288ecf491b1654845ae99c79b7fefad2d3ea47bd Mon Sep 17 00:00:00 2001 From: Benjamin Mikailenko Date: Fri, 18 Nov 2022 16:20:02 -0500 Subject: ice: Accumulate ring statistics over reset Resets may occur with or without user interaction. For example, a TX hang or reconfiguration of parameters will result in a reset. During reset, the VSI is freed, freeing any statistics structures inside as well. This would create an issue for the user where a reset happens in the background, statistics set to zero, and the user checks ring statistics expecting them to be populated. To ensure this doesn't happen, accumulate ring statistics over reset. Define a new ring statistics structure, ice_ring_stats. The new structure lives in the VSI's parent, preserving ring statistics when VSI is freed. 1. Define a new structure vsi_ring_stats in the PF scope 2. Allocate/free stats only during probe, unload, or change in ring size 3. Replace previous ring statistics functionality with new structure Signed-off-by: Benjamin Mikailenko Tested-by: Gurucharan G (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 233 +++++++++++++++++++++++++++++-- 1 file changed, 225 insertions(+), 8 deletions(-) (limited to 'drivers/net/ethernet/intel/ice/ice_lib.c') diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index ffb455e1f3dc..94aa834cd9a6 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -447,6 +447,49 @@ static irqreturn_t ice_eswitch_msix_clean_rings(int __always_unused irq, void *d return IRQ_HANDLED; } +/** + * ice_vsi_alloc_stat_arrays - Allocate statistics arrays + * @vsi: VSI pointer + */ +static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi) +{ + struct ice_vsi_stats *vsi_stat; + struct ice_pf *pf = vsi->back; + + if (vsi->type == ICE_VSI_CHNL) + return 0; + if (!pf->vsi_stats) + return -ENOENT; + + vsi_stat = kzalloc(sizeof(*vsi_stat), GFP_KERNEL); + if (!vsi_stat) + return -ENOMEM; + + vsi_stat->tx_ring_stats = + kcalloc(vsi->alloc_txq, sizeof(*vsi_stat->tx_ring_stats), + GFP_KERNEL); + if (!vsi_stat->tx_ring_stats) + goto err_alloc_tx; + + vsi_stat->rx_ring_stats = + kcalloc(vsi->alloc_rxq, sizeof(*vsi_stat->rx_ring_stats), + GFP_KERNEL); + 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; +} + /** * ice_vsi_alloc - Allocates the next available struct VSI in the PF * @pf: board private structure @@ -560,6 +603,11 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, if (vsi->type == ICE_VSI_CTRL && vf) vf->ctrl_vsi_idx = vsi->idx; + + /* allocate memory for Tx/Rx ring stat pointers */ + if (ice_vsi_alloc_stat_arrays(vsi)) + goto err_rings; + goto unlock_pf; err_rings: @@ -1535,6 +1583,106 @@ err_out: return -ENOMEM; } +/** + * ice_vsi_free_stats - Free the ring statistics structures + * @vsi: VSI pointer + */ +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; + if (!pf->vsi_stats) + 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); + pf->vsi_stats[vsi->idx] = NULL; +} + +/** + * ice_vsi_alloc_ring_stats - Allocates Tx and Rx ring stats for the VSI + * @vsi: VSI which is having stats allocated + */ +static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi) +{ + struct ice_ring_stats **tx_ring_stats; + struct ice_ring_stats **rx_ring_stats; + struct ice_vsi_stats *vsi_stats; + struct ice_pf *pf = vsi->back; + u16 i; + + vsi_stats = pf->vsi_stats[vsi->idx]; + tx_ring_stats = vsi_stats->tx_ring_stats; + rx_ring_stats = vsi_stats->rx_ring_stats; + + /* Allocate Tx ring stats */ + ice_for_each_alloc_txq(vsi, i) { + struct ice_ring_stats *ring_stats; + struct ice_tx_ring *ring; + + ring = vsi->tx_rings[i]; + ring_stats = tx_ring_stats[i]; + + if (!ring_stats) { + ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL); + if (!ring_stats) + goto err_out; + + WRITE_ONCE(tx_ring_stats[i], ring_stats); + } + + ring->ring_stats = ring_stats; + } + + /* Allocate Rx ring stats */ + ice_for_each_alloc_rxq(vsi, i) { + struct ice_ring_stats *ring_stats; + struct ice_rx_ring *ring; + + ring = vsi->rx_rings[i]; + ring_stats = rx_ring_stats[i]; + + if (!ring_stats) { + ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL); + if (!ring_stats) + goto err_out; + + WRITE_ONCE(rx_ring_stats[i], ring_stats); + } + + ring->ring_stats = ring_stats; + } + + return 0; + +err_out: + ice_vsi_free_stats(vsi); + return -ENOMEM; +} + /** * ice_vsi_manage_rss_lut - disable/enable RSS * @vsi: the VSI being changed @@ -2580,6 +2728,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, if (ret) goto unroll_vector_base; + ret = ice_vsi_alloc_ring_stats(vsi); + if (ret) + goto unroll_vector_base; + ice_vsi_map_rings_to_vectors(vsi); /* ICE_VSI_CTRL does not need RSS so skip RSS processing */ @@ -2618,6 +2770,9 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, if (ret) goto unroll_vector_base; + ret = ice_vsi_alloc_ring_stats(vsi); + if (ret) + goto unroll_vector_base; /* Do not exit if configuring RSS had an issue, at least * receive traffic on first queue. Hence no need to capture * return value @@ -2631,6 +2786,11 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, ret = ice_vsi_alloc_rings(vsi); if (ret) goto unroll_vsi_init; + + ret = ice_vsi_alloc_ring_stats(vsi); + if (ret) + goto unroll_vector_base; + break; default: /* clean up the resources and exit */ @@ -2690,6 +2850,7 @@ unroll_vector_base: unroll_alloc_q_vector: ice_vsi_free_q_vectors(vsi); unroll_vsi_init: + ice_vsi_free_stats(vsi); ice_vsi_delete(vsi); unroll_get_qs: ice_vsi_put_qs(vsi); @@ -3081,7 +3242,7 @@ int ice_vsi_release(struct ice_vsi *vsi) vsi->agg_node && vsi->agg_node->valid) vsi->agg_node->num_vsis--; ice_vsi_clear_rings(vsi); - + ice_vsi_free_stats(vsi); ice_vsi_put_qs(vsi); /* retain SW VSI data structure since it is needed to unregister and @@ -3208,6 +3369,47 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, } } +/** + * ice_vsi_realloc_stat_arrays - Frees unused stat structures + * @vsi: VSI pointer + * @prev_txq: Number of Tx rings before ring reallocation + * @prev_rxq: Number of Rx rings before ring reallocation + */ +static int +ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi, int prev_txq, int prev_rxq) +{ + struct ice_vsi_stats *vsi_stat; + struct ice_pf *pf = vsi->back; + int i; + + if (!prev_txq || !prev_rxq) + return 0; + if (vsi->type == ICE_VSI_CHNL) + return 0; + + vsi_stat = pf->vsi_stats[vsi->idx]; + + if (vsi->num_txq < prev_txq) { + for (i = vsi->num_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); + } + } + } + + if (vsi->num_rxq < prev_rxq) { + for (i = vsi->num_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); + } + } + } + + return 0; +} + /** * ice_vsi_rebuild - Rebuild VSI after reset * @vsi: VSI to be rebuild @@ -3219,10 +3421,10 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) { u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; struct ice_coalesce_stored *coalesce; + int ret, i, prev_txq, prev_rxq; int prev_num_q_vectors = 0; enum ice_vsi_type vtype; struct ice_pf *pf; - int ret, i; if (!vsi) return -EINVAL; @@ -3241,6 +3443,9 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi, coalesce); + prev_txq = vsi->num_txq; + prev_rxq = vsi->num_rxq; + ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx); ret = ice_rm_vsi_rdma_cfg(vsi->port_info, vsi->idx); if (ret) @@ -3307,6 +3512,10 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) if (ret) goto err_vectors; + ret = ice_vsi_alloc_ring_stats(vsi); + if (ret) + goto err_vectors; + ice_vsi_map_rings_to_vectors(vsi); vsi->stat_offsets_loaded = false; @@ -3346,6 +3555,10 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) if (ret) goto err_vectors; + ret = ice_vsi_alloc_ring_stats(vsi); + if (ret) + goto err_vectors; + vsi->stat_offsets_loaded = false; break; case ICE_VSI_CHNL: @@ -3394,6 +3607,10 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) return ice_schedule_reset(pf, ICE_RESET_PFR); } } + + if (ice_vsi_realloc_stat_arrays(vsi, prev_txq, prev_rxq)) + goto err_vectors; + ice_vsi_rebuild_set_coalesce(vsi, coalesce, prev_num_q_vectors); kfree(coalesce); @@ -3735,9 +3952,9 @@ static void ice_update_ring_stats(struct ice_q_stats *stats, u64 pkts, u64 bytes */ void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes) { - u64_stats_update_begin(&tx_ring->syncp); - ice_update_ring_stats(&tx_ring->stats, pkts, bytes); - u64_stats_update_end(&tx_ring->syncp); + u64_stats_update_begin(&tx_ring->ring_stats->syncp); + ice_update_ring_stats(&tx_ring->ring_stats->stats, pkts, bytes); + u64_stats_update_end(&tx_ring->ring_stats->syncp); } /** @@ -3748,9 +3965,9 @@ void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes) */ void ice_update_rx_ring_stats(struct ice_rx_ring *rx_ring, u64 pkts, u64 bytes) { - u64_stats_update_begin(&rx_ring->syncp); - ice_update_ring_stats(&rx_ring->stats, pkts, bytes); - u64_stats_update_end(&rx_ring->syncp); + u64_stats_update_begin(&rx_ring->ring_stats->syncp); + ice_update_ring_stats(&rx_ring->ring_stats->stats, pkts, bytes); + u64_stats_update_end(&rx_ring->ring_stats->syncp); } /** -- cgit