net: fec: add xdp and page pool statistics
authorShenwei Wang <shenwei.wang@nxp.com>
Fri, 11 Nov 2022 15:35:05 +0000 (09:35 -0600)
committerDavid S. Miller <davem@davemloft.net>
Mon, 14 Nov 2022 11:28:55 +0000 (11:28 +0000)
Added xdp and page pool statistics.
In order to make the implementation simple and compatible, the patch
uses the 32bit integer to record the XDP statistics.

Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/freescale/Kconfig
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c

index ce866ae..f1e80d6 100644 (file)
@@ -29,6 +29,7 @@ config FEC
        select CRC32
        select PHYLIB
        select PAGE_POOL
+       select PAGE_POOL_STATS
        imply NET_SELFTESTS
        help
          Say Y here if you want to use the built-in 10/100 Fast ethernet
index 61e847b..5ba1e0d 100644 (file)
@@ -526,6 +526,19 @@ struct fec_enet_priv_txrx_info {
        struct  sk_buff *skb;
 };
 
+enum {
+       RX_XDP_REDIRECT = 0,
+       RX_XDP_PASS,
+       RX_XDP_DROP,
+       RX_XDP_TX,
+       RX_XDP_TX_ERRORS,
+       TX_XDP_XMIT,
+       TX_XDP_XMIT_ERRORS,
+
+       /* The following must be the last one */
+       XDP_STATS_TOTAL,
+};
+
 struct fec_enet_priv_tx_q {
        struct bufdesc_prop bd;
        unsigned char *tx_bounce[TX_RING_SIZE];
@@ -546,6 +559,7 @@ struct fec_enet_priv_rx_q {
        /* page_pool */
        struct page_pool *page_pool;
        struct xdp_rxq_info xdp_rxq;
+       u32 stats[XDP_STATS_TOTAL];
 
        /* rx queue number, in the range 0-7 */
        u8 id;
index 616eea7..879dfee 100644 (file)
@@ -1523,10 +1523,12 @@ fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
 
        switch (act) {
        case XDP_PASS:
+               rxq->stats[RX_XDP_PASS]++;
                ret = FEC_ENET_XDP_PASS;
                break;
 
        case XDP_REDIRECT:
+               rxq->stats[RX_XDP_REDIRECT]++;
                err = xdp_do_redirect(fep->netdev, xdp, prog);
                if (!err) {
                        ret = FEC_ENET_XDP_REDIR;
@@ -1549,6 +1551,7 @@ fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
                fallthrough;    /* handle aborts by dropping packet */
 
        case XDP_DROP:
+               rxq->stats[RX_XDP_DROP]++;
                ret = FEC_ENET_XDP_CONSUMED;
                page = virt_to_head_page(xdp->data);
                page_pool_put_page(rxq->page_pool, page, sync, true);
@@ -2701,6 +2704,16 @@ static const struct fec_stat {
 
 #define FEC_STATS_SIZE         (ARRAY_SIZE(fec_stats) * sizeof(u64))
 
+static const char *fec_xdp_stat_strs[XDP_STATS_TOTAL] = {
+       "rx_xdp_redirect",           /* RX_XDP_REDIRECT = 0, */
+       "rx_xdp_pass",               /* RX_XDP_PASS, */
+       "rx_xdp_drop",               /* RX_XDP_DROP, */
+       "rx_xdp_tx",                 /* RX_XDP_TX, */
+       "rx_xdp_tx_errors",          /* RX_XDP_TX_ERRORS, */
+       "tx_xdp_xmit",               /* TX_XDP_XMIT, */
+       "tx_xdp_xmit_errors",        /* TX_XDP_XMIT_ERRORS, */
+};
+
 static void fec_enet_update_ethtool_stats(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
@@ -2710,6 +2723,40 @@ static void fec_enet_update_ethtool_stats(struct net_device *dev)
                fep->ethtool_stats[i] = readl(fep->hwp + fec_stats[i].offset);
 }
 
+static void fec_enet_get_xdp_stats(struct fec_enet_private *fep, u64 *data)
+{
+       u64 xdp_stats[XDP_STATS_TOTAL] = { 0 };
+       struct fec_enet_priv_rx_q *rxq;
+       int i, j;
+
+       for (i = fep->num_rx_queues - 1; i >= 0; i--) {
+               rxq = fep->rx_queue[i];
+
+               for (j = 0; j < XDP_STATS_TOTAL; j++)
+                       xdp_stats[j] += rxq->stats[j];
+       }
+
+       memcpy(data, xdp_stats, sizeof(xdp_stats));
+}
+
+static void fec_enet_page_pool_stats(struct fec_enet_private *fep, u64 *data)
+{
+       struct page_pool_stats stats = {};
+       struct fec_enet_priv_rx_q *rxq;
+       int i;
+
+       for (i = fep->num_rx_queues - 1; i >= 0; i--) {
+               rxq = fep->rx_queue[i];
+
+               if (!rxq->page_pool)
+                       continue;
+
+               page_pool_get_stats(rxq->page_pool, &stats);
+       }
+
+       page_pool_ethtool_stats_get(data, &stats);
+}
+
 static void fec_enet_get_ethtool_stats(struct net_device *dev,
                                       struct ethtool_stats *stats, u64 *data)
 {
@@ -2719,6 +2766,12 @@ static void fec_enet_get_ethtool_stats(struct net_device *dev,
                fec_enet_update_ethtool_stats(dev);
 
        memcpy(data, fep->ethtool_stats, FEC_STATS_SIZE);
+       data += FEC_STATS_SIZE / sizeof(u64);
+
+       fec_enet_get_xdp_stats(fep, data);
+       data += XDP_STATS_TOTAL;
+
+       fec_enet_page_pool_stats(fep, data);
 }
 
 static void fec_enet_get_strings(struct net_device *netdev,
@@ -2727,9 +2780,16 @@ static void fec_enet_get_strings(struct net_device *netdev,
        int i;
        switch (stringset) {
        case ETH_SS_STATS:
-               for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
-                       memcpy(data + i * ETH_GSTRING_LEN,
-                               fec_stats[i].name, ETH_GSTRING_LEN);
+               for (i = 0; i < ARRAY_SIZE(fec_stats); i++) {
+                       memcpy(data, fec_stats[i].name, ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
+               for (i = 0; i < ARRAY_SIZE(fec_xdp_stat_strs); i++) {
+                       strncpy(data, fec_xdp_stat_strs[i], ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
+               page_pool_ethtool_stats_get_strings(data);
+
                break;
        case ETH_SS_TEST:
                net_selftest_get_strings(data);
@@ -2739,9 +2799,14 @@ static void fec_enet_get_strings(struct net_device *netdev,
 
 static int fec_enet_get_sset_count(struct net_device *dev, int sset)
 {
+       int count;
+
        switch (sset) {
        case ETH_SS_STATS:
-               return ARRAY_SIZE(fec_stats);
+               count = ARRAY_SIZE(fec_stats) + XDP_STATS_TOTAL;
+               count += page_pool_ethtool_stats_get_count();
+               return count;
+
        case ETH_SS_TEST:
                return net_selftest_get_count();
        default:
@@ -2752,7 +2817,8 @@ static int fec_enet_get_sset_count(struct net_device *dev, int sset)
 static void fec_enet_clear_ethtool_stats(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
-       int i;
+       struct fec_enet_priv_rx_q *rxq;
+       int i, j;
 
        /* Disable MIB statistics counters */
        writel(FEC_MIB_CTRLSTAT_DISABLE, fep->hwp + FEC_MIB_CTRLSTAT);
@@ -2760,6 +2826,12 @@ static void fec_enet_clear_ethtool_stats(struct net_device *dev)
        for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
                writel(0, fep->hwp + fec_stats[i].offset);
 
+       for (i = fep->num_rx_queues - 1; i >= 0; i--) {
+               rxq = fep->rx_queue[i];
+               for (j = 0; j < XDP_STATS_TOTAL; j++)
+                       rxq->stats[j] = 0;
+       }
+
        /* Don't disable MIB statistics counters */
        writel(0, fep->hwp + FEC_MIB_CTRLSTAT);
 }
@@ -3126,6 +3198,9 @@ static void fec_enet_free_buffers(struct net_device *ndev)
                for (i = 0; i < rxq->bd.ring_size; i++)
                        page_pool_release_page(rxq->page_pool, rxq->rx_skb_info[i].page);
 
+               for (i = 0; i < XDP_STATS_TOTAL; i++)
+                       rxq->stats[i] = 0;
+
                if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
                        xdp_rxq_info_unreg(&rxq->xdp_rxq);
                page_pool_destroy(rxq->page_pool);