xref: /linux/drivers/net/dsa/netc/netc_ethtool.c (revision d603517771d8e08a2d8fc9e1f7682ce393d3973a)
1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /*
3  * NXP NETC switch driver
4  * Copyright 2025-2026 NXP
5  */
6 
7 #include <linux/ethtool_netlink.h>
8 
9 #include "netc_switch.h"
10 
11 static const struct ethtool_rmon_hist_range netc_rmon_ranges[] = {
12 	{   64,   64 },
13 	{   65,  127 },
14 	{  128,  255 },
15 	{  256,  511 },
16 	{  512, 1023 },
17 	{ 1024, 1522 },
18 	{ 1523, NETC_MAX_FRAME_LEN },
19 	{ }
20 };
21 
22 static const struct netc_port_stat netc_port_counters[] = {
23 	{ NETC_PTGSLACR,	"port gate late arrival frames" },
24 	{ NETC_PSDFTCR,	"port SDF transmit frames" },
25 	{ NETC_PSDFDDCR,	"port SDF drop duplicate frames" },
26 	{ NETC_PRXDCR,		"port rx discard frames" },
27 	{ NETC_PRXDCRRR,	"port rx discard read-reset" },
28 	{ NETC_PRXDCRR0,	"port rx discard reason 0" },
29 	{ NETC_PRXDCRR1,	"port rx discard reason 1" },
30 	{ NETC_PTXDCR,		"port tx discard frames" },
31 	{ NETC_BPDCR,		"bridge port discard frames" },
32 };
33 
34 static const struct netc_port_stat netc_emac_counters[] = {
35 	{ NETC_PM_ROCT(0),	"eMAC rx octets" },
36 	{ NETC_PM_RVLAN(0),	"eMAC rx VLAN frames" },
37 	{ NETC_PM_RERR(0),	"eMAC rx frame errors" },
38 	{ NETC_PM_RUCA(0),	"eMAC rx unicast frames" },
39 	{ NETC_PM_RDRP(0),	"eMAC rx dropped packets" },
40 	{ NETC_PM_RPKT(0),	"eMAC rx packets" },
41 	{ NETC_PM_TOCT(0),	"eMAC tx octets" },
42 	{ NETC_PM_TVLAN(0),	"eMAC tx VLAN frames" },
43 	{ NETC_PM_TFCS(0),	"eMAC tx FCS errors" },
44 	{ NETC_PM_TUCA(0),	"eMAC tx unicast frames" },
45 	{ NETC_PM_TPKT(0),	"eMAC tx packets" },
46 	{ NETC_PM_TUND(0),	"eMAC tx undersized packets" },
47 	{ NETC_PM_TIOCT(0),	"eMAC tx invalid octets" },
48 };
49 
50 static const struct netc_port_stat netc_pmac_counters[] = {
51 	{ NETC_PM_ROCT(1),	"pMAC rx octets" },
52 	{ NETC_PM_RVLAN(1),	"pMAC rx VLAN frames" },
53 	{ NETC_PM_RERR(1),	"pMAC rx frame errors" },
54 	{ NETC_PM_RUCA(1),	"pMAC rx unicast frames" },
55 	{ NETC_PM_RDRP(1),	"pMAC rx dropped packets" },
56 	{ NETC_PM_RPKT(1),	"pMAC rx packets" },
57 	{ NETC_PM_TOCT(1),	"pMAC tx octets" },
58 	{ NETC_PM_TVLAN(1),	"pMAC tx VLAN frames" },
59 	{ NETC_PM_TFCS(1),	"pMAC tx FCS errors" },
60 	{ NETC_PM_TUCA(1),	"pMAC tx unicast frames" },
61 	{ NETC_PM_TPKT(1),	"pMAC tx packets" },
62 	{ NETC_PM_TUND(1),	"pMAC tx undersized packets" },
63 	{ NETC_PM_TIOCT(1),	"pMAC tx invalid octets" },
64 };
65 
66 static void netc_port_pause_stats(struct netc_port *np, int mac,
67 				  struct ethtool_pause_stats *stats)
68 {
69 	if (mac && !np->caps.pmac)
70 		return;
71 
72 	stats->tx_pause_frames = netc_port_rd64(np, NETC_PM_TXPF(mac));
73 	stats->rx_pause_frames = netc_port_rd64(np, NETC_PM_RXPF(mac));
74 }
75 
76 void netc_port_get_pause_stats(struct dsa_switch *ds, int port,
77 			       struct ethtool_pause_stats *pause_stats)
78 {
79 	struct netc_port *np = NETC_PORT(ds, port);
80 	struct net_device *ndev;
81 
82 	switch (pause_stats->src) {
83 	case ETHTOOL_MAC_STATS_SRC_EMAC:
84 		netc_port_pause_stats(np, 0, pause_stats);
85 		break;
86 	case ETHTOOL_MAC_STATS_SRC_PMAC:
87 		netc_port_pause_stats(np, 1, pause_stats);
88 		break;
89 	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
90 		ndev = dsa_to_port(ds, port)->user;
91 		ethtool_aggregate_pause_stats(ndev, pause_stats);
92 		break;
93 	}
94 }
95 
96 static void netc_port_rmon_stats(struct netc_port *np, int mac,
97 				 struct ethtool_rmon_stats *stats)
98 {
99 	if (mac && !np->caps.pmac)
100 		return;
101 
102 	stats->undersize_pkts = netc_port_rd64(np, NETC_PM_RUND(mac));
103 	stats->oversize_pkts = netc_port_rd64(np, NETC_PM_ROVR(mac));
104 	stats->fragments = netc_port_rd64(np, NETC_PM_RFRG(mac));
105 	stats->jabbers = netc_port_rd64(np, NETC_PM_RJBR(mac));
106 
107 	stats->hist[0] = netc_port_rd64(np, NETC_PM_R64(mac));
108 	stats->hist[1] = netc_port_rd64(np, NETC_PM_R127(mac));
109 	stats->hist[2] = netc_port_rd64(np, NETC_PM_R255(mac));
110 	stats->hist[3] = netc_port_rd64(np, NETC_PM_R511(mac));
111 	stats->hist[4] = netc_port_rd64(np, NETC_PM_R1023(mac));
112 	stats->hist[5] = netc_port_rd64(np, NETC_PM_R1522(mac));
113 	stats->hist[6] = netc_port_rd64(np, NETC_PM_R1523X(mac));
114 
115 	stats->hist_tx[0] = netc_port_rd64(np, NETC_PM_T64(mac));
116 	stats->hist_tx[1] = netc_port_rd64(np, NETC_PM_T127(mac));
117 	stats->hist_tx[2] = netc_port_rd64(np, NETC_PM_T255(mac));
118 	stats->hist_tx[3] = netc_port_rd64(np, NETC_PM_T511(mac));
119 	stats->hist_tx[4] = netc_port_rd64(np, NETC_PM_T1023(mac));
120 	stats->hist_tx[5] = netc_port_rd64(np, NETC_PM_T1522(mac));
121 	stats->hist_tx[6] = netc_port_rd64(np, NETC_PM_T1523X(mac));
122 }
123 
124 void netc_port_get_rmon_stats(struct dsa_switch *ds, int port,
125 			      struct ethtool_rmon_stats *rmon_stats,
126 			      const struct ethtool_rmon_hist_range **ranges)
127 {
128 	struct netc_port *np = NETC_PORT(ds, port);
129 	struct net_device *ndev;
130 
131 	*ranges = netc_rmon_ranges;
132 
133 	switch (rmon_stats->src) {
134 	case ETHTOOL_MAC_STATS_SRC_EMAC:
135 		netc_port_rmon_stats(np, 0, rmon_stats);
136 		break;
137 	case ETHTOOL_MAC_STATS_SRC_PMAC:
138 		netc_port_rmon_stats(np, 1, rmon_stats);
139 		break;
140 	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
141 		ndev = dsa_to_port(ds, port)->user;
142 		ethtool_aggregate_rmon_stats(ndev, rmon_stats);
143 		break;
144 	}
145 }
146 
147 static void netc_port_ctrl_stats(struct netc_port *np, int mac,
148 				 struct ethtool_eth_ctrl_stats *stats)
149 {
150 	if (mac && !np->caps.pmac)
151 		return;
152 
153 	stats->MACControlFramesTransmitted =
154 		netc_port_rd64(np, NETC_PM_TCNP(mac));
155 	stats->MACControlFramesReceived =
156 		netc_port_rd64(np, NETC_PM_RCNP(mac));
157 }
158 
159 void netc_port_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
160 				  struct ethtool_eth_ctrl_stats *ctrl_stats)
161 {
162 	struct netc_port *np = NETC_PORT(ds, port);
163 	struct net_device *ndev;
164 
165 	switch (ctrl_stats->src) {
166 	case ETHTOOL_MAC_STATS_SRC_EMAC:
167 		netc_port_ctrl_stats(np, 0, ctrl_stats);
168 		break;
169 	case ETHTOOL_MAC_STATS_SRC_PMAC:
170 		netc_port_ctrl_stats(np, 1, ctrl_stats);
171 		break;
172 	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
173 		ndev = dsa_to_port(ds, port)->user;
174 		ethtool_aggregate_ctrl_stats(ndev, ctrl_stats);
175 		break;
176 	}
177 }
178 
179 static void netc_port_mac_stats(struct netc_port *np, int mac,
180 				struct ethtool_eth_mac_stats *stats)
181 {
182 	if (mac && !np->caps.pmac)
183 		return;
184 
185 	stats->FramesTransmittedOK = netc_port_rd64(np, NETC_PM_TFRM(mac));
186 	stats->SingleCollisionFrames = netc_port_rd64(np, NETC_PM_TSCOL(mac));
187 	stats->MultipleCollisionFrames =
188 		netc_port_rd64(np, NETC_PM_TMCOL(mac));
189 	stats->FramesReceivedOK = netc_port_rd64(np, NETC_PM_RFRM(mac));
190 	stats->FrameCheckSequenceErrors =
191 		netc_port_rd64(np, NETC_PM_RFCS(mac));
192 	stats->AlignmentErrors = netc_port_rd64(np, NETC_PM_RALN(mac));
193 	stats->OctetsTransmittedOK = netc_port_rd64(np, NETC_PM_TEOCT(mac));
194 	stats->FramesWithDeferredXmissions =
195 		netc_port_rd64(np, NETC_PM_TDFR(mac));
196 	stats->LateCollisions = netc_port_rd64(np, NETC_PM_TLCOL(mac));
197 	stats->FramesAbortedDueToXSColls =
198 		netc_port_rd64(np, NETC_PM_TECOL(mac));
199 	stats->FramesLostDueToIntMACXmitError =
200 		netc_port_rd64(np, NETC_PM_TERR(mac));
201 	stats->OctetsReceivedOK = netc_port_rd64(np, NETC_PM_REOCT(mac));
202 	stats->FramesLostDueToIntMACRcvError =
203 		netc_port_rd64(np, NETC_PM_RDRNTP(mac));
204 	stats->MulticastFramesXmittedOK =
205 		netc_port_rd64(np, NETC_PM_TMCA(mac));
206 	stats->BroadcastFramesXmittedOK =
207 		netc_port_rd64(np, NETC_PM_TBCA(mac));
208 	stats->MulticastFramesReceivedOK =
209 		netc_port_rd64(np, NETC_PM_RMCA(mac));
210 	stats->BroadcastFramesReceivedOK =
211 		netc_port_rd64(np, NETC_PM_RBCA(mac));
212 	stats->FramesWithExcessiveDeferral =
213 		netc_port_rd64(np, NETC_PM_TEDFR(mac));
214 }
215 
216 void netc_port_get_eth_mac_stats(struct dsa_switch *ds, int port,
217 				 struct ethtool_eth_mac_stats *mac_stats)
218 {
219 	struct netc_port *np = NETC_PORT(ds, port);
220 	struct net_device *ndev;
221 
222 	switch (mac_stats->src) {
223 	case ETHTOOL_MAC_STATS_SRC_EMAC:
224 		netc_port_mac_stats(np, 0, mac_stats);
225 		break;
226 	case ETHTOOL_MAC_STATS_SRC_PMAC:
227 		netc_port_mac_stats(np, 1, mac_stats);
228 		break;
229 	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
230 		ndev = dsa_to_port(ds, port)->user;
231 		ethtool_aggregate_mac_stats(ndev, mac_stats);
232 		break;
233 	}
234 }
235 
236 int netc_port_get_sset_count(struct dsa_switch *ds, int port, int sset)
237 {
238 	struct netc_port *np = NETC_PORT(ds, port);
239 	int size;
240 
241 	if (sset != ETH_SS_STATS)
242 		return -EOPNOTSUPP;
243 
244 	size = ARRAY_SIZE(netc_port_counters) +
245 	       ARRAY_SIZE(netc_emac_counters);
246 
247 	if (np->caps.pmac)
248 		size += ARRAY_SIZE(netc_pmac_counters);
249 
250 	return size;
251 }
252 
253 void netc_port_get_strings(struct dsa_switch *ds, int port,
254 			   u32 sset, u8 *data)
255 {
256 	struct netc_port *np = NETC_PORT(ds, port);
257 	int i;
258 
259 	if (sset != ETH_SS_STATS)
260 		return;
261 
262 	for (i = 0; i < ARRAY_SIZE(netc_port_counters); i++)
263 		ethtool_cpy(&data, netc_port_counters[i].name);
264 
265 	for (i = 0; i < ARRAY_SIZE(netc_emac_counters); i++)
266 		ethtool_cpy(&data, netc_emac_counters[i].name);
267 
268 	if (!np->caps.pmac)
269 		return;
270 
271 	for (i = 0; i < ARRAY_SIZE(netc_pmac_counters); i++)
272 		ethtool_cpy(&data, netc_pmac_counters[i].name);
273 }
274 
275 void netc_port_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
276 {
277 	struct netc_port *np = NETC_PORT(ds, port);
278 	int i;
279 
280 	for (i = 0; i < ARRAY_SIZE(netc_port_counters); i++)
281 		*data++ = netc_port_rd(np, netc_port_counters[i].reg);
282 
283 	for (i = 0; i < ARRAY_SIZE(netc_emac_counters); i++)
284 		*data++ = netc_port_rd64(np, netc_emac_counters[i].reg);
285 
286 	if (!np->caps.pmac)
287 		return;
288 
289 	for (i = 0; i < ARRAY_SIZE(netc_pmac_counters); i++)
290 		*data++ = netc_port_rd64(np, netc_pmac_counters[i].reg);
291 }
292