Report standard counter stats->rx_missed_errors using hc_rx_discards_no_wqe from the hardware.
Add a dedicated workqueue to periodically run mana_query_gf_stats every 2 seconds to get the latest info in eth_stats and define a driver capability flag to notify hardware of the periodic queries. To avoid repeated failures and log flooding, the workqueue is not rescheduled if mana_query_gf_stats fails. Signed-off-by: Erni Sri Satya Vennela <er...@linux.microsoft.com> Reviewed-By: Haiyang Zhang <haiya...@microsoft.com> --- drivers/net/ethernet/microsoft/mana/mana_en.c | 38 +++++++++++++++++-- .../ethernet/microsoft/mana/mana_ethtool.c | 2 - include/net/mana/gdma.h | 6 ++- include/net/mana/mana.h | 5 ++- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 787644229897..9213ae6ba038 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -494,6 +494,8 @@ static void mana_get_stats64(struct net_device *ndev, netdev_stats_to_stats64(st, &ndev->stats); + st->rx_missed_errors = apc->ac->hc_stats.hc_rx_discards_no_wqe; + for (q = 0; q < num_queues; q++) { rx_stats = &apc->rxqs[q]->stats; @@ -2779,7 +2781,7 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx, return 0; } -void mana_query_gf_stats(struct mana_context *ac) +int mana_query_gf_stats(struct mana_context *ac) { struct mana_query_gf_stat_resp resp = {}; struct mana_query_gf_stat_req req = {}; @@ -2822,14 +2824,14 @@ void mana_query_gf_stats(struct mana_context *ac) sizeof(resp)); if (err) { dev_err(dev, "Failed to query GF stats: %d\n", err); - return; + return err; } err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_GF_STAT, sizeof(resp)); if (err || resp.hdr.status) { dev_err(dev, "Failed to query GF stats: %d, 0x%x\n", err, resp.hdr.status); - return; + return err; } ac->hc_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe; @@ -2864,6 +2866,8 @@ void mana_query_gf_stats(struct mana_context *ac) ac->hc_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts; ac->hc_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes; ac->hc_stats.hc_tx_err_gdma = resp.tx_err_gdma; + + return 0; } void mana_query_phy_stats(struct mana_port_context *apc) @@ -3400,6 +3404,19 @@ int mana_rdma_service_event(struct gdma_context *gc, enum gdma_service_type even return 0; } +#define MANA_GF_STATS_PERIOD (2 * HZ) + +static void mana_gf_stats_work_handler(struct work_struct *work) +{ + struct mana_context *ac = + container_of(to_delayed_work(work), struct mana_context, gf_stats_work); + + if (mana_query_gf_stats(ac)) + return; + + queue_delayed_work(ac->gf_stats_wq, &ac->gf_stats_work, MANA_GF_STATS_PERIOD); +} + int mana_probe(struct gdma_dev *gd, bool resuming) { struct gdma_context *gc = gd->gdma_context; @@ -3488,6 +3505,15 @@ int mana_probe(struct gdma_dev *gd, bool resuming) } err = add_adev(gd, "eth"); + ac->gf_stats_wq = create_singlethread_workqueue("mana_gf_stats"); + if (!ac->gf_stats_wq) { + err = -ENOMEM; + goto out; + } + + INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler); + queue_delayed_work(ac->gf_stats_wq, &ac->gf_stats_work, MANA_GF_STATS_PERIOD); + out: if (err) { mana_remove(gd, false); @@ -3511,6 +3537,12 @@ void mana_remove(struct gdma_dev *gd, bool suspending) int err; int i; + if (ac->gf_stats_wq) { + cancel_delayed_work_sync(&ac->gf_stats_work); + destroy_workqueue(ac->gf_stats_wq); + ac->gf_stats_wq = NULL; + } + /* adev currently doesn't support suspending, always remove it */ if (gd->adev) remove_adev(gd); diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c index 3dfd96146424..99e811208683 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c @@ -213,8 +213,6 @@ static void mana_get_ethtool_stats(struct net_device *ndev, if (!apc->port_is_up) return; - /* we call mana function to update stats from GDMA */ - mana_query_gf_stats(apc->ac); /* We call this mana function to get the phy stats from GDMA and includes * aggregate tx/rx drop counters, Per-TC(Traffic Channel) tx/rx and pause diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h index 57df78cfbf82..88a81fb164a0 100644 --- a/include/net/mana/gdma.h +++ b/include/net/mana/gdma.h @@ -591,6 +591,9 @@ enum { /* Driver can self reset on FPGA Reconfig EQE notification */ #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17) +/* Driver can send HWC periodically to query stats */ +#define GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY BIT(21) + #define GDMA_DRV_CAP_FLAGS1 \ (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \ GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \ @@ -599,7 +602,8 @@ enum { GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP | \ GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \ GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \ - GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE) + GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \ + GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY) #define GDMA_DRV_CAP_FLAGS2 0 diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h index 519c4384c51f..74f112bcdc02 100644 --- a/include/net/mana/mana.h +++ b/include/net/mana/mana.h @@ -480,6 +480,9 @@ struct mana_context { struct mana_eq *eqs; struct dentry *mana_eqs_debugfs; + struct workqueue_struct *gf_stats_wq; + struct delayed_work gf_stats_work; + struct net_device *ports[MAX_PORTS_IN_MANA_DEV]; }; @@ -577,7 +580,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, struct bpf_prog *mana_xdp_get(struct mana_port_context *apc); void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog); int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf); -void mana_query_gf_stats(struct mana_context *ac); +int mana_query_gf_stats(struct mana_context *ac); int mana_query_link_cfg(struct mana_port_context *apc); int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed, int enable_clamping); -- 2.34.1