Add custom statistics to be reported via ethtool -S. These include
driver specific per-cpu statistics as well as queue and channel
counters.

Signed-off-by: Ioana Radulescu <ruxandra.radule...@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c     |   42 ++++++++++++++++-
 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h     |   36 ++++++++++++++
 drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c |   49 +++++++++++++++++++-
 3 files changed, 123 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c 
b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
index cfa1d36..9033b70 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
@@ -207,6 +207,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
        void *vaddr;
        struct sk_buff *skb;
        struct rtnl_link_stats64 *percpu_stats;
+       struct dpaa2_eth_drv_stats *percpu_extras;
        struct device *dev = priv->net_dev->dev.parent;
        struct dpaa2_fas *fas;
        u32 status = 0;
@@ -218,6 +219,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
        prefetch(vaddr + dpaa2_fd_get_offset(fd));
 
        percpu_stats = this_cpu_ptr(priv->percpu_stats);
+       percpu_extras = this_cpu_ptr(priv->percpu_extras);
 
        if (fd_format == dpaa2_fd_single) {
                skb = build_linear_skb(priv, ch, fd, vaddr);
@@ -226,6 +228,8 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
                                vaddr + dpaa2_fd_get_offset(fd);
                skb = build_frag_skb(priv, ch, sgt);
                skb_free_frag(vaddr);
+               percpu_extras->rx_sg_frames++;
+               percpu_extras->rx_sg_bytes += dpaa2_fd_get_len(fd);
        } else {
                /* We don't support any other format */
                goto err_frame_format;
@@ -290,6 +294,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch)
 
                fd = dpaa2_dq_fd(dq);
                fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq);
+               fq->stats.frames++;
 
                fq->consume(priv, ch, fd, &ch->napi);
                cleaned++;
@@ -531,11 +536,13 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct 
net_device *net_dev)
        struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
        struct dpaa2_fd fd;
        struct rtnl_link_stats64 *percpu_stats;
+       struct dpaa2_eth_drv_stats *percpu_extras;
        struct dpaa2_eth_fq *fq;
        u16 queue_mapping;
        int err, i;
 
        percpu_stats = this_cpu_ptr(priv->percpu_stats);
+       percpu_extras = this_cpu_ptr(priv->percpu_extras);
 
        if (unlikely(skb_headroom(skb) < DPAA2_ETH_NEEDED_HEADROOM(priv))) {
                struct sk_buff *ns;
@@ -564,10 +571,14 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct 
net_device *net_dev)
        /* Setup the FD fields */
        memset(&fd, 0, sizeof(fd));
 
-       if (skb_is_nonlinear(skb))
+       if (skb_is_nonlinear(skb)) {
                err = build_sg_fd(priv, skb, &fd);
-       else
+               percpu_extras->tx_sg_frames++;
+               percpu_extras->tx_sg_bytes += skb->len;
+       } else {
                err = build_single_fd(priv, skb, &fd);
+       }
+
        if (unlikely(err)) {
                percpu_stats->tx_dropped++;
                goto err_build_fd;
@@ -584,6 +595,7 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct 
net_device *net_dev)
                if (err != -EBUSY)
                        break;
        }
+       percpu_extras->tx_portal_busy += i;
        if (unlikely(err < 0)) {
                percpu_stats->tx_errors++;
                /* Clean up everything, including freeing the skb */
@@ -609,8 +621,13 @@ static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv,
                              struct napi_struct *napi __always_unused)
 {
        struct rtnl_link_stats64 *percpu_stats;
+       struct dpaa2_eth_drv_stats *percpu_extras;
        u32 status = 0;
 
+       percpu_extras = this_cpu_ptr(priv->percpu_extras);
+       percpu_extras->tx_conf_frames++;
+       percpu_extras->tx_conf_bytes += dpaa2_fd_get_len(fd);
+
        free_tx_fd(priv, fd, &status);
 
        if (unlikely(status & DPAA2_ETH_TXCONF_ERR_MASK)) {
@@ -815,13 +832,19 @@ static int refill_pool(struct dpaa2_eth_priv *priv,
 static int pull_channel(struct dpaa2_eth_channel *ch)
 {
        int err;
+       int dequeues = -1;
 
        /* Retry while portal is busy */
        do {
                err = dpaa2_io_service_pull_channel(NULL, ch->ch_id, ch->store);
+               dequeues++;
                cpu_relax();
        } while (err == -EBUSY);
 
+       ch->stats.dequeue_portal_busy += dequeues;
+       if (unlikely(err))
+               ch->stats.pull_err++;
+
        return err;
 }
 
@@ -869,6 +892,8 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int 
budget)
                } while (err == -EBUSY);
        }
 
