linux/drivers/net/ethernet/qualcomm/emac/emac-ethtool.c
<<
>>
Prefs
   1/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
   2 *
   3 * This program is free software; you can redistribute it and/or modify
   4 * it under the terms of the GNU General Public License version 2 and
   5 * only version 2 as published by the Free Software Foundation.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 */
  12
  13#include <linux/ethtool.h>
  14#include <linux/phy.h>
  15
  16#include "emac.h"
  17
  18static const char * const emac_ethtool_stat_strings[] = {
  19        "rx_ok",
  20        "rx_bcast",
  21        "rx_mcast",
  22        "rx_pause",
  23        "rx_ctrl",
  24        "rx_fcs_err",
  25        "rx_len_err",
  26        "rx_byte_cnt",
  27        "rx_runt",
  28        "rx_frag",
  29        "rx_sz_64",
  30        "rx_sz_65_127",
  31        "rx_sz_128_255",
  32        "rx_sz_256_511",
  33        "rx_sz_512_1023",
  34        "rx_sz_1024_1518",
  35        "rx_sz_1519_max",
  36        "rx_sz_ov",
  37        "rx_rxf_ov",
  38        "rx_align_err",
  39        "rx_bcast_byte_cnt",
  40        "rx_mcast_byte_cnt",
  41        "rx_err_addr",
  42        "rx_crc_align",
  43        "rx_jabbers",
  44        "tx_ok",
  45        "tx_bcast",
  46        "tx_mcast",
  47        "tx_pause",
  48        "tx_exc_defer",
  49        "tx_ctrl",
  50        "tx_defer",
  51        "tx_byte_cnt",
  52        "tx_sz_64",
  53        "tx_sz_65_127",
  54        "tx_sz_128_255",
  55        "tx_sz_256_511",
  56        "tx_sz_512_1023",
  57        "tx_sz_1024_1518",
  58        "tx_sz_1519_max",
  59        "tx_1_col",
  60        "tx_2_col",
  61        "tx_late_col",
  62        "tx_abort_col",
  63        "tx_underrun",
  64        "tx_rd_eop",
  65        "tx_len_err",
  66        "tx_trunc",
  67        "tx_bcast_byte",
  68        "tx_mcast_byte",
  69        "tx_col",
  70};
  71
  72#define EMAC_STATS_LEN  ARRAY_SIZE(emac_ethtool_stat_strings)
  73
  74static u32 emac_get_msglevel(struct net_device *netdev)
  75{
  76        struct emac_adapter *adpt = netdev_priv(netdev);
  77
  78        return adpt->msg_enable;
  79}
  80
  81static void emac_set_msglevel(struct net_device *netdev, u32 data)
  82{
  83        struct emac_adapter *adpt = netdev_priv(netdev);
  84
  85        adpt->msg_enable = data;
  86}
  87
  88static int emac_get_sset_count(struct net_device *netdev, int sset)
  89{
  90        switch (sset) {
  91        case ETH_SS_PRIV_FLAGS:
  92                return 1;
  93        case ETH_SS_STATS:
  94                return EMAC_STATS_LEN;
  95        default:
  96                return -EOPNOTSUPP;
  97        }
  98}
  99
 100static void emac_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
 101{
 102        unsigned int i;
 103
 104        switch (stringset) {
 105        case ETH_SS_PRIV_FLAGS:
 106                strcpy(data, "single-pause-mode");
 107                break;
 108
 109        case ETH_SS_STATS:
 110                for (i = 0; i < EMAC_STATS_LEN; i++) {
 111                        strlcpy(data, emac_ethtool_stat_strings[i],
 112                                ETH_GSTRING_LEN);
 113                        data += ETH_GSTRING_LEN;
 114                }
 115                break;
 116        }
 117}
 118
 119static void emac_get_ethtool_stats(struct net_device *netdev,
 120                                   struct ethtool_stats *stats,
 121                                   u64 *data)
 122{
 123        struct emac_adapter *adpt = netdev_priv(netdev);
 124
 125        spin_lock(&adpt->stats.lock);
 126
 127        emac_update_hw_stats(adpt);
 128        memcpy(data, &adpt->stats, EMAC_STATS_LEN * sizeof(u64));
 129
 130        spin_unlock(&adpt->stats.lock);
 131}
 132
 133static int emac_nway_reset(struct net_device *netdev)
 134{
 135        struct phy_device *phydev = netdev->phydev;
 136
 137        if (!phydev)
 138                return -ENODEV;
 139
 140        return genphy_restart_aneg(phydev);
 141}
 142
 143static void emac_get_ringparam(struct net_device *netdev,
 144                               struct ethtool_ringparam *ring)
 145{
 146        struct emac_adapter *adpt = netdev_priv(netdev);
 147
 148        ring->rx_max_pending = EMAC_MAX_RX_DESCS;
 149        ring->tx_max_pending = EMAC_MAX_TX_DESCS;
 150        ring->rx_pending = adpt->rx_desc_cnt;
 151        ring->tx_pending = adpt->tx_desc_cnt;
 152}
 153
 154static int emac_set_ringparam(struct net_device *netdev,
 155                              struct ethtool_ringparam *ring)
 156{
 157        struct emac_adapter *adpt = netdev_priv(netdev);
 158
 159        /* We don't have separate queues/rings for small/large frames, so
 160         * reject any attempt to specify those values separately.
 161         */
 162        if (ring->rx_mini_pending || ring->rx_jumbo_pending)
 163                return -EINVAL;
 164
 165        adpt->tx_desc_cnt =
 166                clamp_val(ring->tx_pending, EMAC_MIN_TX_DESCS, EMAC_MAX_TX_DESCS);
 167
 168        adpt->rx_desc_cnt =
 169                clamp_val(ring->rx_pending, EMAC_MIN_RX_DESCS, EMAC_MAX_RX_DESCS);
 170
 171        if (netif_running(netdev))
 172                return emac_reinit_locked(adpt);
 173
 174        return 0;
 175}
 176
 177static void emac_get_pauseparam(struct net_device *netdev,
 178                                struct ethtool_pauseparam *pause)
 179{
 180        struct emac_adapter *adpt = netdev_priv(netdev);
 181
 182        pause->autoneg = adpt->automatic ? AUTONEG_ENABLE : AUTONEG_DISABLE;
 183        pause->rx_pause = adpt->rx_flow_control ? 1 : 0;
 184        pause->tx_pause = adpt->tx_flow_control ? 1 : 0;
 185}
 186
 187static int emac_set_pauseparam(struct net_device *netdev,
 188                               struct ethtool_pauseparam *pause)
 189{
 190        struct emac_adapter *adpt = netdev_priv(netdev);
 191
 192        adpt->automatic = pause->autoneg == AUTONEG_ENABLE;
 193        adpt->rx_flow_control = pause->rx_pause != 0;
 194        adpt->tx_flow_control = pause->tx_pause != 0;
 195
 196        if (netif_running(netdev))
 197                return emac_reinit_locked(adpt);
 198
 199        return 0;
 200}
 201
 202/* Selected registers that might want to track during runtime. */
 203static const u16 emac_regs[] = {
 204        EMAC_DMA_MAS_CTRL,
 205        EMAC_MAC_CTRL,
 206        EMAC_TXQ_CTRL_0,
 207        EMAC_RXQ_CTRL_0,
 208        EMAC_DMA_CTRL,
 209        EMAC_INT_MASK,
 210        EMAC_AXI_MAST_CTRL,
 211        EMAC_CORE_HW_VERSION,
 212        EMAC_MISC_CTRL,
 213};
 214
 215/* Every time emac_regs[] above is changed, increase this version number. */
 216#define EMAC_REGS_VERSION       0
 217
 218#define EMAC_MAX_REG_SIZE       ARRAY_SIZE(emac_regs)
 219
 220static void emac_get_regs(struct net_device *netdev,
 221                          struct ethtool_regs *regs, void *buff)
 222{
 223        struct emac_adapter *adpt = netdev_priv(netdev);
 224        u32 *val = buff;
 225        unsigned int i;
 226
 227        regs->version = EMAC_REGS_VERSION;
 228        regs->len = EMAC_MAX_REG_SIZE * sizeof(u32);
 229
 230        for (i = 0; i < EMAC_MAX_REG_SIZE; i++)
 231                val[i] = readl(adpt->base + emac_regs[i]);
 232}
 233
 234static int emac_get_regs_len(struct net_device *netdev)
 235{
 236        return EMAC_MAX_REG_SIZE * sizeof(u32);
 237}
 238
 239#define EMAC_PRIV_ENABLE_SINGLE_PAUSE   BIT(0)
 240
 241static int emac_set_priv_flags(struct net_device *netdev, u32 flags)
 242{
 243        struct emac_adapter *adpt = netdev_priv(netdev);
 244
 245        adpt->single_pause_mode = !!(flags & EMAC_PRIV_ENABLE_SINGLE_PAUSE);
 246
 247        if (netif_running(netdev))
 248                return emac_reinit_locked(adpt);
 249
 250        return 0;
 251}
 252
 253static u32 emac_get_priv_flags(struct net_device *netdev)
 254{
 255        struct emac_adapter *adpt = netdev_priv(netdev);
 256
 257        return adpt->single_pause_mode ? EMAC_PRIV_ENABLE_SINGLE_PAUSE : 0;
 258}
 259
 260static const struct ethtool_ops emac_ethtool_ops = {
 261        .get_link_ksettings = phy_ethtool_get_link_ksettings,
 262        .set_link_ksettings = phy_ethtool_set_link_ksettings,
 263
 264        .get_msglevel    = emac_get_msglevel,
 265        .set_msglevel    = emac_set_msglevel,
 266
 267        .get_sset_count  = emac_get_sset_count,
 268        .get_strings = emac_get_strings,
 269        .get_ethtool_stats = emac_get_ethtool_stats,
 270
 271        .get_ringparam = emac_get_ringparam,
 272        .set_ringparam = emac_set_ringparam,
 273
 274        .get_pauseparam = emac_get_pauseparam,
 275        .set_pauseparam = emac_set_pauseparam,
 276
 277        .nway_reset = emac_nway_reset,
 278
 279        .get_link = ethtool_op_get_link,
 280
 281        .get_regs_len    = emac_get_regs_len,
 282        .get_regs        = emac_get_regs,
 283
 284        .set_priv_flags = emac_set_priv_flags,
 285        .get_priv_flags = emac_get_priv_flags,
 286};
 287
 288void emac_set_ethtool_ops(struct net_device *netdev)
 289{
 290        netdev->ethtool_ops = &emac_ethtool_ops;
 291}
 292