aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMadalin Bucur <madalin.bucur@nxp.com>2016-11-15 03:41:04 -0500
committerDavid S. Miller <davem@davemloft.net>2016-11-15 22:34:25 -0500
commitb0ce0d02e44d3bd92b4cb6544d8ff9c90d730d07 (patch)
tree3201cc674b211ab3c279f169783339eee851fe7e
parentb0cdb1682b2112d259dcd90b35eeaec40590e62f (diff)
dpaa_eth: add ethtool statistics
Add a series of counters to be exported through ethtool: - add detailed counters for reception errors; - add detailed counters for QMan enqueue reject events; - count the number of fragmented skbs received from the stack; - count all frames received on the Tx confirmation path; - add congestion group statistics; - count the number of interrupts for each CPU. Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com> Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.c54
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.h33
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c199
3 files changed, 284 insertions, 2 deletions
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 0e7f1c7ff37a..fcb9cac6257a 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -700,10 +700,15 @@ static void dpaa_eth_cgscn(struct qman_portal *qm, struct qman_cgr *cgr,
700 struct dpaa_priv *priv = (struct dpaa_priv *)container_of(cgr, 700 struct dpaa_priv *priv = (struct dpaa_priv *)container_of(cgr,
701 struct dpaa_priv, cgr_data.cgr); 701 struct dpaa_priv, cgr_data.cgr);
702 702
703 if (congested) 703 if (congested) {
704 priv->cgr_data.congestion_start_jiffies = jiffies;
704 netif_tx_stop_all_queues(priv->net_dev); 705 netif_tx_stop_all_queues(priv->net_dev);
705 else 706 priv->cgr_data.cgr_congested_count++;
707 } else {
708 priv->cgr_data.congested_jiffies +=
709 (jiffies - priv->cgr_data.congestion_start_jiffies);
706 netif_tx_wake_all_queues(priv->net_dev); 710 netif_tx_wake_all_queues(priv->net_dev);
711 }
707} 712}
708 713
709static int dpaa_eth_cgr_init(struct dpaa_priv *priv) 714static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
@@ -1217,6 +1222,37 @@ static void dpaa_fd_release(const struct net_device *net_dev,
1217 dpaa_bman_release(dpaa_bp, &bmb, 1); 1222 dpaa_bman_release(dpaa_bp, &bmb, 1);
1218} 1223}
1219 1224
1225static void count_ern(struct dpaa_percpu_priv *percpu_priv,
1226 const union qm_mr_entry *msg)
1227{
1228 switch (msg->ern.rc & QM_MR_RC_MASK) {
1229 case QM_MR_RC_CGR_TAILDROP:
1230 percpu_priv->ern_cnt.cg_tdrop++;
1231 break;
1232 case QM_MR_RC_WRED:
1233 percpu_priv->ern_cnt.wred++;
1234 break;
1235 case QM_MR_RC_ERROR:
1236 percpu_priv->ern_cnt.err_cond++;
1237 break;
1238 case QM_MR_RC_ORPWINDOW_EARLY:
1239 percpu_priv->ern_cnt.early_window++;
1240 break;
1241 case QM_MR_RC_ORPWINDOW_LATE:
1242 percpu_priv->ern_cnt.late_window++;
1243 break;
1244 case QM_MR_RC_FQ_TAILDROP:
1245 percpu_priv->ern_cnt.fq_tdrop++;
1246 break;
1247 case QM_MR_RC_ORPWINDOW_RETIRED:
1248 percpu_priv->ern_cnt.fq_retired++;
1249 break;
1250 case QM_MR_RC_ORP_ZERO:
1251 percpu_priv->ern_cnt.orp_zero++;
1252 break;
1253 }
1254}
1255
1220/* Turn on HW checksum computation for this outgoing frame. 1256/* Turn on HW checksum computation for this outgoing frame.
1221 * If the current protocol is not something we support in this regard 1257 * If the current protocol is not something we support in this regard
1222 * (or if the stack has already computed the SW checksum), we do nothing. 1258 * (or if the stack has already computed the SW checksum), we do nothing.
@@ -1882,6 +1918,7 @@ static int dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
1882 likely(skb_shinfo(skb)->nr_frags < DPAA_SGT_MAX_ENTRIES)) { 1918 likely(skb_shinfo(skb)->nr_frags < DPAA_SGT_MAX_ENTRIES)) {
1883 /* Just create a S/G fd based on the skb */ 1919 /* Just create a S/G fd based on the skb */
1884 err = skb_to_sg_fd(priv, skb, &fd); 1920 err = skb_to_sg_fd(priv, skb, &fd);
1921 percpu_priv->tx_frag_skbuffs++;
1885 } else { 1922 } else {
1886 /* If the egress skb contains more fragments than we support 1923 /* If the egress skb contains more fragments than we support
1887 * we have no choice but to linearize it ourselves. 1924 * we have no choice but to linearize it ourselves.
@@ -1918,6 +1955,15 @@ static void dpaa_rx_error(struct net_device *net_dev,
1918 1955
1919 percpu_priv->stats.rx_errors++; 1956 percpu_priv->stats.rx_errors++;
1920 1957
1958 if (fd->status & FM_FD_ERR_DMA)
1959 percpu_priv->rx_errors.dme++;
1960 if (fd->status & FM_FD_ERR_PHYSICAL)
1961 percpu_priv->rx_errors.fpe++;
1962 if (fd->status & FM_FD_ERR_SIZE)
1963 percpu_priv->rx_errors.fse++;
1964 if (fd->status & FM_FD_ERR_PRS_HDR_ERR)
1965 percpu_priv->rx_errors.phe++;
1966
1921 dpaa_fd_release(net_dev, fd); 1967 dpaa_fd_release(net_dev, fd);
1922} 1968}
1923 1969
@@ -1973,6 +2019,8 @@ static void dpaa_tx_conf(struct net_device *net_dev,
1973 percpu_priv->stats.tx_errors++; 2019 percpu_priv->stats.tx_errors++;
1974 } 2020 }
1975 2021
2022 percpu_priv->tx_confirm++;
2023
1976 skb = dpaa_cleanup_tx_fd(priv, fd); 2024 skb = dpaa_cleanup_tx_fd(priv, fd);
1977 2025
1978 consume_skb(skb); 2026 consume_skb(skb);
@@ -1987,6 +2035,7 @@ static inline int dpaa_eth_napi_schedule(struct dpaa_percpu_priv *percpu_priv,
1987 2035
1988 percpu_priv->np.p = portal; 2036 percpu_priv->np.p = portal;
1989 napi_schedule(&percpu_priv->np.napi); 2037 napi_schedule(&percpu_priv->np.napi);
2038 percpu_priv->in_interrupt++;
1990 return 1; 2039 return 1;
1991 } 2040 }
1992 return 0; 2041 return 0;
@@ -2171,6 +2220,7 @@ static void egress_ern(struct qman_portal *portal,
2171 2220
2172 percpu_priv->stats.tx_dropped++; 2221 percpu_priv->stats.tx_dropped++;
2173 percpu_priv->stats.tx_fifo_errors++; 2222 percpu_priv->stats.tx_fifo_errors++;
2223 count_ern(percpu_priv, msg);
2174 2224
2175 skb = dpaa_cleanup_tx_fd(priv, fd); 2225 skb = dpaa_cleanup_tx_fd(priv, fd);
2176 dev_kfree_skb_any(skb); 2226 dev_kfree_skb_any(skb);
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
index d6ab3354df86..711fb06200b7 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
@@ -95,6 +95,25 @@ struct dpaa_bp {
95 atomic_t refs; 95 atomic_t refs;
96}; 96};
97 97
98struct dpaa_rx_errors {
99 u64 dme; /* DMA Error */
100 u64 fpe; /* Frame Physical Error */
101 u64 fse; /* Frame Size Error */
102 u64 phe; /* Header Error */
103};
104
105/* Counters for QMan ERN frames - one counter per rejection code */
106struct dpaa_ern_cnt {
107 u64 cg_tdrop; /* Congestion group taildrop */
108 u64 wred; /* WRED congestion */
109 u64 err_cond; /* Error condition */
110 u64 early_window; /* Order restoration, frame too early */
111 u64 late_window; /* Order restoration, frame too late */
112 u64 fq_tdrop; /* FQ taildrop */
113 u64 fq_retired; /* FQ is retired */
114 u64 orp_zero; /* ORP disabled */
115};
116
98struct dpaa_napi_portal { 117struct dpaa_napi_portal {
99 struct napi_struct napi; 118 struct napi_struct napi;
100 struct qman_portal *p; 119 struct qman_portal *p;
@@ -104,7 +123,13 @@ struct dpaa_napi_portal {
104struct dpaa_percpu_priv { 123struct dpaa_percpu_priv {
105 struct net_device *net_dev; 124 struct net_device *net_dev;
106 struct dpaa_napi_portal np; 125 struct dpaa_napi_portal np;
126 u64 in_interrupt;
127 u64 tx_confirm;
128 /* fragmented (non-linear) skbuffs received from the stack */
129 u64 tx_frag_skbuffs;
107 struct rtnl_link_stats64 stats; 130 struct rtnl_link_stats64 stats;
131 struct dpaa_rx_errors rx_errors;
132 struct dpaa_ern_cnt ern_cnt;
108}; 133};
109 134
110struct dpaa_buffer_layout { 135struct dpaa_buffer_layout {
@@ -133,6 +158,14 @@ struct dpaa_priv {
133 * (and the same) congestion group. 158 * (and the same) congestion group.
134 */ 159 */
135 struct qman_cgr cgr; 160 struct qman_cgr cgr;
161 /* If congested, when it began. Used for performance stats. */
162 u32 congestion_start_jiffies;
163 /* Number of jiffies the Tx port was congested. */
164 u32 congested_jiffies;
165 /* Counter for the number of times the CGR
166 * entered congestion state
167 */
168 u32 cgr_congested_count;
136 } cgr_data; 169 } cgr_data;
137 /* Use a per-port CGR for ingress traffic. */ 170 /* Use a per-port CGR for ingress traffic. */
138 bool use_ingress_cgr; 171 bool use_ingress_cgr;
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
index 3580a62af369..27e7044667d1 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
@@ -36,6 +36,42 @@
36#include "dpaa_eth.h" 36#include "dpaa_eth.h"
37#include "mac.h" 37#include "mac.h"
38 38
39static const char dpaa_stats_percpu[][ETH_GSTRING_LEN] = {
40 "interrupts",
41 "rx packets",
42 "tx packets",
43 "tx confirm",
44 "tx S/G",
45 "tx error",
46 "rx error",
47};
48
49static char dpaa_stats_global[][ETH_GSTRING_LEN] = {
50 /* dpa rx errors */
51 "rx dma error",
52 "rx frame physical error",
53 "rx frame size error",
54 "rx header error",
55
56 /* demultiplexing errors */
57 "qman cg_tdrop",
58 "qman wred",
59 "qman error cond",
60 "qman early window",
61 "qman late window",
62 "qman fq tdrop",
63 "qman fq retired",
64 "qman orp disabled",
65
66 /* congestion related stats */
67 "congestion time (ms)",
68 "entered congestion",
69 "congested (0/1)"
70};
71
72#define DPAA_STATS_PERCPU_LEN ARRAY_SIZE(dpaa_stats_percpu)
73#define DPAA_STATS_GLOBAL_LEN ARRAY_SIZE(dpaa_stats_global)
74
39static int dpaa_get_settings(struct net_device *net_dev, 75static int dpaa_get_settings(struct net_device *net_dev,
40 struct ethtool_cmd *et_cmd) 76 struct ethtool_cmd *et_cmd)
41{ 77{
@@ -205,6 +241,166 @@ static int dpaa_set_pauseparam(struct net_device *net_dev,
205 return err; 241 return err;
206} 242}
207 243
244static int dpaa_get_sset_count(struct net_device *net_dev, int type)
245{
246 unsigned int total_stats, num_stats;
247
248 num_stats = num_online_cpus() + 1;
249 total_stats = num_stats * (DPAA_STATS_PERCPU_LEN + DPAA_BPS_NUM) +
250 DPAA_STATS_GLOBAL_LEN;
251
252 switch (type) {
253 case ETH_SS_STATS:
254 return total_stats;
255 default:
256 return -EOPNOTSUPP;
257 }
258}
259
260static void copy_stats(struct dpaa_percpu_priv *percpu_priv, int num_cpus,
261 int crr_cpu, u64 *bp_count, u64 *data)
262{
263 int num_values = num_cpus + 1;
264 int crr = 0, j;
265
266 /* update current CPU's stats and also add them to the total values */
267 data[crr * num_values + crr_cpu] = percpu_priv->in_interrupt;
268 data[crr++ * num_values + num_cpus] += percpu_priv->in_interrupt;
269
270 data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_packets;
271 data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_packets;
272
273 data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_packets;
274 data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_packets;
275
276 data[crr * num_values + crr_cpu] = percpu_priv->tx_confirm;
277 data[crr++ * num_values + num_cpus] += percpu_priv->tx_confirm;
278
279 data[crr * num_values + crr_cpu] = percpu_priv->tx_frag_skbuffs;
280 data[crr++ * num_values + num_cpus] += percpu_priv->tx_frag_skbuffs;
281
282 data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_errors;
283 data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_errors;
284
285 data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_errors;
286 data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_errors;
287
288 for (j = 0; j < DPAA_BPS_NUM; j++) {
289 data[crr * num_values + crr_cpu] = bp_count[j];
290 data[crr++ * num_values + num_cpus] += bp_count[j];
291 }
292}
293
294static void dpaa_get_ethtool_stats(struct net_device *net_dev,
295 struct ethtool_stats *stats, u64 *data)
296{
297 u64 bp_count[DPAA_BPS_NUM], cg_time, cg_num;
298 struct dpaa_percpu_priv *percpu_priv;
299 struct dpaa_rx_errors rx_errors;
300 unsigned int num_cpus, offset;
301 struct dpaa_ern_cnt ern_cnt;
302 struct dpaa_bp *dpaa_bp;
303 struct dpaa_priv *priv;
304 int total_stats, i, j;
305 bool cg_status;
306
307 total_stats = dpaa_get_sset_count(net_dev, ETH_SS_STATS);
308 priv = netdev_priv(net_dev);
309 num_cpus = num_online_cpus();
310
311 memset(&bp_count, 0, sizeof(bp_count));
312 memset(&rx_errors, 0, sizeof(struct dpaa_rx_errors));
313 memset(&ern_cnt, 0, sizeof(struct dpaa_ern_cnt));
314 memset(data, 0, total_stats * sizeof(u64));
315
316 for_each_online_cpu(i) {
317 percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
318 for (j = 0; j < DPAA_BPS_NUM; j++) {
319 dpaa_bp = priv->dpaa_bps[j];
320 if (!dpaa_bp->percpu_count)
321 continue;
322 bp_count[j] = *(per_cpu_ptr(dpaa_bp->percpu_count, i));
323 }
324 rx_errors.dme += percpu_priv->rx_errors.dme;
325 rx_errors.fpe += percpu_priv->rx_errors.fpe;
326 rx_errors.fse += percpu_priv->rx_errors.fse;
327 rx_errors.phe += percpu_priv->rx_errors.phe;
328
329 ern_cnt.cg_tdrop += percpu_priv->ern_cnt.cg_tdrop;
330 ern_cnt.wred += percpu_priv->ern_cnt.wred;
331 ern_cnt.err_cond += percpu_priv->ern_cnt.err_cond;
332 ern_cnt.early_window += percpu_priv->ern_cnt.early_window;
333 ern_cnt.late_window += percpu_priv->ern_cnt.late_window;
334 ern_cnt.fq_tdrop += percpu_priv->ern_cnt.fq_tdrop;
335 ern_cnt.fq_retired += percpu_priv->ern_cnt.fq_retired;
336 ern_cnt.orp_zero += percpu_priv->ern_cnt.orp_zero;
337
338 copy_stats(percpu_priv, num_cpus, i, bp_count, data);
339 }
340
341 offset = (num_cpus + 1) * (DPAA_STATS_PERCPU_LEN + DPAA_BPS_NUM);
342 memcpy(data + offset, &rx_errors, sizeof(struct dpaa_rx_errors));
343
344 offset += sizeof(struct dpaa_rx_errors) / sizeof(u64);
345 memcpy(data + offset, &ern_cnt, sizeof(struct dpaa_ern_cnt));
346
347 /* gather congestion related counters */
348 cg_num = 0;
349 cg_status = 0;
350 cg_time = jiffies_to_msecs(priv->cgr_data.congested_jiffies);
351 if (qman_query_cgr_congested(&priv->cgr_data.cgr, &cg_status) == 0) {
352 cg_num = priv->cgr_data.cgr_congested_count;
353
354 /* reset congestion stats (like QMan API does */
355 priv->cgr_data.congested_jiffies = 0;
356 priv->cgr_data.cgr_congested_count = 0;
357 }
358
359 offset += sizeof(struct dpaa_ern_cnt) / sizeof(u64);
360 data[offset++] = cg_time;
361 data[offset++] = cg_num;
362 data[offset++] = cg_status;
363}
364
365static void dpaa_get_strings(struct net_device *net_dev, u32 stringset,
366 u8 *data)
367{
368 unsigned int i, j, num_cpus, size;
369 char string_cpu[ETH_GSTRING_LEN];
370 u8 *strings;
371
372 memset(string_cpu, 0, sizeof(string_cpu));
373 strings = data;
374 num_cpus = num_online_cpus();
375 size = DPAA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN;
376
377 for (i = 0; i < DPAA_STATS_PERCPU_LEN; i++) {
378 for (j = 0; j < num_cpus; j++) {
379 snprintf(string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]",
380 dpaa_stats_percpu[i], j);
381 memcpy(strings, string_cpu, ETH_GSTRING_LEN);
382 strings += ETH_GSTRING_LEN;
383 }
384 snprintf(string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]",
385 dpaa_stats_percpu[i]);
386 memcpy(strings, string_cpu, ETH_GSTRING_LEN);
387 strings += ETH_GSTRING_LEN;
388 }
389 for (i = 0; i < DPAA_BPS_NUM; i++) {
390 for (j = 0; j < num_cpus; j++) {
391 snprintf(string_cpu, ETH_GSTRING_LEN,
392 "bpool %c [CPU %d]", 'a' + i, j);
393 memcpy(strings, string_cpu, ETH_GSTRING_LEN);
394 strings += ETH_GSTRING_LEN;
395 }
396 snprintf(string_cpu, ETH_GSTRING_LEN, "bpool %c [TOTAL]",
397 'a' + i);
398 memcpy(strings, string_cpu, ETH_GSTRING_LEN);
399 strings += ETH_GSTRING_LEN;
400 }
401 memcpy(strings, dpaa_stats_global, size);
402}
403
208const struct ethtool_ops dpaa_ethtool_ops = { 404const struct ethtool_ops dpaa_ethtool_ops = {
209 .get_settings = dpaa_get_settings, 405 .get_settings = dpaa_get_settings,
210 .set_settings = dpaa_set_settings, 406 .set_settings = dpaa_set_settings,
@@ -215,4 +411,7 @@ const struct ethtool_ops dpaa_ethtool_ops = {
215 .get_pauseparam = dpaa_get_pauseparam, 411 .get_pauseparam = dpaa_get_pauseparam,
216 .set_pauseparam = dpaa_set_pauseparam, 412 .set_pauseparam = dpaa_set_pauseparam,
217 .get_link = ethtool_op_get_link, 413 .get_link = ethtool_op_get_link,
414 .get_sset_count = dpaa_get_sset_count,
415 .get_ethtool_stats = dpaa_get_ethtool_stats,
416 .get_strings = dpaa_get_strings,
218}; 417};