diff options
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 202 |
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 | ||
304 | struct 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 | |||
302 | struct cpsw_slave { | 342 | struct 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 | ||
398 | struct cpsw_stats { | ||
399 | char stat_string[ETH_GSTRING_LEN]; | ||
400 | int type; | ||
401 | int sizeof_stat; | ||
402 | int stat_offset; | ||
403 | }; | ||
404 | |||
405 | enum { | ||
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 | |||
421 | static 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 | ||
855 | static 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 | |||
865 | static 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 | |||
881 | static 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 | |||
726 | static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val) | 918 | static 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 | ||
1431 | static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, | 1626 | static 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; |