linux/drivers/staging/mt7621-eth/ethtool.c
<<
>>
Prefs
   1/*   This program is free software; you can redistribute it and/or modify
   2 *   it under the terms of the GNU General Public License as published by
   3 *   the Free Software Foundation; version 2 of the License
   4 *
   5 *   This program is distributed in the hope that it will be useful,
   6 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   7 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   8 *   GNU General Public License for more details.
   9 *
  10 *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
  11 *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
  12 *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
  13 */
  14
  15#include "mtk_eth_soc.h"
  16
  17static const char mtk_gdma_str[][ETH_GSTRING_LEN] = {
  18#define _FE(x...)       # x,
  19MTK_STAT_REG_DECLARE
  20#undef _FE
  21};
  22
  23static int mtk_get_link_ksettings(struct net_device *dev,
  24                                  struct ethtool_link_ksettings *cmd)
  25{
  26        struct mtk_mac *mac = netdev_priv(dev);
  27        int err;
  28
  29        if (!mac->phy_dev)
  30                return -ENODEV;
  31
  32        if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
  33                err = phy_read_status(mac->phy_dev);
  34                if (err)
  35                        return -ENODEV;
  36        }
  37
  38        phy_ethtool_ksettings_get(mac->phy_dev, cmd);
  39        return 0;
  40}
  41
  42static int mtk_set_link_ksettings(struct net_device *dev,
  43                                  const struct ethtool_link_ksettings *cmd)
  44{
  45        struct mtk_mac *mac = netdev_priv(dev);
  46
  47        if (!mac->phy_dev)
  48                return -ENODEV;
  49
  50        if (cmd->base.phy_address != mac->phy_dev->mdio.addr) {
  51                if (mac->hw->phy->phy_node[cmd->base.phy_address]) {
  52                        mac->phy_dev = mac->hw->phy->phy[cmd->base.phy_address];
  53                        mac->phy_flags = MTK_PHY_FLAG_PORT;
  54                } else if (mac->hw->mii_bus) {
  55                        mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus, cmd->base.phy_address);
  56                        if (!mac->phy_dev)
  57                                return -ENODEV;
  58                        mac->phy_flags = MTK_PHY_FLAG_ATTACH;
  59                } else {
  60                        return -ENODEV;
  61                }
  62        }
  63
  64        return phy_ethtool_ksettings_set(mac->phy_dev, cmd);
  65
  66}
  67
  68static void mtk_get_drvinfo(struct net_device *dev,
  69                            struct ethtool_drvinfo *info)
  70{
  71        struct mtk_mac *mac = netdev_priv(dev);
  72        struct mtk_soc_data *soc = mac->hw->soc;
  73
  74        strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
  75        strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
  76
  77        if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE])
  78                info->n_stats = ARRAY_SIZE(mtk_gdma_str);
  79}
  80
  81static u32 mtk_get_msglevel(struct net_device *dev)
  82{
  83        struct mtk_mac *mac = netdev_priv(dev);
  84
  85        return mac->hw->msg_enable;
  86}
  87
  88static void mtk_set_msglevel(struct net_device *dev, u32 value)
  89{
  90        struct mtk_mac *mac = netdev_priv(dev);
  91
  92        mac->hw->msg_enable = value;
  93}
  94
  95static int mtk_nway_reset(struct net_device *dev)
  96{
  97        struct mtk_mac *mac = netdev_priv(dev);
  98
  99        if (!mac->phy_dev)
 100                return -EOPNOTSUPP;
 101
 102        return genphy_restart_aneg(mac->phy_dev);
 103}
 104
 105static u32 mtk_get_link(struct net_device *dev)
 106{
 107        struct mtk_mac *mac = netdev_priv(dev);
 108        int err;
 109
 110        if (!mac->phy_dev)
 111                goto out_get_link;
 112
 113        if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
 114                err = genphy_update_link(mac->phy_dev);
 115                if (err)
 116                        goto out_get_link;
 117        }
 118
 119        return mac->phy_dev->link;
 120
 121out_get_link:
 122        return ethtool_op_get_link(dev);
 123}
 124
 125static int mtk_set_ringparam(struct net_device *dev,
 126                             struct ethtool_ringparam *ring)
 127{
 128        struct mtk_mac *mac = netdev_priv(dev);
 129
 130        if ((ring->tx_pending < 2) ||
 131            (ring->rx_pending < 2) ||
 132            (ring->rx_pending > mac->hw->soc->dma_ring_size) ||
 133            (ring->tx_pending > mac->hw->soc->dma_ring_size))
 134                return -EINVAL;
 135
 136        dev->netdev_ops->ndo_stop(dev);
 137
 138        mac->hw->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
 139        mac->hw->rx_ring[0].rx_ring_size = BIT(fls(ring->rx_pending) - 1);
 140
 141        return dev->netdev_ops->ndo_open(dev);
 142}
 143
 144static void mtk_get_ringparam(struct net_device *dev,
 145                              struct ethtool_ringparam *ring)
 146{
 147        struct mtk_mac *mac = netdev_priv(dev);
 148
 149        ring->rx_max_pending = mac->hw->soc->dma_ring_size;
 150        ring->tx_max_pending = mac->hw->soc->dma_ring_size;
 151        ring->rx_pending = mac->hw->rx_ring[0].rx_ring_size;
 152        ring->tx_pending = mac->hw->tx_ring.tx_ring_size;
 153}
 154
 155static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 156{
 157        switch (stringset) {
 158        case ETH_SS_STATS:
 159                memcpy(data, *mtk_gdma_str, sizeof(mtk_gdma_str));
 160                break;
 161        }
 162}
 163
 164static int mtk_get_sset_count(struct net_device *dev, int sset)
 165{
 166        switch (sset) {
 167        case ETH_SS_STATS:
 168                return ARRAY_SIZE(mtk_gdma_str);
 169        default:
 170                return -EOPNOTSUPP;
 171        }
 172}
 173
 174static void mtk_get_ethtool_stats(struct net_device *dev,
 175                                  struct ethtool_stats *stats, u64 *data)
 176{
 177        struct mtk_mac *mac = netdev_priv(dev);
 178        struct mtk_hw_stats *hwstats = mac->hw_stats;
 179        u64 *data_src, *data_dst;
 180        unsigned int start;
 181        int i;
 182
 183        if (netif_running(dev) && netif_device_present(dev)) {
 184                if (spin_trylock(&hwstats->stats_lock)) {
 185                        mtk_stats_update_mac(mac);
 186                        spin_unlock(&hwstats->stats_lock);
 187                }
 188        }
 189
 190        do {
 191                data_src = &hwstats->tx_bytes;
 192                data_dst = data;
 193                start = u64_stats_fetch_begin_irq(&hwstats->syncp);
 194
 195                for (i = 0; i < ARRAY_SIZE(mtk_gdma_str); i++)
 196                        *data_dst++ = *data_src++;
 197
 198        } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
 199}
 200
 201static struct ethtool_ops mtk_ethtool_ops = {
 202        .get_link_ksettings     = mtk_get_link_ksettings,
 203        .set_link_ksettings     = mtk_set_link_ksettings,
 204        .get_drvinfo            = mtk_get_drvinfo,
 205        .get_msglevel           = mtk_get_msglevel,
 206        .set_msglevel           = mtk_set_msglevel,
 207        .nway_reset             = mtk_nway_reset,
 208        .get_link               = mtk_get_link,
 209        .set_ringparam          = mtk_set_ringparam,
 210        .get_ringparam          = mtk_get_ringparam,
 211};
 212
 213void mtk_set_ethtool_ops(struct net_device *netdev)
 214{
 215        struct mtk_mac *mac = netdev_priv(netdev);
 216        struct mtk_soc_data *soc = mac->hw->soc;
 217
 218        if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) {
 219                mtk_ethtool_ops.get_strings = mtk_get_strings;
 220                mtk_ethtool_ops.get_sset_count = mtk_get_sset_count;
 221                mtk_ethtool_ops.get_ethtool_stats = mtk_get_ethtool_stats;
 222        }
 223
 224        netdev->ethtool_ops = &mtk_ethtool_ops;
 225}
 226