[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251114195312.22863-13-bhargava.marreddy@broadcom.com>
Date: Sat, 15 Nov 2025 01:23:00 +0530
From: Bhargava Marreddy <bhargava.marreddy@...adcom.com>
To: davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
andrew+netdev@...n.ch,
horms@...nel.org
Cc: netdev@...r.kernel.org,
linux-kernel@...r.kernel.org,
michael.chan@...adcom.com,
pavan.chebbi@...adcom.com,
vsrama-krishna.nemani@...adcom.com,
vikas.gupta@...adcom.com,
Bhargava Marreddy <bhargava.marreddy@...adcom.com>,
Rajashekar Hudumula <rajashekar.hudumula@...adcom.com>
Subject: [v2, net-next 12/12] bng_en: Query firmware for statistics and accumulate
Use the per-PF workqueue and timer infrastructure to asynchronously fetch
statistics from firmware and accumulate them in the PF context. With this
patch, ethtool -S exposes all hardware stats.
Signed-off-by: Bhargava Marreddy <bhargava.marreddy@...adcom.com>
Reviewed-by: Vikas Gupta <vikas.gupta@...adcom.com>
Reviewed-by: Rajashekar Hudumula <rajashekar.hudumula@...adcom.com>
---
.../net/ethernet/broadcom/bnge/bnge_netdev.c | 95 +++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
index 872c8b6a9be..dbca011db33 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
@@ -253,6 +253,17 @@ static int bnge_alloc_ring_stats(struct bnge_net *bn)
return rc;
}
+static void __bnge_queue_sp_work(struct bnge_dev *bd)
+{
+ queue_work(bd->bnge_pf_wq, &bd->sp_task);
+}
+
+static void bnge_queue_sp_work(struct bnge_dev *bd, unsigned int event)
+{
+ set_bit(event, &bd->sp_event);
+ __bnge_queue_sp_work(bd);
+}
+
void bnge_timer(struct timer_list *t)
{
struct bnge_dev *bd = timer_container_of(bd, t, timer);
@@ -265,16 +276,100 @@ void bnge_timer(struct timer_list *t)
if (atomic_read(&bn->intr_sem) != 0)
goto bnge_restart_timer;
+ if (BNGE_LINK_IS_UP(bd) && bn->stats_coal_ticks)
+ bnge_queue_sp_work(bd, BNGE_PERIODIC_STATS_SP_EVENT);
+
bnge_restart_timer:
mod_timer(&bd->timer, jiffies + bd->current_interval);
}
+static void bnge_add_one_ctr(u64 hw, u64 *sw, u64 mask)
+{
+ u64 sw_tmp;
+
+ hw &= mask;
+ sw_tmp = (*sw & ~mask) | hw;
+ if (hw < (*sw & mask))
+ sw_tmp += mask + 1;
+ WRITE_ONCE(*sw, sw_tmp);
+}
+
+static void __bnge_accumulate_stats(__le64 *hw_stats, u64 *sw_stats, u64 *masks,
+ int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ u64 hw = le64_to_cpu(READ_ONCE(hw_stats[i]));
+
+ if (masks[i] == -1ULL)
+ sw_stats[i] = hw;
+ else
+ bnge_add_one_ctr(hw, &sw_stats[i], masks[i]);
+ }
+}
+
+static void bnge_accumulate_stats(struct bnge_stats_mem *stats)
+{
+ if (!stats->hw_stats)
+ return;
+
+ __bnge_accumulate_stats(stats->hw_stats, stats->sw_stats,
+ stats->hw_masks, stats->len / 8);
+}
+
+static void bnge_accumulate_all_stats(struct bnge_dev *bd)
+{
+ struct bnge_net *bn = netdev_priv(bd->netdev);
+ struct bnge_stats_mem *ring0_stats;
+ int i;
+
+ for (i = 0; i < bd->nq_nr_rings; i++) {
+ struct bnge_napi *bnapi = bn->bnapi[i];
+ struct bnge_nq_ring_info *nqr;
+ struct bnge_stats_mem *stats;
+
+ nqr = &bnapi->nq_ring;
+ stats = &nqr->stats;
+ if (!i)
+ ring0_stats = stats;
+ __bnge_accumulate_stats(stats->hw_stats, stats->sw_stats,
+ ring0_stats->hw_masks,
+ ring0_stats->len / 8);
+ }
+ if (bn->flags & BNGE_FLAG_PORT_STATS) {
+ struct bnge_stats_mem *stats = &bn->port_stats;
+ __le64 *hw_stats = stats->hw_stats;
+ u64 *sw_stats = stats->sw_stats;
+ u64 *masks = stats->hw_masks;
+ int cnt;
+
+ cnt = sizeof(struct rx_port_stats) / 8;
+ __bnge_accumulate_stats(hw_stats, sw_stats, masks, cnt);
+
+ hw_stats += BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
+ sw_stats += BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
+ masks += BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
+ cnt = sizeof(struct tx_port_stats) / 8;
+ __bnge_accumulate_stats(hw_stats, sw_stats, masks, cnt);
+ }
+ if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) {
+ bnge_accumulate_stats(&bn->rx_port_stats_ext);
+ bnge_accumulate_stats(&bn->tx_port_stats_ext);
+ }
+}
+
void bnge_sp_task(struct work_struct *work)
{
struct bnge_dev *bd = container_of(work, struct bnge_dev, sp_task);
set_bit(BNGE_STATE_IN_SP_TASK, &bd->state);
smp_mb__after_atomic();
+ if (test_and_clear_bit(BNGE_PERIODIC_STATS_SP_EVENT, &bd->sp_event)) {
+ bnge_hwrm_port_qstats(bd, 0);
+ bnge_hwrm_port_qstats_ext(bd, 0);
+ bnge_accumulate_all_stats(bd);
+ }
smp_mb__before_atomic();
clear_bit(BNGE_STATE_IN_SP_TASK, &bd->state);
--
2.47.3
Powered by blists - more mailing lists