1 // SPDX-License-Identifier: GPL-2.0 2 #define pr_fmt(fmt) "bcmasp_ethtool: " fmt 3 4 #include <linux/unaligned.h> 5 #include <linux/ethtool.h> 6 #include <linux/netdevice.h> 7 #include <linux/platform_device.h> 8 9 #include "bcmasp.h" 10 #include "bcmasp_intf_defs.h" 11 12 enum bcmasp_stat_type { 13 BCMASP_STAT_RX_CTRL, 14 BCMASP_STAT_RX_CTRL_PER_INTF, 15 BCMASP_STAT_SOFT, 16 }; 17 18 struct bcmasp_stats { 19 char stat_string[ETH_GSTRING_LEN]; 20 enum bcmasp_stat_type type; 21 u32 reg_offset; 22 }; 23 24 #define STAT_BCMASP_SOFT_MIB(str) { \ 25 .stat_string = str, \ 26 .type = BCMASP_STAT_SOFT, \ 27 } 28 29 #define STAT_BCMASP_OFFSET(str, _type, offset) { \ 30 .stat_string = str, \ 31 .type = _type, \ 32 .reg_offset = offset, \ 33 } 34 35 #define STAT_BCMASP_RX_CTRL(str, offset) \ 36 STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL, offset) 37 #define STAT_BCMASP_RX_CTRL_PER_INTF(str, offset) \ 38 STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL_PER_INTF, offset) 39 40 /* Must match the order of struct bcmasp_mib_counters */ 41 static const struct bcmasp_stats bcmasp_gstrings_stats[] = { 42 /* ASP RX control */ 43 STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Unimac", 44 ASP_RX_CTRL_UMAC_0_FRAME_COUNT), 45 STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Port", 46 ASP_RX_CTRL_FB_0_FRAME_COUNT), 47 STAT_BCMASP_RX_CTRL_PER_INTF("RX Buffer FIFO Depth", 48 ASP_RX_CTRL_FB_RX_FIFO_DEPTH), 49 STAT_BCMASP_RX_CTRL("Frames Out(Buffer)", 50 ASP_RX_CTRL_FB_OUT_FRAME_COUNT), 51 STAT_BCMASP_RX_CTRL("Frames Out(Filters)", 52 ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT), 53 /* Software maintained statistics */ 54 STAT_BCMASP_SOFT_MIB("RX SKB Alloc Failed"), 55 STAT_BCMASP_SOFT_MIB("TX DMA Failed"), 56 STAT_BCMASP_SOFT_MIB("Multicast Filters Full"), 57 STAT_BCMASP_SOFT_MIB("Unicast Filters Full"), 58 STAT_BCMASP_SOFT_MIB("MDA Filters Combined"), 59 STAT_BCMASP_SOFT_MIB("Promisc Filter Set"), 60 STAT_BCMASP_SOFT_MIB("TX Realloc For Offload Failed"), 61 STAT_BCMASP_SOFT_MIB("Tx Timeout Count"), 62 }; 63 64 #define BCMASP_STATS_LEN ARRAY_SIZE(bcmasp_gstrings_stats) 65 66 static int bcmasp_get_sset_count(struct net_device *dev, int string_set) 67 { 68 switch (string_set) { 69 case ETH_SS_STATS: 70 return BCMASP_STATS_LEN; 71 default: 72 return -EOPNOTSUPP; 73 } 74 } 75 76 static void bcmasp_get_strings(struct net_device *dev, u32 stringset, 77 u8 *data) 78 { 79 const char *str; 80 unsigned int i; 81 82 switch (stringset) { 83 case ETH_SS_STATS: 84 for (i = 0; i < BCMASP_STATS_LEN; i++) { 85 str = bcmasp_gstrings_stats[i].stat_string; 86 ethtool_puts(&data, str); 87 } 88 break; 89 default: 90 return; 91 } 92 } 93 94 static void bcmasp_update_mib_counters(struct bcmasp_intf *intf) 95 { 96 unsigned int i; 97 98 for (i = 0; i < BCMASP_STATS_LEN; i++) { 99 const struct bcmasp_stats *s; 100 u32 offset, val; 101 char *p; 102 103 s = &bcmasp_gstrings_stats[i]; 104 offset = s->reg_offset; 105 switch (s->type) { 106 case BCMASP_STAT_SOFT: 107 continue; 108 case BCMASP_STAT_RX_CTRL: 109 val = rx_ctrl_core_rl(intf->parent, offset); 110 break; 111 case BCMASP_STAT_RX_CTRL_PER_INTF: 112 offset += sizeof(u32) * intf->port; 113 val = rx_ctrl_core_rl(intf->parent, offset); 114 break; 115 default: 116 continue; 117 } 118 p = (char *)(&intf->mib) + (i * sizeof(u32)); 119 put_unaligned(val, (u32 *)p); 120 } 121 } 122 123 static void bcmasp_get_ethtool_stats(struct net_device *dev, 124 struct ethtool_stats *stats, 125 u64 *data) 126 { 127 struct bcmasp_intf *intf = netdev_priv(dev); 128 unsigned int i; 129 char *p; 130 131 if (netif_running(dev)) 132 bcmasp_update_mib_counters(intf); 133 134 for (i = 0; i < BCMASP_STATS_LEN; i++) { 135 p = (char *)(&intf->mib) + (i * sizeof(u32)); 136 data[i] = *(u32 *)p; 137 } 138 } 139 140 static void bcmasp_get_drvinfo(struct net_device *dev, 141 struct ethtool_drvinfo *info) 142 { 143 strscpy(info->driver, "bcmasp", sizeof(info->driver)); 144 strscpy(info->bus_info, dev_name(dev->dev.parent), 145 sizeof(info->bus_info)); 146 } 147 148 static u32 bcmasp_get_msglevel(struct net_device *dev) 149 { 150 struct bcmasp_intf *intf = netdev_priv(dev); 151 152 return intf->msg_enable; 153 } 154 155 static void bcmasp_set_msglevel(struct net_device *dev, u32 level) 156 { 157 struct bcmasp_intf *intf = netdev_priv(dev); 158 159 intf->msg_enable = level; 160 } 161 162 #define BCMASP_SUPPORTED_WAKE (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER) 163 static void bcmasp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 164 { 165 struct bcmasp_intf *intf = netdev_priv(dev); 166 struct bcmasp_priv *priv = intf->parent; 167 struct device *kdev = &priv->pdev->dev; 168 u32 phy_wolopts = 0; 169 170 if (dev->phydev) { 171 phy_ethtool_get_wol(dev->phydev, wol); 172 phy_wolopts = wol->wolopts; 173 } 174 175 /* MAC is not wake-up capable, return what the PHY does */ 176 if (!device_can_wakeup(kdev)) 177 return; 178 179 /* Overlay MAC capabilities with that of the PHY queried before */ 180 wol->supported |= BCMASP_SUPPORTED_WAKE; 181 wol->wolopts |= intf->wolopts; 182 183 /* Return the PHY configured magic password */ 184 if (phy_wolopts & WAKE_MAGICSECURE) 185 return; 186 187 memset(wol->sopass, 0, sizeof(wol->sopass)); 188 189 /* Otherwise the MAC one */ 190 if (wol->wolopts & WAKE_MAGICSECURE) 191 memcpy(wol->sopass, intf->sopass, sizeof(intf->sopass)); 192 } 193 194 static int bcmasp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 195 { 196 struct bcmasp_intf *intf = netdev_priv(dev); 197 struct bcmasp_priv *priv = intf->parent; 198 struct device *kdev = &priv->pdev->dev; 199 int ret = 0; 200 201 /* Try Wake-on-LAN from the PHY first */ 202 if (dev->phydev) { 203 ret = phy_ethtool_set_wol(dev->phydev, wol); 204 if (ret != -EOPNOTSUPP && wol->wolopts) 205 return ret; 206 } 207 208 if (!device_can_wakeup(kdev)) 209 return -EOPNOTSUPP; 210 211 if (wol->wolopts & ~BCMASP_SUPPORTED_WAKE) 212 return -EINVAL; 213 214 /* Interface Specific */ 215 intf->wolopts = wol->wolopts; 216 if (intf->wolopts & WAKE_MAGICSECURE) 217 memcpy(intf->sopass, wol->sopass, sizeof(wol->sopass)); 218 219 mutex_lock(&priv->wol_lock); 220 bcmasp_enable_wol(intf, !!intf->wolopts); 221 mutex_unlock(&priv->wol_lock); 222 223 return 0; 224 } 225 226 static int bcmasp_flow_insert(struct net_device *dev, struct ethtool_rxnfc *cmd) 227 { 228 struct bcmasp_intf *intf = netdev_priv(dev); 229 struct bcmasp_net_filter *nfilter; 230 u32 loc = cmd->fs.location; 231 bool wake = false; 232 233 if (cmd->fs.ring_cookie == RX_CLS_FLOW_WAKE) 234 wake = true; 235 236 /* Currently only supports WAKE filters */ 237 if (!wake) 238 return -EOPNOTSUPP; 239 240 switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { 241 case ETHER_FLOW: 242 case IP_USER_FLOW: 243 case TCP_V4_FLOW: 244 case UDP_V4_FLOW: 245 case TCP_V6_FLOW: 246 case UDP_V6_FLOW: 247 break; 248 default: 249 return -EOPNOTSUPP; 250 } 251 252 /* Check if filter already exists */ 253 if (bcmasp_netfilt_check_dup(intf, &cmd->fs)) 254 return -EINVAL; 255 256 nfilter = bcmasp_netfilt_get_init(intf, loc, wake, true); 257 if (IS_ERR(nfilter)) 258 return PTR_ERR(nfilter); 259 260 /* Return the location where we did insert the filter */ 261 cmd->fs.location = nfilter->hw_index; 262 memcpy(&nfilter->fs, &cmd->fs, sizeof(struct ethtool_rx_flow_spec)); 263 264 /* Since we only support wake filters, defer register programming till 265 * suspend time. 266 */ 267 return 0; 268 } 269 270 static int bcmasp_flow_delete(struct net_device *dev, struct ethtool_rxnfc *cmd) 271 { 272 struct bcmasp_intf *intf = netdev_priv(dev); 273 struct bcmasp_net_filter *nfilter; 274 275 nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false); 276 if (IS_ERR(nfilter)) 277 return PTR_ERR(nfilter); 278 279 bcmasp_netfilt_release(intf, nfilter); 280 281 return 0; 282 } 283 284 static int bcmasp_flow_get(struct bcmasp_intf *intf, struct ethtool_rxnfc *cmd) 285 { 286 struct bcmasp_net_filter *nfilter; 287 288 nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false); 289 if (IS_ERR(nfilter)) 290 return PTR_ERR(nfilter); 291 292 memcpy(&cmd->fs, &nfilter->fs, sizeof(nfilter->fs)); 293 294 cmd->data = intf->parent->num_net_filters; 295 296 return 0; 297 } 298 299 static int bcmasp_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 300 { 301 struct bcmasp_intf *intf = netdev_priv(dev); 302 int ret = -EOPNOTSUPP; 303 304 mutex_lock(&intf->parent->net_lock); 305 306 switch (cmd->cmd) { 307 case ETHTOOL_SRXCLSRLINS: 308 ret = bcmasp_flow_insert(dev, cmd); 309 break; 310 case ETHTOOL_SRXCLSRLDEL: 311 ret = bcmasp_flow_delete(dev, cmd); 312 break; 313 default: 314 break; 315 } 316 317 mutex_unlock(&intf->parent->net_lock); 318 319 return ret; 320 } 321 322 static int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 323 u32 *rule_locs) 324 { 325 struct bcmasp_intf *intf = netdev_priv(dev); 326 int err = 0; 327 328 mutex_lock(&intf->parent->net_lock); 329 330 switch (cmd->cmd) { 331 case ETHTOOL_GRXCLSRLCNT: 332 cmd->rule_cnt = bcmasp_netfilt_get_active(intf); 333 /* We support specifying rule locations */ 334 cmd->data |= RX_CLS_LOC_SPECIAL; 335 break; 336 case ETHTOOL_GRXCLSRULE: 337 err = bcmasp_flow_get(intf, cmd); 338 break; 339 case ETHTOOL_GRXCLSRLALL: 340 err = bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt); 341 cmd->data = intf->parent->num_net_filters; 342 break; 343 default: 344 err = -EOPNOTSUPP; 345 break; 346 } 347 348 mutex_unlock(&intf->parent->net_lock); 349 350 return err; 351 } 352 353 static int bcmasp_get_eee(struct net_device *dev, struct ethtool_keee *e) 354 { 355 if (!dev->phydev) 356 return -ENODEV; 357 358 return phy_ethtool_get_eee(dev->phydev, e); 359 } 360 361 static int bcmasp_set_eee(struct net_device *dev, struct ethtool_keee *e) 362 { 363 if (!dev->phydev) 364 return -ENODEV; 365 366 return phy_ethtool_set_eee(dev->phydev, e); 367 } 368 369 static void bcmasp_get_eth_mac_stats(struct net_device *dev, 370 struct ethtool_eth_mac_stats *mac_stats) 371 { 372 struct bcmasp_intf *intf = netdev_priv(dev); 373 374 mac_stats->FramesTransmittedOK = umac_rl(intf, UMC_GTPOK); 375 mac_stats->SingleCollisionFrames = umac_rl(intf, UMC_GTSCL); 376 mac_stats->MultipleCollisionFrames = umac_rl(intf, UMC_GTMCL); 377 mac_stats->FramesReceivedOK = umac_rl(intf, UMC_GRPOK); 378 mac_stats->FrameCheckSequenceErrors = umac_rl(intf, UMC_GRFCS); 379 mac_stats->AlignmentErrors = umac_rl(intf, UMC_GRALN); 380 mac_stats->OctetsTransmittedOK = umac_rl(intf, UMC_GTBYT); 381 mac_stats->FramesWithDeferredXmissions = umac_rl(intf, UMC_GTDRF); 382 mac_stats->LateCollisions = umac_rl(intf, UMC_GTLCL); 383 mac_stats->FramesAbortedDueToXSColls = umac_rl(intf, UMC_GTXCL); 384 mac_stats->OctetsReceivedOK = umac_rl(intf, UMC_GRBYT); 385 mac_stats->MulticastFramesXmittedOK = umac_rl(intf, UMC_GTMCA); 386 mac_stats->BroadcastFramesXmittedOK = umac_rl(intf, UMC_GTBCA); 387 mac_stats->FramesWithExcessiveDeferral = umac_rl(intf, UMC_GTEDF); 388 mac_stats->MulticastFramesReceivedOK = umac_rl(intf, UMC_GRMCA); 389 mac_stats->BroadcastFramesReceivedOK = umac_rl(intf, UMC_GRBCA); 390 } 391 392 static const struct ethtool_rmon_hist_range bcmasp_rmon_ranges[] = { 393 { 0, 64}, 394 { 65, 127}, 395 { 128, 255}, 396 { 256, 511}, 397 { 512, 1023}, 398 { 1024, 1518}, 399 { 1519, 1522}, 400 {} 401 }; 402 403 static void bcmasp_get_rmon_stats(struct net_device *dev, 404 struct ethtool_rmon_stats *rmon_stats, 405 const struct ethtool_rmon_hist_range **ranges) 406 { 407 struct bcmasp_intf *intf = netdev_priv(dev); 408 409 *ranges = bcmasp_rmon_ranges; 410 411 rmon_stats->undersize_pkts = umac_rl(intf, UMC_RRUND); 412 rmon_stats->oversize_pkts = umac_rl(intf, UMC_GROVR); 413 rmon_stats->fragments = umac_rl(intf, UMC_RRFRG); 414 rmon_stats->jabbers = umac_rl(intf, UMC_GRJBR); 415 416 rmon_stats->hist[0] = umac_rl(intf, UMC_GR64); 417 rmon_stats->hist[1] = umac_rl(intf, UMC_GR127); 418 rmon_stats->hist[2] = umac_rl(intf, UMC_GR255); 419 rmon_stats->hist[3] = umac_rl(intf, UMC_GR511); 420 rmon_stats->hist[4] = umac_rl(intf, UMC_GR1023); 421 rmon_stats->hist[5] = umac_rl(intf, UMC_GR1518); 422 rmon_stats->hist[6] = umac_rl(intf, UMC_GRMGV); 423 424 rmon_stats->hist_tx[0] = umac_rl(intf, UMC_TR64); 425 rmon_stats->hist_tx[1] = umac_rl(intf, UMC_TR127); 426 rmon_stats->hist_tx[2] = umac_rl(intf, UMC_TR255); 427 rmon_stats->hist_tx[3] = umac_rl(intf, UMC_TR511); 428 rmon_stats->hist_tx[4] = umac_rl(intf, UMC_TR1023); 429 rmon_stats->hist_tx[5] = umac_rl(intf, UMC_TR1518); 430 rmon_stats->hist_tx[6] = umac_rl(intf, UMC_TRMGV); 431 } 432 433 static void bcmasp_get_eth_ctrl_stats(struct net_device *dev, 434 struct ethtool_eth_ctrl_stats *ctrl_stats) 435 { 436 struct bcmasp_intf *intf = netdev_priv(dev); 437 438 ctrl_stats->MACControlFramesTransmitted = umac_rl(intf, UMC_GTXCF); 439 ctrl_stats->MACControlFramesReceived = umac_rl(intf, UMC_GRXCF); 440 ctrl_stats->UnsupportedOpcodesReceived = umac_rl(intf, UMC_GRXUO); 441 } 442 443 const struct ethtool_ops bcmasp_ethtool_ops = { 444 .get_drvinfo = bcmasp_get_drvinfo, 445 .get_link = ethtool_op_get_link, 446 .get_link_ksettings = phy_ethtool_get_link_ksettings, 447 .set_link_ksettings = phy_ethtool_set_link_ksettings, 448 .get_msglevel = bcmasp_get_msglevel, 449 .set_msglevel = bcmasp_set_msglevel, 450 .get_wol = bcmasp_get_wol, 451 .set_wol = bcmasp_set_wol, 452 .get_rxnfc = bcmasp_get_rxnfc, 453 .set_rxnfc = bcmasp_set_rxnfc, 454 .set_eee = bcmasp_set_eee, 455 .get_eee = bcmasp_get_eee, 456 .get_eth_mac_stats = bcmasp_get_eth_mac_stats, 457 .get_rmon_stats = bcmasp_get_rmon_stats, 458 .get_eth_ctrl_stats = bcmasp_get_eth_ctrl_stats, 459 .get_strings = bcmasp_get_strings, 460 .get_ethtool_stats = bcmasp_get_ethtool_stats, 461 .get_sset_count = bcmasp_get_sset_count, 462 .get_ts_info = ethtool_op_get_ts_info, 463 .nway_reset = phy_ethtool_nway_reset, 464 }; 465