+       ch->stats.frames += cleaned;
+
        return cleaned;
 }
 
@@ -1330,6 +1355,10 @@ static void cdan_cb(struct dpaa2_io_notification_ctx 
*ctx)
        struct dpaa2_eth_channel *ch;
 
        ch = container_of(ctx, struct dpaa2_eth_channel, nctx);
+
+       /* Update NAPI statistics */
+       ch->stats.cdan++;
+
        napi_schedule_irqoff(&ch->napi);
 }
 
@@ -2351,6 +2380,12 @@ static int dpaa2_eth_probe(struct fsl_mc_device 
*dpni_dev)
                err = -ENOMEM;
                goto err_alloc_percpu_stats;
        }
+       priv->percpu_extras = alloc_percpu(*priv->percpu_extras);
+       if (!priv->percpu_extras) {
+               dev_err(dev, "alloc_percpu(percpu_extras) failed\n");
+               err = -ENOMEM;
+               goto err_alloc_percpu_extras;
+       }
 
        err = netdev_init(net_dev);
        if (err)
@@ -2392,6 +2427,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
 err_csum:
        unregister_netdev(net_dev);
 err_netdev_init:
+       free_percpu(priv->percpu_extras);
+err_alloc_percpu_extras:
        free_percpu(priv->percpu_stats);
 err_alloc_percpu_stats:
        del_ch_napi(priv);
@@ -2430,6 +2467,7 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
 
        free_rings(priv);
        free_percpu(priv->percpu_stats);
