Implement the ethtool private statistics interface to expose additional
port-level and MAC-level counters that are not covered by the standard
IEEE 802.3 statistics. The pMAC counters are only reported when the port
supports Frame Preemption (802.1Qbu/802.3br).

Signed-off-by: Wei Fang <[email protected]>
---
 drivers/net/dsa/netc/netc_ethtool.c   | 107 ++++++++++++++++++++++++++
 drivers/net/dsa/netc/netc_main.c      |   3 +
 drivers/net/dsa/netc/netc_switch.h    |   9 +++
 drivers/net/dsa/netc/netc_switch_hw.h |  58 ++++++++++++++
 4 files changed, 177 insertions(+)

diff --git a/drivers/net/dsa/netc/netc_ethtool.c 
b/drivers/net/dsa/netc/netc_ethtool.c
index ac8940b5a85c..8d04db534347 100644
--- a/drivers/net/dsa/netc/netc_ethtool.c
+++ b/drivers/net/dsa/netc/netc_ethtool.c
@@ -19,6 +19,56 @@ static const struct ethtool_rmon_hist_range 
netc_rmon_ranges[] = {
        { }
 };
 
+static const struct netc_port_stat netc_port_counters[] = {
+       { NETC_PTGSLACR,        "port gate late arrival frames" },
+       { NETC_PSDFTCR, "port SDF transmit frames" },
+       { NETC_PSDFDDCR,        "port SDF drop duplicate frames" },
+       { NETC_PRXDCR,          "port rx discard frames" },
+       { NETC_PRXDCRRR,        "port rx discard read-reset" },
+       { NETC_PRXDCRR0,        "port rx discard reason 0" },
+       { NETC_PRXDCRR1,        "port rx discard reason 1" },
+       { NETC_PTXDCR,          "port tx discard frames" },
+       { NETC_PTXDCRRR,        "port tx discard read-reset" },
+       { NETC_PTXDCRR0,        "port tx discard reason 0" },
+       { NETC_PTXDCRR1,        "port tx discard reason 1" },
+       { NETC_BPDCR,           "bridge port discard frames" },
+       { NETC_BPDCRRR, "bridge port discard read-reset" },
+       { NETC_BPDCRR0, "bridge port discard reason 0" },
+       { NETC_BPDCRR1, "bridge port discard reason 1" },
+};
+
+static const struct netc_port_stat netc_emac_counters[] = {
+       { NETC_PM_ROCT(0),      "eMAC rx octets" },
+       { NETC_PM_RVLAN(0),     "eMAC rx VLAN frames" },
+       { NETC_PM_RERR(0),      "eMAC rx frame errors" },
+       { NETC_PM_RUCA(0),      "eMAC rx unicast frames" },
+       { NETC_PM_RDRP(0),      "eMAC rx dropped packets" },
+       { NETC_PM_RPKT(0),      "eMAC rx packets" },
+       { NETC_PM_TOCT(0),      "eMAC tx octets" },
+       { NETC_PM_TVLAN(0),     "eMAC tx VLAN frames" },
+       { NETC_PM_TFCS(0),      "eMAC tx FCS errors" },
+       { NETC_PM_TUCA(0),      "eMAC tx unicast frames" },
+       { NETC_PM_TPKT(0),      "eMAC tx packets" },
+       { NETC_PM_TUND(0),      "eMAC tx undersized packets" },
+       { NETC_PM_TIOCT(0),     "eMAC tx invalid octets" },
+};
+
+static const struct netc_port_stat netc_pmac_counters[] = {
+       { NETC_PM_ROCT(1),      "pMAC rx octets" },
+       { NETC_PM_RVLAN(1),     "pMAC rx VLAN frames" },
+       { NETC_PM_RERR(1),      "pMAC rx frame errors" },
+       { NETC_PM_RUCA(1),      "pMAC rx unicast frames" },
+       { NETC_PM_RDRP(1),      "pMAC rx dropped packets" },
+       { NETC_PM_RPKT(1),      "pMAC rx packets" },
+       { NETC_PM_TOCT(1),      "pMAC tx octets" },
+       { NETC_PM_TVLAN(1),     "pMAC tx VLAN frames" },
+       { NETC_PM_TFCS(1),      "pMAC tx FCS errors" },
+       { NETC_PM_TUCA(1),      "pMAC tx unicast frames" },
+       { NETC_PM_TPKT(1),      "pMAC tx packets" },
+       { NETC_PM_TUND(1),      "pMAC tx undersized packets" },
+       { NETC_PM_TIOCT(1),     "pMAC tx invalid octets" },
+};
+
 static void netc_port_pause_stats(struct netc_port *np, int mac,
                                  struct ethtool_pause_stats *stats)
 {
@@ -188,3 +238,60 @@ void netc_port_get_eth_mac_stats(struct dsa_switch *ds, 
int port,
                break;
        }
 }
