linux/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Applied Micro X-Gene SoC Ethernet Driver
   3 *
   4 * Copyright (c) 2014, Applied Micro Circuits Corporation
   5 * 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                7
  89#define RALN_IDX                13
  90#define RFLR_IDX                14
  91#define FALSE_RFLR_IDX          15
  92#define RUND_IDX                18
  93#define FALSE_RJBR_IDX          22
  94#define RX_OVERRUN_IDX          24
  95#define TFCS_IDX                38
  96#define TFRG_IDX                42
  97#define TX_UNDERRUN_IDX         43
  98
  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_pauseparam
 338};
 339
 340void xgene_enet_set_ethtool_ops(struct net_device *ndev)
 341{
 342        ndev->ethtool_ops = &xgene_ethtool_ops;
 343}
 344