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


Reply via email to