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