344 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Applied Micro X-Gene SoC Ethernet Driver3 *4 * Copyright (c) 2014, Applied Micro Circuits Corporation5 * Authors: Iyappan Subramanian <isubramanian@apm.com>6 */7 8#include <linux/ethtool.h>9#include "xgene_enet_main.h"10 11struct xgene_gstrings_stats {12 char name[ETH_GSTRING_LEN];13 int offset;14 u32 addr;15 u32 mask;16};17 18#define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }19#define XGENE_EXTD_STAT(s, a, m) \20 { \21 .name = #s, \22 .addr = a ## _ADDR, \23 .mask = m \24 }25 26static const struct xgene_gstrings_stats gstrings_stats[] = {27 XGENE_STAT(rx_packets),28 XGENE_STAT(tx_packets),29 XGENE_STAT(rx_bytes),30 XGENE_STAT(tx_bytes),31 XGENE_STAT(rx_errors),32 XGENE_STAT(tx_errors),33 XGENE_STAT(rx_length_errors),34 XGENE_STAT(rx_crc_errors),35 XGENE_STAT(rx_frame_errors),36 XGENE_STAT(rx_fifo_errors)37};38 39static const struct xgene_gstrings_stats gstrings_extd_stats[] = {40 XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31),41 XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31),42 XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31),43 XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31),44 XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31),45 XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31),46 XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31),47 XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16),48 XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31),49 XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31),50 XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16),51 XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16),52 XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16),53 XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16),54 XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16),55 XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0),56 XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16),57 XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16),58 XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16),59 XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16),60 XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16),61 XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16),62 XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0),63 XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16),64 XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0),65 XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),66 XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31),67 XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16),68 XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31),69 XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31),70 XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31),71 XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31),72 XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31),73 XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31),74 XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31),75 XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16),76 XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16),77 XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12),78 XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12),79 XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12),80 XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12),81 XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12),82 XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12),83 XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0)84};85 86#define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats)87#define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats)88#define RFCS_IDX 789#define RALN_IDX 1390#define RFLR_IDX 1491#define FALSE_RFLR_IDX 1592#define RUND_IDX 1893#define FALSE_RJBR_IDX 2294#define RX_OVERRUN_IDX 2495#define TFCS_IDX 3896#define TFRG_IDX 4297#define TX_UNDERRUN_IDX 4398 99static void xgene_get_drvinfo(struct net_device *ndev,100 struct ethtool_drvinfo *info)101{102 struct xgene_enet_pdata *pdata = netdev_priv(ndev);103 struct platform_device *pdev = pdata->pdev;104 105 strcpy(info->driver, "xgene_enet");106 sprintf(info->bus_info, "%s", pdev->name);107}108 109static int xgene_get_link_ksettings(struct net_device *ndev,110 struct ethtool_link_ksettings *cmd)111{112 struct xgene_enet_pdata *pdata = netdev_priv(ndev);113 struct phy_device *phydev = ndev->phydev;114 u32 supported;115 116 if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {117 if (phydev == NULL)118 return -ENODEV;119 120 phy_ethtool_ksettings_get(phydev, cmd);121 122 return 0;123 } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {124 if (pdata->mdio_driver) {125 if (!phydev)126 return -ENODEV;127 128 phy_ethtool_ksettings_get(phydev, cmd);129 130 return 0;131 }132 133 supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |134 SUPPORTED_MII;135 ethtool_convert_legacy_u32_to_link_mode(136 cmd->link_modes.supported,137 supported);138 ethtool_convert_legacy_u32_to_link_mode(139 cmd->link_modes.advertising,140 supported);141 142 cmd->base.speed = SPEED_1000;143 cmd->base.duplex = DUPLEX_FULL;144 cmd->base.port = PORT_MII;145 cmd->base.autoneg = AUTONEG_ENABLE;146 } else {147 supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE;148 ethtool_convert_legacy_u32_to_link_mode(149 cmd->link_modes.supported,150 supported);151 ethtool_convert_legacy_u32_to_link_mode(152 cmd->link_modes.advertising,153 supported);154 155 cmd->base.speed = SPEED_10000;156 cmd->base.duplex = DUPLEX_FULL;157 cmd->base.port = PORT_FIBRE;158 cmd->base.autoneg = AUTONEG_DISABLE;159 }160 161 return 0;162}163 164static int xgene_set_link_ksettings(struct net_device *ndev,165 const struct ethtool_link_ksettings *cmd)166{167 struct xgene_enet_pdata *pdata = netdev_priv(ndev);168 struct phy_device *phydev = ndev->phydev;169 170 if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {171 if (!phydev)172 return -ENODEV;173 174 return phy_ethtool_ksettings_set(phydev, cmd);175 }176 177 if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {178 if (pdata->mdio_driver) {179 if (!phydev)180 return -ENODEV;181 182 return phy_ethtool_ksettings_set(phydev, cmd);183 }184 }185 186 return -EINVAL;187}188 189static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)190{191 int i;192 u8 *p = data;193 194 if (stringset != ETH_SS_STATS)195 return;196 197 for (i = 0; i < XGENE_STATS_LEN; i++) {198 memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);199 p += ETH_GSTRING_LEN;200 }201 202 for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {203 memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN);204 p += ETH_GSTRING_LEN;205 }206}207 208static int xgene_get_sset_count(struct net_device *ndev, int sset)209{210 if (sset != ETH_SS_STATS)211 return -EINVAL;212 213 return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN;214}215 216static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)217{218 u32 rx_drop, tx_drop;219 u32 mask, tmp;220 int i;221 222 for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {223 tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);224 if (gstrings_extd_stats[i].mask) {225 mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0);226 pdata->extd_stats[i] += (tmp & mask);227 }228 }229 230 if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {231 /* Errata 10GE_10 - SW should intepret RALN as 0 */232 pdata->extd_stats[RALN_IDX] = 0;233 } else {234 /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */235 pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX];236 pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX];237 pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX];238 }239 240 pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop);241 pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop;242 pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop;243 244 /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */245 pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr;246 /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */247 pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr;248}249 250int xgene_extd_stats_init(struct xgene_enet_pdata *pdata)251{252 pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev,253 XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL);254 if (!pdata->extd_stats)255 return -ENOMEM;256 257 xgene_get_extd_stats(pdata);258 memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64));259 260 return 0;261}262 263static void xgene_get_ethtool_stats(struct net_device *ndev,264 struct ethtool_stats *dummy,265 u64 *data)266{267 struct xgene_enet_pdata *pdata = netdev_priv(ndev);268 struct rtnl_link_stats64 stats;269 int i;270 271 dev_get_stats(ndev, &stats);272 for (i = 0; i < XGENE_STATS_LEN; i++)273 data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset);274 275 xgene_get_extd_stats(pdata);276 for (i = 0; i < XGENE_EXTD_STATS_LEN; i++)277 data[i + XGENE_STATS_LEN] = pdata->extd_stats[i];278}279 280static void xgene_get_pauseparam(struct net_device *ndev,281 struct ethtool_pauseparam *pp)282{283 struct xgene_enet_pdata *pdata = netdev_priv(ndev);284 285 pp->autoneg = pdata->pause_autoneg;286 pp->tx_pause = pdata->tx_pause;287 pp->rx_pause = pdata->rx_pause;288}289 290static int xgene_set_pauseparam(struct net_device *ndev,291 struct ethtool_pauseparam *pp)292{293 struct xgene_enet_pdata *pdata = netdev_priv(ndev);294 struct phy_device *phydev = ndev->phydev;295 296 if (phy_interface_mode_is_rgmii(pdata->phy_mode) ||297 pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {298 if (!phydev)299 return -EINVAL;300 301 if (!phy_validate_pause(phydev, pp))302 return -EINVAL;303 304 pdata->pause_autoneg = pp->autoneg;305 pdata->tx_pause = pp->tx_pause;306 pdata->rx_pause = pp->rx_pause;307 308 phy_set_asym_pause(phydev, pp->rx_pause, pp->tx_pause);309 310 if (!pp->autoneg) {311 pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);312 pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);313 }314 } else {315 if (pp->autoneg)316 return -EINVAL;317 318 pdata->tx_pause = pp->tx_pause;319 pdata->rx_pause = pp->rx_pause;320 321 pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);322 pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);323 }324 325 return 0;326}327 328static const struct ethtool_ops xgene_ethtool_ops = {329 .get_drvinfo = xgene_get_drvinfo,330 .get_link = ethtool_op_get_link,331 .get_strings = xgene_get_strings,332 .get_sset_count = xgene_get_sset_count,333 .get_ethtool_stats = xgene_get_ethtool_stats,334 .get_link_ksettings = xgene_get_link_ksettings,335 .set_link_ksettings = xgene_set_link_ksettings,336 .get_pauseparam = xgene_get_pauseparam,337 .set_pauseparam = xgene_set_pauseparam338};339 340void xgene_enet_set_ethtool_ops(struct net_device *ndev)341{342 ndev->ethtool_ops = &xgene_ethtool_ops;343}344