Commit 6970ef27 authored by Shenwei Wang's avatar Shenwei Wang Committed by David S. Miller
Browse files

net: fec: add xdp and page pool statistics



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: default avatarShenwei Wang <shenwei.wang@nxp.com>
Reported-by: default avatarkernel test robot <lkp@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4d1bbdf5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+14 −0
Original line number Diff line number Diff line
@@ -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;
+80 −5
Original line number Diff line number Diff line
@@ -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);