Implement the ndo_get_stats64 callback to report aggregate network statistics. The driver gathers these by accumulating the per-ring counters into the provided rtnl_link_stats64 structure. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Ajit Kumar Khaparde --- .../net/ethernet/broadcom/bnge/bnge_netdev.c | 110 +++++++++++++++++- .../net/ethernet/broadcom/bnge/bnge_netdev.h | 1 + 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c index 29c072e38a7..017bb68f71f 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -2924,6 +2924,102 @@ static int bnge_shutdown_nic(struct bnge_net *bn) return 0; } +static void bnge_get_ring_stats(struct bnge_dev *bd, + struct rtnl_link_stats64 *stats) +{ + struct bnge_net *bn = netdev_priv(bd->netdev); + int i; + + for (i = 0; i < bd->nq_nr_rings; i++) { + struct bnge_napi *bnapi = bn->bnapi[i]; + struct bnge_nq_ring_info *nqr = &bnapi->nq_ring; + u64 *sw = nqr->stats.sw_stats; + + stats->rx_packets += BNGE_GET_RING_STATS64(sw, rx_ucast_pkts); + stats->rx_packets += BNGE_GET_RING_STATS64(sw, rx_mcast_pkts); + stats->rx_packets += BNGE_GET_RING_STATS64(sw, rx_bcast_pkts); + + stats->tx_packets += BNGE_GET_RING_STATS64(sw, tx_ucast_pkts); + stats->tx_packets += BNGE_GET_RING_STATS64(sw, tx_mcast_pkts); + stats->tx_packets += BNGE_GET_RING_STATS64(sw, tx_bcast_pkts); + + stats->rx_bytes += BNGE_GET_RING_STATS64(sw, rx_ucast_bytes); + stats->rx_bytes += BNGE_GET_RING_STATS64(sw, rx_mcast_bytes); + stats->rx_bytes += BNGE_GET_RING_STATS64(sw, rx_bcast_bytes); + + stats->tx_bytes += BNGE_GET_RING_STATS64(sw, tx_ucast_bytes); + stats->tx_bytes += BNGE_GET_RING_STATS64(sw, tx_mcast_bytes); + stats->tx_bytes += BNGE_GET_RING_STATS64(sw, tx_bcast_bytes); + + stats->rx_missed_errors += + BNGE_GET_RING_STATS64(sw, rx_discard_pkts); + + stats->multicast += BNGE_GET_RING_STATS64(sw, rx_mcast_pkts); + + stats->tx_dropped += BNGE_GET_RING_STATS64(sw, tx_error_pkts); + + stats->rx_dropped += + nqr->sw_stats->rx.rx_netpoll_discards + + nqr->sw_stats->rx.rx_oom_discards; + } +} + +static void bnge_add_prev_stats(struct bnge_net *bn, + struct rtnl_link_stats64 *stats) +{ + struct rtnl_link_stats64 *prev_stats = &bn->net_stats_prev; + + stats->rx_packets += prev_stats->rx_packets; + stats->tx_packets += prev_stats->tx_packets; + stats->rx_bytes += prev_stats->rx_bytes; + stats->tx_bytes += prev_stats->tx_bytes; + stats->rx_missed_errors += prev_stats->rx_missed_errors; + stats->multicast += prev_stats->multicast; + stats->rx_dropped += prev_stats->rx_dropped; + stats->tx_dropped += prev_stats->tx_dropped; +} + +static void bnge_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + struct bnge_net *bn = netdev_priv(dev); + struct bnge_dev *bd = bn->bd; + + rcu_read_lock(); + if (!test_bit(BNGE_STATE_OPEN, &bd->state)) { + rcu_read_unlock(); + *stats = bn->net_stats_prev; + return; + } + + bnge_get_ring_stats(bd, stats); + bnge_add_prev_stats(bn, stats); + + if (bn->flags & BNGE_FLAG_PORT_STATS) { + u64 *rx = bn->port_stats.sw_stats; + u64 *tx = bn->port_stats.sw_stats + + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + + stats->rx_crc_errors = + BNGE_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); + stats->rx_frame_errors = + BNGE_GET_RX_PORT_STATS64(rx, rx_align_err_frames); + stats->rx_length_errors = + BNGE_GET_RX_PORT_STATS64(rx, rx_undrsz_frames) + + BNGE_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames) + + BNGE_GET_RX_PORT_STATS64(rx, rx_runt_frames); + stats->rx_errors = + BNGE_GET_RX_PORT_STATS64(rx, rx_false_carrier_frames) + + BNGE_GET_RX_PORT_STATS64(rx, rx_jbr_frames); + stats->collisions = + BNGE_GET_TX_PORT_STATS64(tx, tx_total_collisions); + stats->tx_fifo_errors = + BNGE_GET_TX_PORT_STATS64(tx, tx_fifo_underruns); + stats->tx_errors = BNGE_GET_TX_PORT_STATS64(tx, tx_err); + } + rcu_read_unlock(); +} + static void bnge_close_core(struct bnge_net *bn) { struct bnge_dev *bd = bn->bd; @@ -2931,14 +3027,23 @@ static void bnge_close_core(struct bnge_net *bn) bnge_tx_disable(bn); clear_bit(BNGE_STATE_OPEN, &bd->state); - /* Ensure BNGE_STATE_OPEN is cleared before checking drv_busy */ - smp_mb__after_atomic(); + /* No explicit barrier needed - synchronize_rcu() provides full + * ordering between clear_bit() above and drv_busy() below. + */ + synchronize_rcu(); while (bnge_drv_busy(bn)) msleep(20); timer_delete_sync(&bn->timer); bnge_shutdown_nic(bn); bnge_disable_napi(bn); + + /* Save ring stats before shutdown */ + if (bn->bnapi) { + bnge_get_ring_stats(bd, &bn->net_stats_prev); + bnge_get_ring_err_stats(bn, &bn->ring_err_stats_prev); + } + bnge_free_all_rings_bufs(bn); bnge_free_irq(bn); bnge_del_napi(bn); @@ -2988,6 +3093,7 @@ static const struct net_device_ops bnge_netdev_ops = { .ndo_open = bnge_open, .ndo_stop = bnge_close, .ndo_start_xmit = bnge_start_xmit, + .ndo_get_stats64 = bnge_get_stats64, .ndo_features_check = bnge_features_check, }; diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h index f160ba9b69c..5a2defa970c 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -382,6 +382,7 @@ struct bnge_net { u64 flags; + struct rtnl_link_stats64 net_stats_prev; struct bnge_total_ring_err_stats ring_err_stats_prev; struct bnge_stats_mem port_stats; -- 2.47.3