+
+int netc_port_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       int size;
+
+       if (sset != ETH_SS_STATS)
+               return -EOPNOTSUPP;
+
+       size = ARRAY_SIZE(netc_port_counters) +
+              ARRAY_SIZE(netc_emac_counters);
+
+       if (np->caps.pmac)
+               size += ARRAY_SIZE(netc_pmac_counters);
+
+       return size;
+}
+
+void netc_port_get_strings(struct dsa_switch *ds, int port,
+                          u32 sset, u8 *data)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       int i;
+
+       if (sset != ETH_SS_STATS)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(netc_port_counters); i++)
+               ethtool_cpy(&data, netc_port_counters[i].name);
+
+       for (i = 0; i < ARRAY_SIZE(netc_emac_counters); i++)
+               ethtool_cpy(&data, netc_emac_counters[i].name);
+
+       if (!np->caps.pmac)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(netc_pmac_counters); i++)
+               ethtool_cpy(&data, netc_pmac_counters[i].name);
+}
+
+void netc_port_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(netc_port_counters); i++)
+               *data++ = netc_port_rd(np, netc_port_counters[i].reg);
+
+       for (i = 0; i < ARRAY_SIZE(netc_emac_counters); i++)
+               *data++ = netc_port_rd64(np, netc_emac_counters[i].reg);
+
+       if (!np->caps.pmac)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(netc_pmac_counters); i++)
+               *data++ = netc_port_rd64(np, netc_pmac_counters[i].reg);
+}
diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c
index 338f2421ccb4..a82e156ce86e 100644
--- a/drivers/net/dsa/netc/netc_main.c
+++ b/drivers/net/dsa/netc/netc_main.c
@@ -1467,6 +1467,9 @@ static const struct dsa_switch_ops netc_switch_ops = {
        .get_rmon_stats                 = netc_port_get_rmon_stats,
        .get_eth_ctrl_stats             = netc_port_get_eth_ctrl_stats,
        .get_eth_mac_stats              = netc_port_get_eth_mac_stats,
+       .get_sset_count                 = netc_port_get_sset_count,
+       .get_strings                    = netc_port_get_strings,
+       .get_ethtool_stats              = netc_port_get_ethtool_stats,
 };
 
 static int netc_switch_probe(struct pci_dev *pdev,
diff --git a/drivers/net/dsa/netc/netc_switch.h 
b/drivers/net/dsa/netc/netc_switch.h
index 40e54af0c356..740e1f307c45 100644
--- a/drivers/net/dsa/netc/netc_switch.h
+++ b/drivers/net/dsa/netc/netc_switch.h
@@ -94,6 +94,11 @@ struct netc_fdb_entry {
        struct hlist_node node;
 };
 
+struct netc_port_stat {
+       int reg;
+       char name[ETH_GSTRING_LEN] __nonstring;
+};
+
 struct netc_switch {
        struct pci_dev *pdev;
        struct device *dev;
@@ -160,5 +165,9 @@ void netc_port_get_eth_ctrl_stats(struct dsa_switch *ds, 
int port,
                                  struct ethtool_eth_ctrl_stats *ctrl_stats);
 void netc_port_get_eth_mac_stats(struct dsa_switch *ds, int port,
                                 struct ethtool_eth_mac_stats *mac_stats);
+int netc_port_get_sset_count(struct dsa_switch *ds, int port, int sset);
+void netc_port_get_strings(struct dsa_switch *ds, int port,
+                          u32 sset, u8 *data);
+void netc_port_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data);
 
 #endif
diff --git a/drivers/net/dsa/netc/netc_switch_hw.h 
b/drivers/net/dsa/netc/netc_switch_hw.h
index f8d436ad9623..1b016e7dd03e 100644
--- a/drivers/net/dsa/netc/netc_switch_hw.h
+++ b/drivers/net/dsa/netc/netc_switch_hw.h
@@ -87,6 +87,17 @@
 #define  PSR_TX_BUSY                   BIT(0)
 #define  PSR_RX_BUSY                   BIT(1)
 
+#define NETC_PTGSLACR                  0x130
+
+#define NETC_PRXDCR                    0x1c0
+#define NETC_PRXDCRRR                  0x1c4
+#define NETC_PRXDCRR0                  0x1c8
+#define NETC_PRXDCRR1                  0x1cc
+#define NETC_PTXDCR                    0x1e0
+#define NETC_PTXDCRRR                  0x1e4
+#define NETC_PTXDCRR0                  0x1e8
+#define NETC_PTXDCRR1                  0x1ec
+
 #define NETC_PTCTMSDUR(a)              (0x208 + (a) * 0x20)
 #define  PTCTMSDUR_MAXSDU              GENMASK(15, 0)
 #define  PTCTMSDUR_SDU_TYPE            GENMASK(17, 16)
@@ -94,6 +105,9 @@
 #define   SDU_TYPE_MPDU                        1
 #define   SDU_TYPE_MSDU                        2
 
+#define NETC_PSDFTCR                   0x4c4
+#define NETC_PSDFDDCR                  0x4c8
+
 #define NETC_BPCR                      0x500
 #define  BPCR_DYN_LIMIT                        GENMASK(15, 0)
 #define  BPCR_MLO                      GENMASK(22, 20)
@@ -142,6 +156,11 @@ enum netc_stg_stage {
        NETC_STG_STATE_FORWARDING,
 };
 
+#define NETC_BPDCR                     0x580
+#define NETC_BPDCRRR                   0x584
+#define NETC_BPDCRR0                   0x588
+#define NETC_BPDCRR1                   0x58c
+
 /* Definition of Switch ethernet MAC port registers */
 #define NETC_PMAC_OFFSET               0x400
 #define NETC_PM_CMD_CFG(a)             (0x1008 + (a) * 0x400)
@@ -176,6 +195,9 @@ enum netc_stg_stage {
 /* Port MAC 0/1 Receive Ethernet Octets Counter */
 #define NETC_PM_REOCT(a)               (0x1100 + (a) * 0x400)
 
+/* Port MAC 0/1 Receive Octets Counter */
+#define NETC_PM_ROCT(a)                        (0x1108 + (a) * 0x400)
+
 /* Port MAC 0/1 Receive Alignment Error Counter Register */
 #define NETC_PM_RALN(a)                        (0x1110 + (a) * 0x400)
 
@@ -188,12 +210,27 @@ enum netc_stg_stage {
 /* Port MAC 0/1 Receive Frame Check Sequence Error Counter */
 #define NETC_PM_RFCS(a)                        (0x1128 + (a) * 0x400)
 
+/* Port MAC 0/1 Receive VLAN Frame Counter */
+#define NETC_PM_RVLAN(a)               (0x1130 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Frame Error Counter */
+#define NETC_PM_RERR(a)                        (0x1138 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Unicast Frame Counter */
+#define NETC_PM_RUCA(a)                        (0x1140 + (a) * 0x400)
+
 /* Port MAC 0/1 Receive Multicast Frame Counter */
 #define NETC_PM_RMCA(a)                        (0x1148 + (a) * 0x400)
 
 /* Port MAC 0/1 Receive Broadcast Frame Counter */
 #define NETC_PM_RBCA(a)                        (0x1150 + (a) * 0x400)
 
+/* Port MAC 0/1 Receive Dropped Packets Counter */
+#define NETC_PM_RDRP(a)                        (0x1158 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Packets Counter */
+#define NETC_PM_RPKT(a)                        (0x1160 + (a) * 0x400)
+
 /* Port MAC 0/1 Receive Undersized Packet Counter */
 #define NETC_PM_RUND(a)                        (0x1168 + (a) * 0x400)
 
@@ -236,6 +273,9 @@ enum netc_stg_stage {
 /* Port MAC 0/1 Transmit Ethernet Octets Counter */
 #define NETC_PM_TEOCT(a)               (0x1200 + (a) * 0x400)
 
+/* Port MAC 0/1 Transmit Octets Counter */
+#define NETC_PM_TOCT(a)                        (0x1208 + (a) * 0x400)
+
 /* Port MAC 0/1 Transmit Excessive Deferral Packet Counter */
 #define NETC_PM_TEDFR(a)               (0x1210 + (a) * 0x400)
 
@@ -245,15 +285,30 @@ enum netc_stg_stage {
 /* Port MAC 0/1 Transmit Frame Counter */
 #define NETC_PM_TFRM(a)                        (0x1220 + (a) * 0x400)
 
+/* Port MAC 0/1 Transmit Frame Check Sequence Error Counter */
+#define NETC_PM_TFCS(a)                        (0x1228 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit VLAN Frame Counter */
+#define NETC_PM_TVLAN(a)               (0x1230 + (a) * 0x400)
+
 /* Port MAC 0/1 Transmit Frame Error Counter */
 #define NETC_PM_TERR(a)                        (0x1238 + (a) * 0x400)
 
+/* Port MAC 0/1 Transmit Unicast Frame Counter */
+#define NETC_PM_TUCA(a)                        (0x1240 + (a) * 0x400)
+
 /* Port MAC 0/1 Transmit Multicast Frame Counter */
 #define NETC_PM_TMCA(a)                        (0x1248 + (a) * 0x400)
 
 /* Port MAC 0/1 Transmit Broadcast Frame Counter */
 #define NETC_PM_TBCA(a)                        (0x1250 + (a) * 0x400)
 
+/* Port MAC 0/1 Transmit Packets Counter */
+#define NETC_PM_TPKT(a)                        (0x1260 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Undersized Packet Counter */
+#define NETC_PM_TUND(a)                        (0x1268 + (a) * 0x400)
+
 /* Port MAC 0/1 Transmit 64-Octet Packet Counter */
 #define NETC_PM_T64(a)                 (0x1270 + (a) * 0x400)
 
@@ -293,6 +348,9 @@ enum netc_stg_stage {
 /* Port MAC 0/1 Transmit Excessive Collisions Counter */
 #define NETC_PM_TECOL(a)               (0x12f0 + (a) * 0x400)
 
+/* Port MAC 0/1 Transmit Invalid Octets Counter */
+#define NETC_PM_TIOCT(a)               (0x12f8 + (a) * 0x400)
+
 #define NETC_PEMDIOCR                  0x1c00
 #define NETC_EMDIO_BASE                        NETC_PEMDIOCR
 
-- 
2.34.1


Reply via email to