]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: dsa: netc: add support for the standardized counters
authorWei Fang <wei.fang@nxp.com>
Mon, 18 May 2026 08:25:05 +0000 (16:25 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 21 May 2026 11:04:42 +0000 (13:04 +0200)
Each user port of the NETC switch supports 802.3 basic and mandatory
managed objects statistic counters and IETF Management Information
Database (MIB) package (RFC2665) and Remote Network Monitoring (RMON)
counters. And all of these counters are 64-bit registers. In addition,
some user ports support preemption, so these ports have two MACs, MAC
0 is the express MAC (eMAC), MAC 1 is the preemptible MAC (pMAC). So
for ports that support preemption, the statistics are the sum of the
pMAC and eMAC statistics.

Note that the current switch driver does not support preemption, all
frames are sent and received via the eMAC by default. The statistics
read from the pMAC should be zero.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
Link: https://patch.msgid.link/20260518082506.1318236-15-wei.fang@nxp.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/dsa/netc/Makefile
drivers/net/dsa/netc/netc_ethtool.c [new file with mode: 0644]
drivers/net/dsa/netc/netc_main.c
drivers/net/dsa/netc/netc_switch.h
drivers/net/dsa/netc/netc_switch_hw.h
include/linux/fsl/netc_global.h

index 4a5767562574883f3cb0384ba105c7163071d331..f40b13c702e078eb471ce799d0c5d4695147466f 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_NET_DSA_NETC_SWITCH) += nxp-netc-switch.o
-nxp-netc-switch-objs := netc_main.o netc_platform.o
+nxp-netc-switch-objs := netc_main.o netc_platform.o netc_ethtool.o
diff --git a/drivers/net/dsa/netc/netc_ethtool.c b/drivers/net/dsa/netc/netc_ethtool.c
new file mode 100644 (file)
index 0000000..ac8940b
--- /dev/null
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * NXP NETC switch driver
+ * Copyright 2025-2026 NXP
+ */
+
+#include <linux/ethtool_netlink.h>
+
+#include "netc_switch.h"
+
+static const struct ethtool_rmon_hist_range netc_rmon_ranges[] = {
+       {   64,   64 },
+       {   65,  127 },
+       {  128,  255 },
+       {  256,  511 },
+       {  512, 1023 },
+       { 1024, 1522 },
+       { 1523, NETC_MAX_FRAME_LEN },
+       { }
+};
+
+static void netc_port_pause_stats(struct netc_port *np, int mac,
+                                 struct ethtool_pause_stats *stats)
+{
+       if (mac && !np->caps.pmac)
+               return;
+
+       stats->tx_pause_frames = netc_port_rd64(np, NETC_PM_TXPF(mac));
+       stats->rx_pause_frames = netc_port_rd64(np, NETC_PM_RXPF(mac));
+}
+
+void netc_port_get_pause_stats(struct dsa_switch *ds, int port,
+                              struct ethtool_pause_stats *pause_stats)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       struct net_device *ndev;
+
+       switch (pause_stats->src) {
+       case ETHTOOL_MAC_STATS_SRC_EMAC:
+               netc_port_pause_stats(np, 0, pause_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_PMAC:
+               netc_port_pause_stats(np, 1, pause_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
+               ndev = dsa_to_port(ds, port)->user;
+               ethtool_aggregate_pause_stats(ndev, pause_stats);
+               break;
+       }
+}
+
+static void netc_port_rmon_stats(struct netc_port *np, int mac,
+                                struct ethtool_rmon_stats *stats)
+{
+       if (mac && !np->caps.pmac)
+               return;
+
+       stats->undersize_pkts = netc_port_rd64(np, NETC_PM_RUND(mac));
+       stats->oversize_pkts = netc_port_rd64(np, NETC_PM_ROVR(mac));
+       stats->fragments = netc_port_rd64(np, NETC_PM_RFRG(mac));
+       stats->jabbers = netc_port_rd64(np, NETC_PM_RJBR(mac));
+
+       stats->hist[0] = netc_port_rd64(np, NETC_PM_R64(mac));
+       stats->hist[1] = netc_port_rd64(np, NETC_PM_R127(mac));
+       stats->hist[2] = netc_port_rd64(np, NETC_PM_R255(mac));
+       stats->hist[3] = netc_port_rd64(np, NETC_PM_R511(mac));
+       stats->hist[4] = netc_port_rd64(np, NETC_PM_R1023(mac));
+       stats->hist[5] = netc_port_rd64(np, NETC_PM_R1522(mac));
+       stats->hist[6] = netc_port_rd64(np, NETC_PM_R1523X(mac));
+
+       stats->hist_tx[0] = netc_port_rd64(np, NETC_PM_T64(mac));
+       stats->hist_tx[1] = netc_port_rd64(np, NETC_PM_T127(mac));
+       stats->hist_tx[2] = netc_port_rd64(np, NETC_PM_T255(mac));
+       stats->hist_tx[3] = netc_port_rd64(np, NETC_PM_T511(mac));
+       stats->hist_tx[4] = netc_port_rd64(np, NETC_PM_T1023(mac));
+       stats->hist_tx[5] = netc_port_rd64(np, NETC_PM_T1522(mac));
+       stats->hist_tx[6] = netc_port_rd64(np, NETC_PM_T1523X(mac));
+}
+
+void netc_port_get_rmon_stats(struct dsa_switch *ds, int port,
+                             struct ethtool_rmon_stats *rmon_stats,
+                             const struct ethtool_rmon_hist_range **ranges)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       struct net_device *ndev;
+
+       *ranges = netc_rmon_ranges;
+
+       switch (rmon_stats->src) {
+       case ETHTOOL_MAC_STATS_SRC_EMAC:
+               netc_port_rmon_stats(np, 0, rmon_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_PMAC:
+               netc_port_rmon_stats(np, 1, rmon_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
+               ndev = dsa_to_port(ds, port)->user;
+               ethtool_aggregate_rmon_stats(ndev, rmon_stats);
+               break;
+       }
+}
+
+static void netc_port_ctrl_stats(struct netc_port *np, int mac,
+                                struct ethtool_eth_ctrl_stats *stats)
+{
+       if (mac && !np->caps.pmac)
+               return;
+
+       stats->MACControlFramesTransmitted =
+               netc_port_rd64(np, NETC_PM_TCNP(mac));
+       stats->MACControlFramesReceived =
+               netc_port_rd64(np, NETC_PM_RCNP(mac));
+}
+
+void netc_port_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
+                                 struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       struct net_device *ndev;
+
+       switch (ctrl_stats->src) {
+       case ETHTOOL_MAC_STATS_SRC_EMAC:
+               netc_port_ctrl_stats(np, 0, ctrl_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_PMAC:
+               netc_port_ctrl_stats(np, 1, ctrl_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
+               ndev = dsa_to_port(ds, port)->user;
+               ethtool_aggregate_ctrl_stats(ndev, ctrl_stats);
+               break;
+       }
+}
+
+static void netc_port_mac_stats(struct netc_port *np, int mac,
+                               struct ethtool_eth_mac_stats *stats)
+{
+       if (mac && !np->caps.pmac)
+               return;
+
+       stats->FramesTransmittedOK = netc_port_rd64(np, NETC_PM_TFRM(mac));
+       stats->SingleCollisionFrames = netc_port_rd64(np, NETC_PM_TSCOL(mac));
+       stats->MultipleCollisionFrames =
+               netc_port_rd64(np, NETC_PM_TMCOL(mac));
+       stats->FramesReceivedOK = netc_port_rd64(np, NETC_PM_RFRM(mac));
+       stats->FrameCheckSequenceErrors =
+               netc_port_rd64(np, NETC_PM_RFCS(mac));
+       stats->AlignmentErrors = netc_port_rd64(np, NETC_PM_RALN(mac));
+       stats->OctetsTransmittedOK = netc_port_rd64(np, NETC_PM_TEOCT(mac));
+       stats->FramesWithDeferredXmissions =
+               netc_port_rd64(np, NETC_PM_TDFR(mac));
+       stats->LateCollisions = netc_port_rd64(np, NETC_PM_TLCOL(mac));
+       stats->FramesAbortedDueToXSColls =
+               netc_port_rd64(np, NETC_PM_TECOL(mac));
+       stats->FramesLostDueToIntMACXmitError =
+               netc_port_rd64(np, NETC_PM_TERR(mac));
+       stats->OctetsReceivedOK = netc_port_rd64(np, NETC_PM_REOCT(mac));
+       stats->FramesLostDueToIntMACRcvError =
+               netc_port_rd64(np, NETC_PM_RDRNTP(mac));
+       stats->MulticastFramesXmittedOK =
+               netc_port_rd64(np, NETC_PM_TMCA(mac));
+       stats->BroadcastFramesXmittedOK =
+               netc_port_rd64(np, NETC_PM_TBCA(mac));
+       stats->MulticastFramesReceivedOK =
+               netc_port_rd64(np, NETC_PM_RMCA(mac));
+       stats->BroadcastFramesReceivedOK =
+               netc_port_rd64(np, NETC_PM_RBCA(mac));
+       stats->FramesWithExcessiveDeferral =
+               netc_port_rd64(np, NETC_PM_TEDFR(mac));
+}
+
+void netc_port_get_eth_mac_stats(struct dsa_switch *ds, int port,
+                                struct ethtool_eth_mac_stats *mac_stats)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       struct net_device *ndev;
+
+       switch (mac_stats->src) {
+       case ETHTOOL_MAC_STATS_SRC_EMAC:
+               netc_port_mac_stats(np, 0, mac_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_PMAC:
+               netc_port_mac_stats(np, 1, mac_stats);
+               break;
+       case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
+               ndev = dsa_to_port(ds, port)->user;
+               ethtool_aggregate_mac_stats(ndev, mac_stats);
+               break;
+       }
+}
index bc1962b38cda212bf6910a0d638ddf125503b184..f3ab0c7646da681b4dce0d9be41c1016c9d1aa80 100644 (file)
@@ -1487,6 +1487,10 @@ static const struct dsa_switch_ops netc_switch_ops = {
        .port_mdb_add                   = netc_port_mdb_add,
        .port_mdb_del                   = netc_port_mdb_del,
        .port_set_host_flood            = netc_port_set_host_flood,
+       .get_pause_stats                = netc_port_get_pause_stats,
+       .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,
 };
 
 static int netc_switch_probe(struct pci_dev *pdev,
index f587c5031c700fdda4d1363d2efa5433b487a7fc..ed83201d128b02303d2c6b8a09327107995ffcff 100644 (file)
@@ -124,6 +124,7 @@ struct netc_switch {
 
 /* Write/Read registers of Switch Port (including pseudo MAC port) */
 #define netc_port_rd(p, o)             netc_read((p)->iobase + (o))
+#define netc_port_rd64(p, o)           netc_read64((p)->iobase + (o))
 #define netc_port_wr(p, o, v)          netc_write((p)->iobase + (o), v)
 
 /* Write/Read Switch global registers */
@@ -149,4 +150,15 @@ static inline void netc_del_fdb_entry(struct netc_fdb_entry *entry)
 
 int netc_switch_platform_probe(struct netc_switch *priv);
 
+/* ethtool APIs */
+void netc_port_get_pause_stats(struct dsa_switch *ds, int port,
+                              struct ethtool_pause_stats *pause_stats);
+void netc_port_get_rmon_stats(struct dsa_switch *ds, int port,
+                             struct ethtool_rmon_stats *rmon_stats,
+                             const struct ethtool_rmon_hist_range **ranges);
+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);
+
 #endif
index 78335c399955e1002b74b21e9d198ae27e512484..f4e8ef983c214ff6c0c7085a9b97144dcbe6641b 100644 (file)
@@ -184,6 +184,126 @@ enum netc_stg_stage {
 #define   SSP_10M                      1
 #define   SSP_1G                       2
 
+/* Port MAC 0/1 Receive Ethernet Octets Counter */
+#define NETC_PM_REOCT(a)               (0x1100 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Alignment Error Counter Register */
+#define NETC_PM_RALN(a)                        (0x1110 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Valid Pause Frame Counter */
+#define NETC_PM_RXPF(a)                        (0x1118 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Frame Counter */
+#define NETC_PM_RFRM(a)                        (0x1120 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Frame Check Sequence Error Counter */
+#define NETC_PM_RFCS(a)                        (0x1128 + (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 Undersized Packet Counter */
+#define NETC_PM_RUND(a)                        (0x1168 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive 64-Octet Packet Counter */
+#define NETC_PM_R64(a)                 (0x1170 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive 65 to 127-Octet Packet Counter */
+#define NETC_PM_R127(a)                        (0x1178 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive 128 to 255-Octet Packet Counter */
+#define NETC_PM_R255(a)                        (0x1180 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive 256 to 511-Octet Packet Counter */
+#define NETC_PM_R511(a)                        (0x1188 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive 512 to 1023-Octet Packet Counter */
+#define NETC_PM_R1023(a)               (0x1190 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive 1024 to 1522-Octet Packet Counter */
+#define NETC_PM_R1522(a)               (0x1198 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive 1523 to Max-Octet Packet Counter */
+#define NETC_PM_R1523X(a)              (0x11a0 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Oversized Packet Counter */
+#define NETC_PM_ROVR(a)                        (0x11a8 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Jabber Packet Counter */
+#define NETC_PM_RJBR(a)                        (0x11b0 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Fragment Packet Counter */
+#define NETC_PM_RFRG(a)                        (0x11b8 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Control Packet Counter */
+#define NETC_PM_RCNP(a)                        (0x11c0 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Dropped Not Truncated Packets Counter */
+#define NETC_PM_RDRNTP(a)              (0x11c8 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Ethernet Octets Counter */
+#define NETC_PM_TEOCT(a)               (0x1200 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Excessive Deferral Packet Counter */
+#define NETC_PM_TEDFR(a)               (0x1210 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Valid Pause Frame Counter */
+#define NETC_PM_TXPF(a)                        (0x1218 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Frame Counter */
+#define NETC_PM_TFRM(a)                        (0x1220 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Frame Error Counter */
+#define NETC_PM_TERR(a)                        (0x1238 + (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 64-Octet Packet Counter */
+#define NETC_PM_T64(a)                 (0x1270 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit 65 to 127-Octet Packet Counter */
+#define NETC_PM_T127(a)                        (0x1278 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit 128 to 255-Octet Packet Counter */
+#define NETC_PM_T255(a)                        (0x1280 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit 256 to 511-Octet Packet Counter */
+#define NETC_PM_T511(a)                        (0x1288 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit 512 to 1023-Octet Packet Counter */
+#define NETC_PM_T1023(a)               (0x1290 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit 1024 to 1522-Octet Packet Counter */
+#define NETC_PM_T1522(a)               (0x1298 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit 1523 to TX_MTU-Octet Packet Counter */
+#define NETC_PM_T1523X(a)              (0x12a0 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Control Packet Counter */
+#define NETC_PM_TCNP(a)                        (0x12c0 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Deferred Packet Counter */
+#define NETC_PM_TDFR(a)                        (0x12d0 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Multiple Collisions Counter */
+#define NETC_PM_TMCOL(a)               (0x12d8 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Single Collision */
+#define NETC_PM_TSCOL(a)               (0x12e0 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Late Collision Counter */
+#define NETC_PM_TLCOL(a)               (0x12e8 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Excessive Collisions Counter */
+#define NETC_PM_TECOL(a)               (0x12f0 + (a) * 0x400)
+
 #define NETC_PEMDIOCR                  0x1c00
 #define NETC_EMDIO_BASE                        NETC_PEMDIOCR
 
index fdecca8c90f0c1eebe06080f2bf916225d3b3dda..5b8ff528d36992ea0e30a41e404a3bb2619129d7 100644 (file)
@@ -5,6 +5,7 @@
 #define __NETC_GLOBAL_H
 
 #include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 static inline u32 netc_read(void __iomem *reg)
 {
@@ -16,4 +17,9 @@ static inline void netc_write(void __iomem *reg, u32 val)
        iowrite32(val, reg);
 }
 
+static inline u64 netc_read64(void __iomem *reg)
+{
+       return ioread64(reg);
+}
+
 #endif