aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMugunthan V N <mugunthanvnm@ti.com>2013-07-23 06:08:17 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-24 20:52:32 -0400
commitd97185466cc83902de49c7bea512651c7af12566 (patch)
tree61a8a4281c5d86ec6f710b86ae8da9a55be119dd
parentb07ea07bd0fa63bfb74dbd803ac3bb9e14dc630b (diff)
drivers: net: cpsw: add support to show hw stats via ethtool
Add support to show CPSW hardware statistics to user via ethtool so user can find if there were any error reported by hardware or the system is over loaded duing high data rate transfer. Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/ti/cpsw.c202
1 files changed, 200 insertions, 2 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 05a1674e204f..1cd1c00c089f 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -91,6 +91,7 @@ do { \
91#define CPSW1_SLAVE_SIZE 0x040 91#define CPSW1_SLAVE_SIZE 0x040
92#define CPSW1_CPDMA_OFFSET 0x100 92#define CPSW1_CPDMA_OFFSET 0x100
93#define CPSW1_STATERAM_OFFSET 0x200 93#define CPSW1_STATERAM_OFFSET 0x200
94#define CPSW1_HW_STATS 0x400
94#define CPSW1_CPTS_OFFSET 0x500 95#define CPSW1_CPTS_OFFSET 0x500
95#define CPSW1_ALE_OFFSET 0x600 96#define CPSW1_ALE_OFFSET 0x600
96#define CPSW1_SLIVER_OFFSET 0x700 97#define CPSW1_SLIVER_OFFSET 0x700
@@ -99,6 +100,7 @@ do { \
99#define CPSW2_SLAVE_OFFSET 0x200 100#define CPSW2_SLAVE_OFFSET 0x200
100#define CPSW2_SLAVE_SIZE 0x100 101#define CPSW2_SLAVE_SIZE 0x100
101#define CPSW2_CPDMA_OFFSET 0x800 102#define CPSW2_CPDMA_OFFSET 0x800
103#define CPSW2_HW_STATS 0x900
102#define CPSW2_STATERAM_OFFSET 0xa00 104#define CPSW2_STATERAM_OFFSET 0xa00
103#define CPSW2_CPTS_OFFSET 0xc00 105#define CPSW2_CPTS_OFFSET 0xc00
104#define CPSW2_ALE_OFFSET 0xd00 106#define CPSW2_ALE_OFFSET 0xd00
@@ -299,6 +301,44 @@ struct cpsw_sliver_regs {
299 u32 rx_pri_map; 301 u32 rx_pri_map;
300}; 302};
301 303
304struct cpsw_hw_stats {
305 u32 rxgoodframes;
306 u32 rxbroadcastframes;
307 u32 rxmulticastframes;
308 u32 rxpauseframes;
309 u32 rxcrcerrors;
310 u32 rxaligncodeerrors;
311 u32 rxoversizedframes;
312 u32 rxjabberframes;
313 u32 rxundersizedframes;
314 u32 rxfragments;
315 u32 __pad_0[2];
316 u32 rxoctets;
317 u32 txgoodframes;
318 u32 txbroadcastframes;
319 u32 txmulticastframes;
320 u32 txpauseframes;
321 u32 txdeferredframes;
322 u32 txcollisionframes;
323 u32 txsinglecollframes;
324 u32 txmultcollframes;
325 u32 txexcessivecollisions;
326 u32 txlatecollisions;
327 u32 txunderrun;
328 u32 txcarriersenseerrors;
329 u32 txoctets;
330 u32 octetframes64;
331 u32 octetframes65t127;
332 u32 octetframes128t255;
333 u32 octetframes256t511;
334 u32 octetframes512t1023;
335 u32 octetframes1024tup;
336 u32 netoctets;
337 u32 rxsofoverruns;
338 u32 rxmofoverruns;
339 u32 rxdmaoverruns;
340};
341
302struct cpsw_slave { 342struct cpsw_slave {
303 void __iomem *regs; 343 void __iomem *regs;
304 struct cpsw_sliver_regs __iomem *sliver; 344 struct cpsw_sliver_regs __iomem *sliver;
@@ -332,6 +372,7 @@ struct cpsw_priv {
332 struct cpsw_platform_data data; 372 struct cpsw_platform_data data;
333 struct cpsw_ss_regs __iomem *regs; 373 struct cpsw_ss_regs __iomem *regs;
334 struct cpsw_wr_regs __iomem *wr_regs; 374 struct cpsw_wr_regs __iomem *wr_regs;
375 u8 __iomem *hw_stats;
335 struct cpsw_host_regs __iomem *host_port_regs; 376 struct cpsw_host_regs __iomem *host_port_regs;
336 u32 msg_enable; 377 u32 msg_enable;
337 u32 version; 378 u32 version;
@@ -354,6 +395,94 @@ struct cpsw_priv {
354 u32 emac_port; 395 u32 emac_port;
355}; 396};
356 397
398struct cpsw_stats {
399 char stat_string[ETH_GSTRING_LEN];
400 int type;
401 int sizeof_stat;
402 int stat_offset;
403};
404
405enum {
406 CPSW_STATS,
407 CPDMA_RX_STATS,
408 CPDMA_TX_STATS,
409};
410
411#define CPSW_STAT(m) CPSW_STATS, \
412 sizeof(((struct cpsw_hw_stats *)0)->m), \
413 offsetof(struct cpsw_hw_stats, m)
414#define CPDMA_RX_STAT(m) CPDMA_RX_STATS, \
415 sizeof(((struct cpdma_chan_stats *)0)->m), \
416 offsetof(struct cpdma_chan_stats, m)
417#define CPDMA_TX_STAT(m) CPDMA_TX_STATS, \
418 sizeof(((struct cpdma_chan_stats *)0)->m), \
419 offsetof(struct cpdma_chan_stats, m)
420
421static const struct cpsw_stats cpsw_gstrings_stats[] = {
422 { "Good Rx Frames", CPSW_STAT(rxgoodframes) },
423 { "Broadcast Rx Frames", CPSW_STAT(rxbroadcastframes) },
424 { "Multicast Rx Frames", CPSW_STAT(rxmulticastframes) },
425 { "Pause Rx Frames", CPSW_STAT(rxpauseframes) },
426 { "Rx CRC Errors", CPSW_STAT(rxcrcerrors) },
427 { "Rx Align/Code Errors", CPSW_STAT(rxaligncodeerrors) },
428 { "Oversize Rx Frames", CPSW_STAT(rxoversizedframes) },
429 { "Rx Jabbers", CPSW_STAT(rxjabberframes) },
430 { "Undersize (Short) Rx Frames", CPSW_STAT(rxundersizedframes) },
431 { "Rx Fragments", CPSW_STAT(rxfragments) },
432 { "Rx Octets", CPSW_STAT(rxoctets) },
433 { "Good Tx Frames", CPSW_STAT(txgoodframes) },
434 { "Broadcast Tx Frames", CPSW_STAT(txbroadcastframes) },
435 { "Multicast Tx Frames", CPSW_STAT(txmulticastframes) },
436 { "Pause Tx Frames", CPSW_STAT(txpauseframes) },
437 { "Deferred Tx Frames", CPSW_STAT(txdeferredframes) },
438 { "Collisions", CPSW_STAT(txcollisionframes) },
439 { "Single Collision Tx Frames", CPSW_STAT(txsinglecollframes) },
440 { "Multiple Collision Tx Frames", CPSW_STAT(txmultcollframes) },
441 { "Excessive Collisions", CPSW_STAT(txexcessivecollisions) },
442 { "Late Collisions", CPSW_STAT(txlatecollisions) },
443 { "Tx Underrun", CPSW_STAT(txunderrun) },
444 { "Carrier Sense Errors", CPSW_STAT(txcarriersenseerrors) },
445 { "Tx Octets", CPSW_STAT(txoctets) },
446 { "Rx + Tx 64 Octet Frames", CPSW_STAT(octetframes64) },
447 { "Rx + Tx 65-127 Octet Frames", CPSW_STAT(octetframes65t127) },
448 { "Rx + Tx 128-255 Octet Frames", CPSW_STAT(octetframes128t255) },
449 { "Rx + Tx 256-511 Octet Frames", CPSW_STAT(octetframes256t511) },
450 { "Rx + Tx 512-1023 Octet Frames", CPSW_STAT(octetframes512t1023) },
451 { "Rx + Tx 1024-Up Octet Frames", CPSW_STAT(octetframes1024tup) },
452 { "Net Octets", CPSW_STAT(netoctets) },
453 { "Rx Start of Frame Overruns", CPSW_STAT(rxsofoverruns) },
454 { "Rx Middle of Frame Overruns", CPSW_STAT(rxmofoverruns) },
455 { "Rx DMA Overruns", CPSW_STAT(rxdmaoverruns) },
456 { "Rx DMA chan: head_enqueue", CPDMA_RX_STAT(head_enqueue) },
457 { "Rx DMA chan: tail_enqueue", CPDMA_RX_STAT(tail_enqueue) },
458 { "Rx DMA chan: pad_enqueue", CPDMA_RX_STAT(pad_enqueue) },
459 { "Rx DMA chan: misqueued", CPDMA_RX_STAT(misqueued) },
460 { "Rx DMA chan: desc_alloc_fail", CPDMA_RX_STAT(desc_alloc_fail) },
461 { "Rx DMA chan: pad_alloc_fail", CPDMA_RX_STAT(pad_alloc_fail) },
462 { "Rx DMA chan: runt_receive_buf", CPDMA_RX_STAT(runt_receive_buff) },
463 { "Rx DMA chan: runt_transmit_buf", CPDMA_RX_STAT(runt_transmit_buff) },
464 { "Rx DMA chan: empty_dequeue", CPDMA_RX_STAT(empty_dequeue) },
465 { "Rx DMA chan: busy_dequeue", CPDMA_RX_STAT(busy_dequeue) },
466 { "Rx DMA chan: good_dequeue", CPDMA_RX_STAT(good_dequeue) },
467 { "Rx DMA chan: requeue", CPDMA_RX_STAT(requeue) },
468 { "Rx DMA chan: teardown_dequeue", CPDMA_RX_STAT(teardown_dequeue) },
469 { "Tx DMA chan: head_enqueue", CPDMA_TX_STAT(head_enqueue) },
470 { "Tx DMA chan: tail_enqueue", CPDMA_TX_STAT(tail_enqueue) },
471 { "Tx DMA chan: pad_enqueue", CPDMA_TX_STAT(pad_enqueue) },
472 { "Tx DMA chan: misqueued", CPDMA_TX_STAT(misqueued) },
473 { "Tx DMA chan: desc_alloc_fail", CPDMA_TX_STAT(desc_alloc_fail) },
474 { "Tx DMA chan: pad_alloc_fail", CPDMA_TX_STAT(pad_alloc_fail) },
475 { "Tx DMA chan: runt_receive_buf", CPDMA_TX_STAT(runt_receive_buff) },
476 { "Tx DMA chan: runt_transmit_buf", CPDMA_TX_STAT(runt_transmit_buff) },
477 { "Tx DMA chan: empty_dequeue", CPDMA_TX_STAT(empty_dequeue) },
478 { "Tx DMA chan: busy_dequeue", CPDMA_TX_STAT(busy_dequeue) },
479 { "Tx DMA chan: good_dequeue", CPDMA_TX_STAT(good_dequeue) },
480 { "Tx DMA chan: requeue", CPDMA_TX_STAT(requeue) },
481 { "Tx DMA chan: teardown_dequeue", CPDMA_TX_STAT(teardown_dequeue) },
482};
483
484#define CPSW_STATS_LEN ARRAY_SIZE(cpsw_gstrings_stats)
485
357#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi) 486#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi)
358#define for_each_slave(priv, func, arg...) \ 487#define for_each_slave(priv, func, arg...) \
359 do { \ 488 do { \
@@ -723,6 +852,69 @@ static int cpsw_set_coalesce(struct net_device *ndev,
723 return 0; 852 return 0;
724} 853}
725 854
855static int cpsw_get_sset_count(struct net_device *ndev, int sset)
856{
857 switch (sset) {
858 case ETH_SS_STATS:
859 return CPSW_STATS_LEN;
860 default:
861 return -EOPNOTSUPP;
862 }
863}
864
865static void cpsw_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
866{
867 u8 *p = data;
868 int i;
869
870 switch (stringset) {
871 case ETH_SS_STATS:
872 for (i = 0; i < CPSW_STATS_LEN; i++) {
873 memcpy(p, cpsw_gstrings_stats[i].stat_string,
874 ETH_GSTRING_LEN);
875 p += ETH_GSTRING_LEN;
876 }
877 break;
878 }
879}
880
881static void cpsw_get_ethtool_stats(struct net_device *ndev,
882 struct ethtool_stats *stats, u64 *data)
883{
884 struct cpsw_priv *priv = netdev_priv(ndev);
885 struct cpdma_chan_stats rx_stats;
886 struct cpdma_chan_stats tx_stats;
887 u32 val;
888 u8 *p;
889 int i;
890
891 /* Collect Davinci CPDMA stats for Rx and Tx Channel */
892 cpdma_chan_get_stats(priv->rxch, &rx_stats);
893 cpdma_chan_get_stats(priv->txch, &tx_stats);
894
895 for (i = 0; i < CPSW_STATS_LEN; i++) {
896 switch (cpsw_gstrings_stats[i].type) {
897 case CPSW_STATS:
898 val = readl(priv->hw_stats +
899 cpsw_gstrings_stats[i].stat_offset);
900 data[i] = val;
901 break;
902
903 case CPDMA_RX_STATS:
904 p = (u8 *)&rx_stats +
905 cpsw_gstrings_stats[i].stat_offset;
906 data[i] = *(u32 *)p;
907 break;
908
909 case CPDMA_TX_STATS:
910 p = (u8 *)&tx_stats +
911 cpsw_gstrings_stats[i].stat_offset;
912 data[i] = *(u32 *)p;
913 break;
914 }
915 }
916}
917
726static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val) 918static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
727{ 919{
728 static char *leader = "........................................"; 920 static char *leader = "........................................";
@@ -1426,6 +1618,9 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
1426 .set_settings = cpsw_set_settings, 1618 .set_settings = cpsw_set_settings,
1427 .get_coalesce = cpsw_get_coalesce, 1619 .get_coalesce = cpsw_get_coalesce,
1428 .set_coalesce = cpsw_set_coalesce, 1620 .set_coalesce = cpsw_set_coalesce,
1621 .get_sset_count = cpsw_get_sset_count,
1622 .get_strings = cpsw_get_strings,
1623 .get_ethtool_stats = cpsw_get_ethtool_stats,
1429}; 1624};
1430 1625
1431static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, 1626static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1623,6 +1818,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
1623 priv_sl2->host_port = priv->host_port; 1818 priv_sl2->host_port = priv->host_port;
1624 priv_sl2->host_port_regs = priv->host_port_regs; 1819 priv_sl2->host_port_regs = priv->host_port_regs;
1625 priv_sl2->wr_regs = priv->wr_regs; 1820 priv_sl2->wr_regs = priv->wr_regs;
1821 priv_sl2->hw_stats = priv->hw_stats;
1626 priv_sl2->dma = priv->dma; 1822 priv_sl2->dma = priv->dma;
1627 priv_sl2->txch = priv->txch; 1823 priv_sl2->txch = priv->txch;
1628 priv_sl2->rxch = priv->rxch; 1824 priv_sl2->rxch = priv->rxch;
@@ -1780,7 +1976,8 @@ static int cpsw_probe(struct platform_device *pdev)
1780 switch (priv->version) { 1976 switch (priv->version) {
1781 case CPSW_VERSION_1: 1977 case CPSW_VERSION_1:
1782 priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET; 1978 priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
1783 priv->cpts->reg = ss_regs + CPSW1_CPTS_OFFSET; 1979 priv->cpts->reg = ss_regs + CPSW1_CPTS_OFFSET;
1980 priv->hw_stats = ss_regs + CPSW1_HW_STATS;
1784 dma_params.dmaregs = ss_regs + CPSW1_CPDMA_OFFSET; 1981 dma_params.dmaregs = ss_regs + CPSW1_CPDMA_OFFSET;
1785 dma_params.txhdp = ss_regs + CPSW1_STATERAM_OFFSET; 1982 dma_params.txhdp = ss_regs + CPSW1_STATERAM_OFFSET;
1786 ale_params.ale_regs = ss_regs + CPSW1_ALE_OFFSET; 1983 ale_params.ale_regs = ss_regs + CPSW1_ALE_OFFSET;
@@ -1791,7 +1988,8 @@ static int cpsw_probe(struct platform_device *pdev)
1791 break; 1988 break;
1792 case CPSW_VERSION_2: 1989 case CPSW_VERSION_2:
1793 priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET; 1990 priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
1794 priv->cpts->reg = ss_regs + CPSW2_CPTS_OFFSET; 1991 priv->cpts->reg = ss_regs + CPSW2_CPTS_OFFSET;
1992 priv->hw_stats = ss_regs + CPSW2_HW_STATS;
1795 dma_params.dmaregs = ss_regs + CPSW2_CPDMA_OFFSET; 1993 dma_params.dmaregs = ss_regs + CPSW2_CPDMA_OFFSET;
1796 dma_params.txhdp = ss_regs + CPSW2_STATERAM_OFFSET; 1994 dma_params.txhdp = ss_regs + CPSW2_STATERAM_OFFSET;
1797 ale_params.ale_regs = ss_regs + CPSW2_ALE_OFFSET; 1995 ale_params.ale_regs = ss_regs + CPSW2_ALE_OFFSET;