Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85047abd authored by Ioana Radulescu's avatar Ioana Radulescu Committed by Greg Kroah-Hartman
Browse files

staging: fsl-dpaa2/eth: Add driver specific stats



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: default avatarIoana Radulescu <ruxandra.radulescu@nxp.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 34196740
Loading
Loading
Loading
Loading
+40 −2
Original line number Diff line number Diff line
@@ -208,6 +208,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;
@@ -219,6 +220,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);
@@ -227,6 +229,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;
@@ -291,6 +295,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++;
@@ -532,11 +537,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;
@@ -563,10 +570,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;
@@ -583,6 +594,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 */
@@ -608,8 +620,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)) {
@@ -814,13 +831,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;
}

@@ -868,6 +891,8 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget)
		} while (err == -EBUSY);
	}

	ch->stats.frames += cleaned;

	return cleaned;
}

@@ -1320,6 +1345,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);
}

@@ -2345,6 +2374,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)
@@ -2387,6 +2422,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);
@@ -2425,6 +2462,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);
+36 −0
Original line number Diff line number Diff line
@@ -197,6 +197,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
@@ -224,6 +256,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 {
@@ -236,6 +269,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 {
@@ -275,6 +309,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;

+47 −2
Original line number Diff line number Diff line
@@ -56,6 +56,23 @@ char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = {

#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)
{
@@ -147,6 +164,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;
	}
}
@@ -155,7 +176,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;
	}
@@ -171,9 +192,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++) {
@@ -197,6 +223,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,