+       free_percpu(priv->percpu_extras);
 
        del_ch_napi(priv);
        free_dpbp(priv);
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h 
b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
index b757a99..c330927 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
@@ -195,6 +195,38 @@ struct dpaa2_fas {
  */
 #define DPAA2_ETH_ENQUEUE_RETRIES      10
 
+/* Driver statistics, other than those in struct rtnl_link_stats64.
+ * These are usually collected per-CPU and aggregated by ethtool.
+ */
+struct dpaa2_eth_drv_stats {
+       __u64   tx_conf_frames;
+       __u64   tx_conf_bytes;
+       __u64   tx_sg_frames;
+       __u64   tx_sg_bytes;
+       __u64   rx_sg_frames;
+       __u64   rx_sg_bytes;
+       /* Enqueues retried due to portal busy */
+       __u64   tx_portal_busy;
+};
+
+/* Per-FQ statistics */
+struct dpaa2_eth_fq_stats {
+       /* Number of frames received on this queue */
+       __u64 frames;
+};
+
+/* Per-channel statistics */
+struct dpaa2_eth_ch_stats {
+       /* Volatile dequeues retried due to portal busy */
+       __u64 dequeue_portal_busy;
+       /* Number of CDANs; useful to estimate avg NAPI len */
+       __u64 cdan;
+       /* Number of frames received on queues from this channel */
+       __u64 frames;
+       /* Pull errors */
+       __u64 pull_err;
+};
+
 /* Maximum number of queues associated with a DPNI */
 #define DPAA2_ETH_MAX_RX_QUEUES                16
 #define DPAA2_ETH_MAX_TX_QUEUES                NR_CPUS
@@ -222,6 +254,7 @@ struct dpaa2_eth_fq {
                        struct dpaa2_eth_channel *,
                        const struct dpaa2_fd *,
                        struct napi_struct *);
+       struct dpaa2_eth_fq_stats stats;
 };
 
 struct dpaa2_eth_channel {
@@ -234,6 +267,7 @@ struct dpaa2_eth_channel {
        struct dpaa2_io_store *store;
        struct dpaa2_eth_priv *priv;
        int buf_count;
+       struct dpaa2_eth_ch_stats stats;
 };
 
 struct dpaa2_eth_hash_fields {
@@ -273,6 +307,8 @@ struct dpaa2_eth_priv {
 
        /* Standard statistics */
        struct rtnl_link_stats64 __percpu *percpu_stats;
+       /* Extra stats, in addition to the ones known by the kernel */
+       struct dpaa2_eth_drv_stats __percpu *percpu_extras;
 
        u16 mc_token;
 
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c 
b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
index 09cc2c7..00ef665 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
@@ -55,6 +55,23 @@
 
 #define DPAA2_ETH_NUM_STATS    ARRAY_SIZE(dpaa2_ethtool_stats)
 
+char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = {
+       /* per-cpu stats */
+       "tx conf frames",
+       "tx conf bytes",
+       "tx sg frames",
+       "tx sg bytes",
+       "rx sg frames",
+       "rx sg bytes",
+       "enqueue portal busy",
+       /* Channel stats */
+       "dequeue portal busy",
+       "channel pull errors",
+       "cdan",
+};
+
+#define DPAA2_ETH_NUM_EXTRA_STATS      ARRAY_SIZE(dpaa2_ethtool_extras)
+
 static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
                                  struct ethtool_drvinfo *drvinfo)
 {
@@ -146,6 +163,10 @@ static void dpaa2_eth_get_strings(struct net_device 
*netdev, u32 stringset,
                        strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN);
                        p += ETH_GSTRING_LEN;
                }
+               for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) {
+                       strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN);
+                       p += ETH_GSTRING_LEN;
+               }
                break;
        }
 }
@@ -154,7 +175,7 @@ static int dpaa2_eth_get_sset_count(struct net_device 
*net_dev, int sset)
 {
        switch (sset) {
        case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */
-               return DPAA2_ETH_NUM_STATS;
+               return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS;
        default:
                return -EOPNOTSUPP;
        }
@@ -170,9 +191,14 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device 
*net_dev,
        int j, k, err;
        int num_cnt;
        union dpni_statistics dpni_stats;
+       u64 cdan = 0;
+       u64 portal_busy = 0, pull_err = 0;
        struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+       struct dpaa2_eth_drv_stats *extras;
+       struct dpaa2_eth_ch_stats *ch_stats;
 
-       memset(data, 0, sizeof(u64) * DPAA2_ETH_NUM_STATS);
+       memset(data, 0,
+              sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS));
 
        /* Print standard counters, from DPNI statistics */
        for (j = 0; j <= 2; j++) {
@@ -196,6 +222,25 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device 
*net_dev,
                for (k = 0; k < num_cnt; k++)
                        *(data + i++) = dpni_stats.raw.counter[k];
        }
+
+       /* Print per-cpu extra stats */
+       for_each_online_cpu(k) {
+               extras = per_cpu_ptr(priv->percpu_extras, k);
+               for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++)
+                       *((__u64 *)data + i + j) += *((__u64 *)extras + j);
+       }
+       i += j;
+
+       for (j = 0; j < priv->num_channels; j++) {
+               ch_stats = &priv->channel[j]->stats;
+               cdan += ch_stats->cdan;
+               portal_busy += ch_stats->dequeue_portal_busy;
+               pull_err += ch_stats->pull_err;
+       }
+
+       *(data + i++) = portal_busy;
+       *(data + i++) = pull_err;
+       *(data + i++) = cdan;
 }
 
 static int dpaa2_eth_get_rxnfc(struct net_device *net_dev,
-- 
1.7.3.4

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to