aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;