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