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

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
...@@ -208,6 +208,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, ...@@ -208,6 +208,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
void *vaddr; void *vaddr;
struct sk_buff *skb; struct sk_buff *skb;
struct rtnl_link_stats64 *percpu_stats; struct rtnl_link_stats64 *percpu_stats;
struct dpaa2_eth_drv_stats *percpu_extras;
struct device *dev = priv->net_dev->dev.parent; struct device *dev = priv->net_dev->dev.parent;
struct dpaa2_fas *fas; struct dpaa2_fas *fas;
u32 status = 0; u32 status = 0;
...@@ -219,6 +220,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, ...@@ -219,6 +220,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
prefetch(vaddr + dpaa2_fd_get_offset(fd)); prefetch(vaddr + dpaa2_fd_get_offset(fd));
percpu_stats = this_cpu_ptr(priv->percpu_stats); percpu_stats = this_cpu_ptr(priv->percpu_stats);
percpu_extras = this_cpu_ptr(priv->percpu_extras);
if (fd_format == dpaa2_fd_single) { if (fd_format == dpaa2_fd_single) {
skb = build_linear_skb(priv, ch, fd, vaddr); skb = build_linear_skb(priv, ch, fd, vaddr);
...@@ -227,6 +229,8 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, ...@@ -227,6 +229,8 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
vaddr + dpaa2_fd_get_offset(fd); vaddr + dpaa2_fd_get_offset(fd);
skb = build_frag_skb(priv, ch, sgt); skb = build_frag_skb(priv, ch, sgt);
skb_free_frag(vaddr); skb_free_frag(vaddr);
percpu_extras->rx_sg_frames++;
percpu_extras->rx_sg_bytes += dpaa2_fd_get_len(fd);
} else { } else {
/* We don't support any other format */ /* We don't support any other format */
goto err_frame_format; goto err_frame_format;
...@@ -291,6 +295,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch) ...@@ -291,6 +295,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch)
fd = dpaa2_dq_fd(dq); fd = dpaa2_dq_fd(dq);
fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq); fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq);
fq->stats.frames++;
fq->consume(priv, ch, fd, &ch->napi); fq->consume(priv, ch, fd, &ch->napi);
cleaned++; cleaned++;
...@@ -532,11 +537,13 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) ...@@ -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_eth_priv *priv = netdev_priv(net_dev);
struct dpaa2_fd fd; struct dpaa2_fd fd;
struct rtnl_link_stats64 *percpu_stats; struct rtnl_link_stats64 *percpu_stats;
struct dpaa2_eth_drv_stats *percpu_extras;
struct dpaa2_eth_fq *fq; struct dpaa2_eth_fq *fq;
u16 queue_mapping; u16 queue_mapping;
int err, i; int err, i;
percpu_stats = this_cpu_ptr(priv->percpu_stats); 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))) { if (unlikely(skb_headroom(skb) < DPAA2_ETH_NEEDED_HEADROOM(priv))) {
struct sk_buff *ns; struct sk_buff *ns;
...@@ -563,10 +570,14 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) ...@@ -563,10 +570,14 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev)
/* Setup the FD fields */ /* Setup the FD fields */
memset(&fd, 0, sizeof(fd)); memset(&fd, 0, sizeof(fd));
if (skb_is_nonlinear(skb)) if (skb_is_nonlinear(skb)) {
err = build_sg_fd(priv, skb, &fd); 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); err = build_single_fd(priv, skb, &fd);
}
if (unlikely(err)) { if (unlikely(err)) {
percpu_stats->tx_dropped++; percpu_stats->tx_dropped++;
goto err_build_fd; goto err_build_fd;
...@@ -583,6 +594,7 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) ...@@ -583,6 +594,7 @@ static int dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev)
if (err != -EBUSY) if (err != -EBUSY)
break; break;
} }
percpu_extras->tx_portal_busy += i;
if (unlikely(err < 0)) { if (unlikely(err < 0)) {
percpu_stats->tx_errors++; percpu_stats->tx_errors++;
/* Clean up everything, including freeing the skb */ /* Clean up everything, including freeing the skb */
...@@ -608,8 +620,13 @@ static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv, ...@@ -608,8 +620,13 @@ static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv,
struct napi_struct *napi __always_unused) struct napi_struct *napi __always_unused)
{ {
struct rtnl_link_stats64 *percpu_stats; struct rtnl_link_stats64 *percpu_stats;
struct dpaa2_eth_drv_stats *percpu_extras;
u32 status = 0; 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); free_tx_fd(priv, fd, &status);
if (unlikely(status & DPAA2_ETH_TXCONF_ERR_MASK)) { if (unlikely(status & DPAA2_ETH_TXCONF_ERR_MASK)) {
...@@ -814,13 +831,19 @@ static int refill_pool(struct dpaa2_eth_priv *priv, ...@@ -814,13 +831,19 @@ static int refill_pool(struct dpaa2_eth_priv *priv,
static int pull_channel(struct dpaa2_eth_channel *ch) static int pull_channel(struct dpaa2_eth_channel *ch)
{ {
int err; int err;
int dequeues = -1;
/* Retry while portal is busy */ /* Retry while portal is busy */
do { do {
err = dpaa2_io_service_pull_channel(NULL, ch->ch_id, ch->store); err = dpaa2_io_service_pull_channel(NULL, ch->ch_id, ch->store);
dequeues++;
cpu_relax(); cpu_relax();
} while (err == -EBUSY); } while (err == -EBUSY);
ch->stats.dequeue_portal_busy += dequeues;
if (unlikely(err))
ch->stats.pull_err++;
return err; return err;
} }
...@@ -868,6 +891,8 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) ...@@ -868,6 +891,8 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget)
} while (err == -EBUSY); } while (err == -EBUSY);
} }
ch->stats.frames += cleaned;
return cleaned; return cleaned;
} }
...@@ -1320,6 +1345,10 @@ static void cdan_cb(struct dpaa2_io_notification_ctx *ctx) ...@@ -1320,6 +1345,10 @@ static void cdan_cb(struct dpaa2_io_notification_ctx *ctx)
struct dpaa2_eth_channel *ch; struct dpaa2_eth_channel *ch;
ch = container_of(ctx, struct dpaa2_eth_channel, nctx); ch = container_of(ctx, struct dpaa2_eth_channel, nctx);
/* Update NAPI statistics */
ch->stats.cdan++;
napi_schedule_irqoff(&ch->napi); napi_schedule_irqoff(&ch->napi);
} }
...@@ -2345,6 +2374,12 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) ...@@ -2345,6 +2374,12 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
err = -ENOMEM; err = -ENOMEM;
goto err_alloc_percpu_stats; 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); err = netdev_init(net_dev);
if (err) if (err)
...@@ -2387,6 +2422,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) ...@@ -2387,6 +2422,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
err_csum: err_csum:
unregister_netdev(net_dev); unregister_netdev(net_dev);
err_netdev_init: err_netdev_init:
free_percpu(priv->percpu_extras);
err_alloc_percpu_extras:
free_percpu(priv->percpu_stats); free_percpu(priv->percpu_stats);
err_alloc_percpu_stats: err_alloc_percpu_stats:
del_ch_napi(priv); del_ch_napi(priv);
...@@ -2425,6 +2462,7 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) ...@@ -2425,6 +2462,7 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
free_rings(priv); free_rings(priv);
free_percpu(priv->percpu_stats); free_percpu(priv->percpu_stats);
free_percpu(priv->percpu_extras);
del_ch_napi(priv); del_ch_napi(priv);
free_dpbp(priv); free_dpbp(priv);
......
...@@ -197,6 +197,38 @@ struct dpaa2_fas { ...@@ -197,6 +197,38 @@ struct dpaa2_fas {
*/ */
#define DPAA2_ETH_ENQUEUE_RETRIES 10 #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 */ /* Maximum number of queues associated with a DPNI */
#define DPAA2_ETH_MAX_RX_QUEUES 16 #define DPAA2_ETH_MAX_RX_QUEUES 16
#define DPAA2_ETH_MAX_TX_QUEUES NR_CPUS #define DPAA2_ETH_MAX_TX_QUEUES NR_CPUS
...@@ -224,6 +256,7 @@ struct dpaa2_eth_fq { ...@@ -224,6 +256,7 @@ struct dpaa2_eth_fq {
struct dpaa2_eth_channel *, struct dpaa2_eth_channel *,
const struct dpaa2_fd *, const struct dpaa2_fd *,
struct napi_struct *); struct napi_struct *);
struct dpaa2_eth_fq_stats stats;
}; };
struct dpaa2_eth_channel { struct dpaa2_eth_channel {
...@@ -236,6 +269,7 @@ struct dpaa2_eth_channel { ...@@ -236,6 +269,7 @@ struct dpaa2_eth_channel {
struct dpaa2_io_store *store; struct dpaa2_io_store *store;
struct dpaa2_eth_priv *priv; struct dpaa2_eth_priv *priv;
int buf_count; int buf_count;
struct dpaa2_eth_ch_stats stats;
}; };
struct dpaa2_eth_hash_fields { struct dpaa2_eth_hash_fields {
...@@ -275,6 +309,8 @@ struct dpaa2_eth_priv { ...@@ -275,6 +309,8 @@ struct dpaa2_eth_priv {
/* Standard statistics */ /* Standard statistics */
struct rtnl_link_stats64 __percpu *percpu_stats; 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; u16 mc_token;
......
...@@ -56,6 +56,23 @@ char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = { ...@@ -56,6 +56,23 @@ char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = {
#define DPAA2_ETH_NUM_STATS ARRAY_SIZE(dpaa2_ethtool_stats) #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, static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
struct ethtool_drvinfo *drvinfo) struct ethtool_drvinfo *drvinfo)
{ {
...@@ -147,6 +164,10 @@ static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, ...@@ -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); strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN);
p += 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; break;
} }
} }
...@@ -155,7 +176,7 @@ static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset) ...@@ -155,7 +176,7 @@ static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset)
{ {
switch (sset) { switch (sset) {
case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */ 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: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -171,9 +192,14 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, ...@@ -171,9 +192,14 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
int j, k, err; int j, k, err;
int num_cnt; int num_cnt;
union dpni_statistics dpni_stats; 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_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 */ /* Print standard counters, from DPNI statistics */
for (j = 0; j <= 2; j++) { for (j = 0; j <= 2; j++) {
...@@ -197,6 +223,25 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, ...@@ -197,6 +223,25 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
for (k = 0; k < num_cnt; k++) for (k = 0; k < num_cnt; k++)
*(data + i++) = dpni_stats.raw.counter[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, static int dpaa2_eth_get_rxnfc(struct net_device *net_dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment