]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: lan966x: add ethtool configuration and statistics
authorHoratiu Vultur <horatiu.vultur@microchip.com>
Mon, 29 Nov 2021 12:43:58 +0000 (13:43 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 29 Nov 2021 12:58:38 +0000 (12:58 +0000)
This patch adds support for statistics counters for the network
interfaces. Also adds support for configuring the network interface via
ethtool like: speed, duplex etc.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/microchip/lan966x/Makefile
drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c [new file with mode: 0644]
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.h

index 75556387df085c7a6fd6ce8474521b7019cdb966..2989ba528236aa085732aa7f9377fdc6466d8bed 100644 (file)
@@ -6,4 +6,4 @@
 obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
 
 lan966x-switch-objs  := lan966x_main.o lan966x_phylink.o lan966x_port.o \
-                       lan966x_mac.o
+                       lan966x_mac.o lan966x_ethtool.o
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c
new file mode 100644 (file)
index 0000000..614f12c
--- /dev/null
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/netdevice.h>
+
+#include "lan966x_main.h"
+
+/* Number of traffic classes */
+#define LAN966X_NUM_TC                 8
+#define LAN966X_STATS_CHECK_DELAY      (2 * HZ)
+
+static const struct lan966x_stat_layout lan966x_stats_layout[] = {
+       { .name = "rx_octets", .offset = 0x00, },
+       { .name = "rx_unicast", .offset = 0x01, },
+       { .name = "rx_multicast", .offset = 0x02 },
+       { .name = "rx_broadcast", .offset = 0x03 },
+       { .name = "rx_short", .offset = 0x04 },
+       { .name = "rx_frag", .offset = 0x05 },
+       { .name = "rx_jabber", .offset = 0x06 },
+       { .name = "rx_crc", .offset = 0x07 },
+       { .name = "rx_symbol_err", .offset = 0x08 },
+       { .name = "rx_sz_64", .offset = 0x09 },
+       { .name = "rx_sz_65_127", .offset = 0x0a},
+       { .name = "rx_sz_128_255", .offset = 0x0b},
+       { .name = "rx_sz_256_511", .offset = 0x0c },
+       { .name = "rx_sz_512_1023", .offset = 0x0d },
+       { .name = "rx_sz_1024_1526", .offset = 0x0e },
+       { .name = "rx_sz_jumbo", .offset = 0x0f },
+       { .name = "rx_pause", .offset = 0x10 },
+       { .name = "rx_control", .offset = 0x11 },
+       { .name = "rx_long", .offset = 0x12 },
+       { .name = "rx_cat_drop", .offset = 0x13 },
+       { .name = "rx_red_prio_0", .offset = 0x14 },
+       { .name = "rx_red_prio_1", .offset = 0x15 },
+       { .name = "rx_red_prio_2", .offset = 0x16 },
+       { .name = "rx_red_prio_3", .offset = 0x17 },
+       { .name = "rx_red_prio_4", .offset = 0x18 },
+       { .name = "rx_red_prio_5", .offset = 0x19 },
+       { .name = "rx_red_prio_6", .offset = 0x1a },
+       { .name = "rx_red_prio_7", .offset = 0x1b },
+       { .name = "rx_yellow_prio_0", .offset = 0x1c },
+       { .name = "rx_yellow_prio_1", .offset = 0x1d },
+       { .name = "rx_yellow_prio_2", .offset = 0x1e },
+       { .name = "rx_yellow_prio_3", .offset = 0x1f },
+       { .name = "rx_yellow_prio_4", .offset = 0x20 },
+       { .name = "rx_yellow_prio_5", .offset = 0x21 },
+       { .name = "rx_yellow_prio_6", .offset = 0x22 },
+       { .name = "rx_yellow_prio_7", .offset = 0x23 },
+       { .name = "rx_green_prio_0", .offset = 0x24 },
+       { .name = "rx_green_prio_1", .offset = 0x25 },
+       { .name = "rx_green_prio_2", .offset = 0x26 },
+       { .name = "rx_green_prio_3", .offset = 0x27 },
+       { .name = "rx_green_prio_4", .offset = 0x28 },
+       { .name = "rx_green_prio_5", .offset = 0x29 },
+       { .name = "rx_green_prio_6", .offset = 0x2a },
+       { .name = "rx_green_prio_7", .offset = 0x2b },
+       { .name = "rx_assembly_err", .offset = 0x2c },
+       { .name = "rx_smd_err", .offset = 0x2d },
+       { .name = "rx_assembly_ok", .offset = 0x2e },
+       { .name = "rx_merge_frag", .offset = 0x2f },
+       { .name = "rx_pmac_octets", .offset = 0x30, },
+       { .name = "rx_pmac_unicast", .offset = 0x31, },
+       { .name = "rx_pmac_multicast", .offset = 0x32 },
+       { .name = "rx_pmac_broadcast", .offset = 0x33 },
+       { .name = "rx_pmac_short", .offset = 0x34 },
+       { .name = "rx_pmac_frag", .offset = 0x35 },
+       { .name = "rx_pmac_jabber", .offset = 0x36 },
+       { .name = "rx_pmac_crc", .offset = 0x37 },
+       { .name = "rx_pmac_symbol_err", .offset = 0x38 },
+       { .name = "rx_pmac_sz_64", .offset = 0x39 },
+       { .name = "rx_pmac_sz_65_127", .offset = 0x3a },
+       { .name = "rx_pmac_sz_128_255", .offset = 0x3b },
+       { .name = "rx_pmac_sz_256_511", .offset = 0x3c },
+       { .name = "rx_pmac_sz_512_1023", .offset = 0x3d },
+       { .name = "rx_pmac_sz_1024_1526", .offset = 0x3e },
+       { .name = "rx_pmac_sz_jumbo", .offset = 0x3f },
+       { .name = "rx_pmac_pause", .offset = 0x40 },
+       { .name = "rx_pmac_control", .offset = 0x41 },
+       { .name = "rx_pmac_long", .offset = 0x42 },
+
+       { .name = "tx_octets", .offset = 0x80, },
+       { .name = "tx_unicast", .offset = 0x81, },
+       { .name = "tx_multicast", .offset = 0x82 },
+       { .name = "tx_broadcast", .offset = 0x83 },
+       { .name = "tx_col", .offset = 0x84 },
+       { .name = "tx_drop", .offset = 0x85 },
+       { .name = "tx_pause", .offset = 0x86 },
+       { .name = "tx_sz_64", .offset = 0x87 },
+       { .name = "tx_sz_65_127", .offset = 0x88 },
+       { .name = "tx_sz_128_255", .offset = 0x89 },
+       { .name = "tx_sz_256_511", .offset = 0x8a },
+       { .name = "tx_sz_512_1023", .offset = 0x8b },
+       { .name = "tx_sz_1024_1526", .offset = 0x8c },
+       { .name = "tx_sz_jumbo", .offset = 0x8d },
+       { .name = "tx_yellow_prio_0", .offset = 0x8e },
+       { .name = "tx_yellow_prio_1", .offset = 0x8f },
+       { .name = "tx_yellow_prio_2", .offset = 0x90 },
+       { .name = "tx_yellow_prio_3", .offset = 0x91 },
+       { .name = "tx_yellow_prio_4", .offset = 0x92 },
+       { .name = "tx_yellow_prio_5", .offset = 0x93 },
+       { .name = "tx_yellow_prio_6", .offset = 0x94 },
+       { .name = "tx_yellow_prio_7", .offset = 0x95 },
+       { .name = "tx_green_prio_0", .offset = 0x96 },
+       { .name = "tx_green_prio_1", .offset = 0x97 },
+       { .name = "tx_green_prio_2", .offset = 0x98 },
+       { .name = "tx_green_prio_3", .offset = 0x99 },
+       { .name = "tx_green_prio_4", .offset = 0x9a },
+       { .name = "tx_green_prio_5", .offset = 0x9b },
+       { .name = "tx_green_prio_6", .offset = 0x9c },
+       { .name = "tx_green_prio_7", .offset = 0x9d },
+       { .name = "tx_aged", .offset = 0x9e },
+       { .name = "tx_llct", .offset = 0x9f },
+       { .name = "tx_ct", .offset = 0xa0 },
+       { .name = "tx_mm_hold", .offset = 0xa1 },
+       { .name = "tx_merge_frag", .offset = 0xa2 },
+       { .name = "tx_pmac_octets", .offset = 0xa3, },
+       { .name = "tx_pmac_unicast", .offset = 0xa4, },
+       { .name = "tx_pmac_multicast", .offset = 0xa5 },
+       { .name = "tx_pmac_broadcast", .offset = 0xa6 },
+       { .name = "tx_pmac_pause", .offset = 0xa7 },
+       { .name = "tx_pmac_sz_64", .offset = 0xa8 },
+       { .name = "tx_pmac_sz_65_127", .offset = 0xa9 },
+       { .name = "tx_pmac_sz_128_255", .offset = 0xaa },
+       { .name = "tx_pmac_sz_256_511", .offset = 0xab },
+       { .name = "tx_pmac_sz_512_1023", .offset = 0xac },
+       { .name = "tx_pmac_sz_1024_1526", .offset = 0xad },
+       { .name = "tx_pmac_sz_jumbo", .offset = 0xae },
+
+       { .name = "dr_local", .offset = 0x100 },
+       { .name = "dr_tail", .offset = 0x101 },
+       { .name = "dr_yellow_prio_0", .offset = 0x102 },
+       { .name = "dr_yellow_prio_1", .offset = 0x103 },
+       { .name = "dr_yellow_prio_2", .offset = 0x104 },
+       { .name = "dr_yellow_prio_3", .offset = 0x105 },
+       { .name = "dr_yellow_prio_4", .offset = 0x106 },
+       { .name = "dr_yellow_prio_5", .offset = 0x107 },
+       { .name = "dr_yellow_prio_6", .offset = 0x108 },
+       { .name = "dr_yellow_prio_7", .offset = 0x109 },
+       { .name = "dr_green_prio_0", .offset = 0x10a },
+       { .name = "dr_green_prio_1", .offset = 0x10b },
+       { .name = "dr_green_prio_2", .offset = 0x10c },
+       { .name = "dr_green_prio_3", .offset = 0x10d },
+       { .name = "dr_green_prio_4", .offset = 0x10e },
+       { .name = "dr_green_prio_5", .offset = 0x10f },
+       { .name = "dr_green_prio_6", .offset = 0x110 },
+       { .name = "dr_green_prio_7", .offset = 0x111 },
+};
+
+/* The following numbers are indexes into lan966x_stats_layout[] */
+#define SYS_COUNT_RX_OCT                 0
+#define SYS_COUNT_RX_UC                          1
+#define SYS_COUNT_RX_MC                          2
+#define SYS_COUNT_RX_BC                          3
+#define SYS_COUNT_RX_SHORT               4
+#define SYS_COUNT_RX_FRAG                5
+#define SYS_COUNT_RX_JABBER              6
+#define SYS_COUNT_RX_CRC                 7
+#define SYS_COUNT_RX_SYMBOL_ERR                  8
+#define SYS_COUNT_RX_SZ_64               9
+#define SYS_COUNT_RX_SZ_65_127          10
+#define SYS_COUNT_RX_SZ_128_255                 11
+#define SYS_COUNT_RX_SZ_256_511                 12
+#define SYS_COUNT_RX_SZ_512_1023        13
+#define SYS_COUNT_RX_SZ_1024_1526       14
+#define SYS_COUNT_RX_SZ_JUMBO           15
+#define SYS_COUNT_RX_PAUSE              16
+#define SYS_COUNT_RX_CONTROL            17
+#define SYS_COUNT_RX_LONG               18
+#define SYS_COUNT_RX_CAT_DROP           19
+#define SYS_COUNT_RX_RED_PRIO_0                 20
+#define SYS_COUNT_RX_RED_PRIO_1                 21
+#define SYS_COUNT_RX_RED_PRIO_2                 22
+#define SYS_COUNT_RX_RED_PRIO_3                 23
+#define SYS_COUNT_RX_RED_PRIO_4                 24
+#define SYS_COUNT_RX_RED_PRIO_5                 25
+#define SYS_COUNT_RX_RED_PRIO_6                 26
+#define SYS_COUNT_RX_RED_PRIO_7                 27
+#define SYS_COUNT_RX_YELLOW_PRIO_0      28
+#define SYS_COUNT_RX_YELLOW_PRIO_1      29
+#define SYS_COUNT_RX_YELLOW_PRIO_2      30
+#define SYS_COUNT_RX_YELLOW_PRIO_3      31
+#define SYS_COUNT_RX_YELLOW_PRIO_4      32
+#define SYS_COUNT_RX_YELLOW_PRIO_5      33
+#define SYS_COUNT_RX_YELLOW_PRIO_6      34
+#define SYS_COUNT_RX_YELLOW_PRIO_7      35
+#define SYS_COUNT_RX_GREEN_PRIO_0       36
+#define SYS_COUNT_RX_GREEN_PRIO_1       37
+#define SYS_COUNT_RX_GREEN_PRIO_2       38
+#define SYS_COUNT_RX_GREEN_PRIO_3       39
+#define SYS_COUNT_RX_GREEN_PRIO_4       40
+#define SYS_COUNT_RX_GREEN_PRIO_5       41
+#define SYS_COUNT_RX_GREEN_PRIO_6       42
+#define SYS_COUNT_RX_GREEN_PRIO_7       43
+#define SYS_COUNT_RX_ASSEMBLY_ERR       44
+#define SYS_COUNT_RX_SMD_ERR            45
+#define SYS_COUNT_RX_ASSEMBLY_OK        46
+#define SYS_COUNT_RX_MERGE_FRAG                 47
+#define SYS_COUNT_RX_PMAC_OCT           48
+#define SYS_COUNT_RX_PMAC_UC            49
+#define SYS_COUNT_RX_PMAC_MC            50
+#define SYS_COUNT_RX_PMAC_BC            51
+#define SYS_COUNT_RX_PMAC_SHORT                 52
+#define SYS_COUNT_RX_PMAC_FRAG          53
+#define SYS_COUNT_RX_PMAC_JABBER        54
+#define SYS_COUNT_RX_PMAC_CRC           55
+#define SYS_COUNT_RX_PMAC_SYMBOL_ERR    56
+#define SYS_COUNT_RX_PMAC_SZ_64                 57
+#define SYS_COUNT_RX_PMAC_SZ_65_127     58
+#define SYS_COUNT_RX_PMAC_SZ_128_255    59
+#define SYS_COUNT_RX_PMAC_SZ_256_511    60
+#define SYS_COUNT_RX_PMAC_SZ_512_1023   61
+#define SYS_COUNT_RX_PMAC_SZ_1024_1526  62
+#define SYS_COUNT_RX_PMAC_SZ_JUMBO      63
+#define SYS_COUNT_RX_PMAC_PAUSE                 64
+#define SYS_COUNT_RX_PMAC_CONTROL       65
+#define SYS_COUNT_RX_PMAC_LONG          66
+
+#define SYS_COUNT_TX_OCT                67
+#define SYS_COUNT_TX_UC                         68
+#define SYS_COUNT_TX_MC                         69
+#define SYS_COUNT_TX_BC                         70
+#define SYS_COUNT_TX_COL                71
+#define SYS_COUNT_TX_DROP               72
+#define SYS_COUNT_TX_PAUSE              73
+#define SYS_COUNT_TX_SZ_64              74
+#define SYS_COUNT_TX_SZ_65_127          75
+#define SYS_COUNT_TX_SZ_128_255                 76
+#define SYS_COUNT_TX_SZ_256_511                 77
+#define SYS_COUNT_TX_SZ_512_1023        78
+#define SYS_COUNT_TX_SZ_1024_1526       79
+#define SYS_COUNT_TX_SZ_JUMBO           80
+#define SYS_COUNT_TX_YELLOW_PRIO_0      81
+#define SYS_COUNT_TX_YELLOW_PRIO_1      82
+#define SYS_COUNT_TX_YELLOW_PRIO_2      83
+#define SYS_COUNT_TX_YELLOW_PRIO_3      84
+#define SYS_COUNT_TX_YELLOW_PRIO_4      85
+#define SYS_COUNT_TX_YELLOW_PRIO_5      86
+#define SYS_COUNT_TX_YELLOW_PRIO_6      87
+#define SYS_COUNT_TX_YELLOW_PRIO_7      88
+#define SYS_COUNT_TX_GREEN_PRIO_0       89
+#define SYS_COUNT_TX_GREEN_PRIO_1       90
+#define SYS_COUNT_TX_GREEN_PRIO_2       91
+#define SYS_COUNT_TX_GREEN_PRIO_3       92
+#define SYS_COUNT_TX_GREEN_PRIO_4       93
+#define SYS_COUNT_TX_GREEN_PRIO_5       94
+#define SYS_COUNT_TX_GREEN_PRIO_6       95
+#define SYS_COUNT_TX_GREEN_PRIO_7       96
+#define SYS_COUNT_TX_AGED               97
+#define SYS_COUNT_TX_LLCT               98
+#define SYS_COUNT_TX_CT                         99
+#define SYS_COUNT_TX_MM_HOLD           100
+#define SYS_COUNT_TX_MERGE_FRAG                101
+#define SYS_COUNT_TX_PMAC_OCT          102
+#define SYS_COUNT_TX_PMAC_UC           103
+#define SYS_COUNT_TX_PMAC_MC           104
+#define SYS_COUNT_TX_PMAC_BC           105
+#define SYS_COUNT_TX_PMAC_PAUSE                106
+#define SYS_COUNT_TX_PMAC_SZ_64                107
+#define SYS_COUNT_TX_PMAC_SZ_65_127    108
+#define SYS_COUNT_TX_PMAC_SZ_128_255   109
+#define SYS_COUNT_TX_PMAC_SZ_256_511   110
+#define SYS_COUNT_TX_PMAC_SZ_512_1023  111
+#define SYS_COUNT_TX_PMAC_SZ_1024_1526 112
+#define SYS_COUNT_TX_PMAC_SZ_JUMBO     113
+
+#define SYS_COUNT_DR_LOCAL             114
+#define SYS_COUNT_DR_TAIL              115
+#define SYS_COUNT_DR_YELLOW_PRIO_0     116
+#define SYS_COUNT_DR_YELLOW_PRIO_1     117
+#define SYS_COUNT_DR_YELLOW_PRIO_2     118
+#define SYS_COUNT_DR_YELLOW_PRIO_3     119
+#define SYS_COUNT_DR_YELLOW_PRIO_4     120
+#define SYS_COUNT_DR_YELLOW_PRIO_5     121
+#define SYS_COUNT_DR_YELLOW_PRIO_6     122
+#define SYS_COUNT_DR_YELLOW_PRIO_7     123
+#define SYS_COUNT_DR_GREEN_PRIO_0      124
+#define SYS_COUNT_DR_GREEN_PRIO_1      125
+#define SYS_COUNT_DR_GREEN_PRIO_2      126
+#define SYS_COUNT_DR_GREEN_PRIO_3      127
+#define SYS_COUNT_DR_GREEN_PRIO_4      128
+#define SYS_COUNT_DR_GREEN_PRIO_5      129
+#define SYS_COUNT_DR_GREEN_PRIO_6      130
+#define SYS_COUNT_DR_GREEN_PRIO_7      131
+
+/* Add a possibly wrapping 32 bit value to a 64 bit counter */
+static void lan966x_add_cnt(u64 *cnt, u32 val)
+{
+       if (val < (*cnt & U32_MAX))
+               *cnt += (u64)1 << 32; /* value has wrapped */
+
+       *cnt = (*cnt & ~(u64)U32_MAX) + val;
+}
+
+static void lan966x_stats_update(struct lan966x *lan966x)
+{
+       int i, j;
+
+       mutex_lock(&lan966x->stats_lock);
+
+       for (i = 0; i < lan966x->num_phys_ports; i++) {
+               uint idx = i * lan966x->num_stats;
+
+               lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(i),
+                      lan966x, SYS_STAT_CFG);
+
+               for (j = 0; j < lan966x->num_stats; j++) {
+                       u32 offset = lan966x->stats_layout[j].offset;
+
+                       lan966x_add_cnt(&lan966x->stats[idx++],
+                                       lan_rd(lan966x, SYS_CNT(offset)));
+               }
+       }
+
+       mutex_unlock(&lan966x->stats_lock);
+}
+
+static int lan966x_get_sset_count(struct net_device *dev, int sset)
+{
+       struct lan966x_port *port = netdev_priv(dev);
+       struct lan966x *lan966x = port->lan966x;
+
+       if (sset != ETH_SS_STATS)
+               return -EOPNOTSUPP;
+
+       return lan966x->num_stats;
+}
+
+static void lan966x_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+{
+       struct lan966x_port *port = netdev_priv(netdev);
+       struct lan966x *lan966x = port->lan966x;
+       int i;
+
+       if (sset != ETH_SS_STATS)
+               return;
+
+       for (i = 0; i < lan966x->num_stats; i++)
+               memcpy(data + i * ETH_GSTRING_LEN,
+                      lan966x->stats_layout[i].name, ETH_GSTRING_LEN);
+}
+
+static void lan966x_get_ethtool_stats(struct net_device *dev,
+                                     struct ethtool_stats *stats, u64 *data)
+{
+       struct lan966x_port *port = netdev_priv(dev);
+       struct lan966x *lan966x = port->lan966x;
+       int i;
+
+       /* check and update now */
+       lan966x_stats_update(lan966x);
+
+       /* Copy all counters */
+       for (i = 0; i < lan966x->num_stats; i++)
+               *data++ = lan966x->stats[port->chip_port *
+                                        lan966x->num_stats + i];
+}
+
+static void lan966x_get_eth_mac_stats(struct net_device *dev,
+                                     struct ethtool_eth_mac_stats *mac_stats)
+{
+       struct lan966x_port *port = netdev_priv(dev);
+       struct lan966x *lan966x = port->lan966x;
+       u32 idx;
+
+       lan966x_stats_update(lan966x);
+
+       idx = port->chip_port * lan966x->num_stats;
+
+       mutex_lock(&lan966x->stats_lock);
+
+       mac_stats->FramesTransmittedOK =
+               lan966x->stats[idx + SYS_COUNT_TX_UC] +
+               lan966x->stats[idx + SYS_COUNT_TX_MC] +
+               lan966x->stats[idx + SYS_COUNT_TX_BC] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_UC] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
+       mac_stats->SingleCollisionFrames =
+               lan966x->stats[idx + SYS_COUNT_TX_COL];
+       mac_stats->MultipleCollisionFrames = 0;
+       mac_stats->FramesReceivedOK =
+               lan966x->stats[idx + SYS_COUNT_RX_UC] +
+               lan966x->stats[idx + SYS_COUNT_RX_MC] +
+               lan966x->stats[idx + SYS_COUNT_RX_BC];
+       mac_stats->FrameCheckSequenceErrors =
+               lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+               lan966x->stats[idx + SYS_COUNT_RX_CRC];
+       mac_stats->AlignmentErrors = 0;
+       mac_stats->OctetsTransmittedOK =
+               lan966x->stats[idx + SYS_COUNT_TX_OCT] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
+       mac_stats->FramesWithDeferredXmissions =
+               lan966x->stats[idx + SYS_COUNT_TX_MM_HOLD];
+       mac_stats->LateCollisions = 0;
+       mac_stats->FramesAbortedDueToXSColls = 0;
+       mac_stats->FramesLostDueToIntMACXmitError = 0;
+       mac_stats->CarrierSenseErrors = 0;
+       mac_stats->OctetsReceivedOK =
+               lan966x->stats[idx + SYS_COUNT_RX_OCT];
+       mac_stats->FramesLostDueToIntMACRcvError = 0;
+       mac_stats->MulticastFramesXmittedOK =
+               lan966x->stats[idx + SYS_COUNT_TX_MC] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC];
+       mac_stats->BroadcastFramesXmittedOK =
+               lan966x->stats[idx + SYS_COUNT_TX_BC] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC];
+       mac_stats->FramesWithExcessiveDeferral = 0;
+       mac_stats->MulticastFramesReceivedOK =
+               lan966x->stats[idx + SYS_COUNT_RX_MC];
+       mac_stats->BroadcastFramesReceivedOK =
+               lan966x->stats[idx + SYS_COUNT_RX_BC];
+       mac_stats->InRangeLengthErrors =
+               lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
+               lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
+               lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_CRC];
+       mac_stats->OutOfRangeLengthField =
+               lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
+               lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
+       mac_stats->FrameTooLongErrors =
+               lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
+
+       mutex_unlock(&lan966x->stats_lock);
+}
+
+static const struct ethtool_rmon_hist_range lan966x_rmon_ranges[] = {
+       {    0,    64 },
+       {   65,   127 },
+       {  128,   255 },
+       {  256,   511 },
+       {  512,  1023 },
+       { 1024,  1518 },
+       { 1519, 10239 },
+       {}
+};
+
+static void lan966x_get_eth_rmon_stats(struct net_device *dev,
+                                      struct ethtool_rmon_stats *rmon_stats,
+                                      const struct ethtool_rmon_hist_range **ranges)
+{
+       struct lan966x_port *port = netdev_priv(dev);
+       struct lan966x *lan966x = port->lan966x;
+       u32 idx;
+
+       lan966x_stats_update(lan966x);
+
+       idx = port->chip_port * lan966x->num_stats;
+
+       mutex_lock(&lan966x->stats_lock);
+
+       rmon_stats->undersize_pkts =
+               lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT];
+       rmon_stats->oversize_pkts =
+               lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG];
+       rmon_stats->fragments =
+               lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG];
+       rmon_stats->jabbers =
+               lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER];
+       rmon_stats->hist[0] =
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_64] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64];
+       rmon_stats->hist[1] =
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127];
+       rmon_stats->hist[2] =
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255];
+       rmon_stats->hist[3] =
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511];
+       rmon_stats->hist[4] =
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023];
+       rmon_stats->hist[5] =
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];
+       rmon_stats->hist[6] =
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];
+
+       rmon_stats->hist_tx[0] =
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_64] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64];
+       rmon_stats->hist_tx[1] =
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127];
+       rmon_stats->hist_tx[2] =
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255];
+       rmon_stats->hist_tx[3] =
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511];
+       rmon_stats->hist_tx[4] =
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023];
+       rmon_stats->hist_tx[5] =
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];
+       rmon_stats->hist_tx[6] =
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];
+
+       mutex_unlock(&lan966x->stats_lock);
+
+       *ranges = lan966x_rmon_ranges;
+}
+
+static int lan966x_get_link_ksettings(struct net_device *ndev,
+                                     struct ethtool_link_ksettings *cmd)
+{
+       struct lan966x_port *port = netdev_priv(ndev);
+
+       return phylink_ethtool_ksettings_get(port->phylink, cmd);
+}
+
+static int lan966x_set_link_ksettings(struct net_device *ndev,
+                                     const struct ethtool_link_ksettings *cmd)
+{
+       struct lan966x_port *port = netdev_priv(ndev);
+
+       return phylink_ethtool_ksettings_set(port->phylink, cmd);
+}
+
+static void lan966x_get_pauseparam(struct net_device *dev,
+                                  struct ethtool_pauseparam *pause)
+{
+       struct lan966x_port *port = netdev_priv(dev);
+
+       phylink_ethtool_get_pauseparam(port->phylink, pause);
+}
+
+static int lan966x_set_pauseparam(struct net_device *dev,
+                                 struct ethtool_pauseparam *pause)
+{
+       struct lan966x_port *port = netdev_priv(dev);
+
+       return phylink_ethtool_set_pauseparam(port->phylink, pause);
+}
+
+const struct ethtool_ops lan966x_ethtool_ops = {
+       .get_link_ksettings     = lan966x_get_link_ksettings,
+       .set_link_ksettings     = lan966x_set_link_ksettings,
+       .get_pauseparam         = lan966x_get_pauseparam,
+       .set_pauseparam         = lan966x_set_pauseparam,
+       .get_sset_count         = lan966x_get_sset_count,
+       .get_strings            = lan966x_get_strings,
+       .get_ethtool_stats      = lan966x_get_ethtool_stats,
+       .get_eth_mac_stats      = lan966x_get_eth_mac_stats,
+       .get_rmon_stats         = lan966x_get_eth_rmon_stats,
+       .get_link               = ethtool_op_get_link,
+};
+
+static void lan966x_check_stats_work(struct work_struct *work)
+{
+       struct delayed_work *del_work = to_delayed_work(work);
+       struct lan966x *lan966x = container_of(del_work, struct lan966x,
+                                              stats_work);
+
+       lan966x_stats_update(lan966x);
+
+       queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work,
+                          LAN966X_STATS_CHECK_DELAY);
+}
+
+void lan966x_stats_get(struct net_device *dev,
+                      struct rtnl_link_stats64 *stats)
+{
+       struct lan966x_port *port = netdev_priv(dev);
+       struct lan966x *lan966x = port->lan966x;
+       u32 idx;
+       int i;
+
+       idx = port->chip_port * lan966x->num_stats;
+
+       mutex_lock(&lan966x->stats_lock);
+
+       stats->rx_bytes = lan966x->stats[idx + SYS_COUNT_RX_OCT] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_OCT];
+
+       stats->rx_packets = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
+               lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
+               lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
+               lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+               lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_64] +
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] +
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] +
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] +
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] +
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_RX_SZ_JUMBO] +
+               lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_JUMBO];
+
+       stats->multicast = lan966x->stats[idx + SYS_COUNT_RX_MC] +
+               lan966x->stats[idx + SYS_COUNT_RX_PMAC_MC];
+
+       stats->rx_errors = lan966x->stats[idx + SYS_COUNT_RX_SHORT] +
+               lan966x->stats[idx + SYS_COUNT_RX_FRAG] +
+               lan966x->stats[idx + SYS_COUNT_RX_JABBER] +
+               lan966x->stats[idx + SYS_COUNT_RX_CRC] +
+               lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] +
+               lan966x->stats[idx + SYS_COUNT_RX_LONG];
+
+       stats->rx_dropped = dev->stats.rx_dropped +
+               lan966x->stats[idx + SYS_COUNT_RX_LONG] +
+               lan966x->stats[idx + SYS_COUNT_DR_LOCAL] +
+               lan966x->stats[idx + SYS_COUNT_DR_TAIL];
+
+       for (i = 0; i < LAN966X_NUM_TC; i++) {
+               stats->rx_dropped +=
+                       (lan966x->stats[idx + SYS_COUNT_DR_YELLOW_PRIO_0 + i] +
+                        lan966x->stats[idx + SYS_COUNT_DR_GREEN_PRIO_0 + i]);
+       }
+
+       /* Get Tx stats */
+       stats->tx_bytes = lan966x->stats[idx + SYS_COUNT_TX_OCT] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT];
+
+       stats->tx_packets = lan966x->stats[idx + SYS_COUNT_TX_SZ_64] +
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] +
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] +
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] +
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] +
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_TX_SZ_JUMBO] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526] +
+               lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_JUMBO];
+
+       stats->tx_dropped = lan966x->stats[idx + SYS_COUNT_TX_DROP] +
+               lan966x->stats[idx + SYS_COUNT_TX_AGED];
+
+       stats->collisions = lan966x->stats[idx + SYS_COUNT_TX_COL];
+
+       mutex_unlock(&lan966x->stats_lock);
+}
+
+int lan966x_stats_init(struct lan966x *lan966x)
+{
+       char queue_name[32];
+
+       lan966x->stats_layout = lan966x_stats_layout;
+       lan966x->num_stats = ARRAY_SIZE(lan966x_stats_layout);
+       lan966x->stats = devm_kcalloc(lan966x->dev, lan966x->num_phys_ports *
+                                     lan966x->num_stats,
+                                     sizeof(u64), GFP_KERNEL);
+       if (!lan966x->stats)
+               return -ENOMEM;
+
+       /* Init stats worker */
+       mutex_init(&lan966x->stats_lock);
+       snprintf(queue_name, sizeof(queue_name), "%s-stats",
+                dev_name(lan966x->dev));
+       lan966x->stats_queue = create_singlethread_workqueue(queue_name);
+       INIT_DELAYED_WORK(&lan966x->stats_work, lan966x_check_stats_work);
+       queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work,
+                          LAN966X_STATS_CHECK_DELAY);
+
+       return 0;
+}
index b042b7f47d5e27628cb149d9acad396781e42bad..e9e4dca6542d4b87c88b3995d1a1fbc238b7995a 100644 (file)
@@ -373,6 +373,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
        .ndo_change_mtu                 = lan966x_port_change_mtu,
        .ndo_set_rx_mode                = lan966x_port_set_rx_mode,
        .ndo_get_phys_port_name         = lan966x_port_get_phys_port_name,
+       .ndo_get_stats64                = lan966x_stats_get,
        .ndo_set_mac_address            = lan966x_port_set_mac_address,
        .ndo_get_port_parent_id         = lan966x_port_get_parent_id,
 };
@@ -588,6 +589,7 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
        dev->max_mtu = ETH_MAX_MTU;
 
        dev->netdev_ops = &lan966x_port_netdev_ops;
+       dev->ethtool_ops = &lan966x_ethtool_ops;
        dev->needed_headroom = IFH_LEN * sizeof(u32);
 
        eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);
@@ -875,6 +877,7 @@ static int lan966x_probe(struct platform_device *pdev)
 
        /* init switch */
        lan966x_init(lan966x);
+       lan966x_stats_init(lan966x);
 
        /* go over the child nodes */
        fwnode_for_each_available_child_node(ports, portnp) {
@@ -908,6 +911,10 @@ cleanup_ports:
 
        lan966x_cleanup_ports(lan966x);
 
+       cancel_delayed_work_sync(&lan966x->stats_work);
+       destroy_workqueue(lan966x->stats_queue);
+       mutex_destroy(&lan966x->stats_lock);
+
        return err;
 }
 
@@ -917,6 +924,10 @@ static int lan966x_remove(struct platform_device *pdev)
 
        lan966x_cleanup_ports(lan966x);
 
+       cancel_delayed_work_sync(&lan966x->stats_work);
+       destroy_workqueue(lan966x->stats_queue);
+       mutex_destroy(&lan966x->stats_lock);
+
        return 0;
 }
 
index ddac44bfddf7d663925a109b4794abdc640cb005..7e5a3b6f168dd5dd4b3e07bcbadf393c89285ef2 100644 (file)
@@ -58,6 +58,11 @@ enum macaccess_entry_type {
 
 struct lan966x_port;
 
+struct lan966x_stat_layout {
+       u32 offset;
+       char name[ETH_GSTRING_LEN];
+};
+
 struct lan966x {
        struct device *dev;
 
@@ -70,6 +75,16 @@ struct lan966x {
 
        u8 base_mac[ETH_ALEN];
 
+       /* stats */
+       const struct lan966x_stat_layout *stats_layout;
+       u32 num_stats;
+
+       /* workqueue for reading stats */
+       struct mutex stats_lock;
+       u64 *stats;
+       struct delayed_work stats_work;
+       struct workqueue_struct *stats_queue;
+
        /* interrupts */
        int xtr_irq;
 };
@@ -101,6 +116,11 @@ struct lan966x_port {
 
 extern const struct phylink_mac_ops lan966x_phylink_mac_ops;
 extern const struct phylink_pcs_ops lan966x_phylink_pcs_ops;
+extern const struct ethtool_ops lan966x_ethtool_ops;
+
+void lan966x_stats_get(struct net_device *dev,
+                      struct rtnl_link_stats64 *stats);
+int lan966x_stats_init(struct lan966x *lan966x);
 
 void lan966x_port_config_down(struct lan966x_port *port);
 void lan966x_port_config_up(struct lan966x_port *port);