288 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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 struct kernel_ethtool_ringparam *kernel_ring,138 struct netlink_ext_ack *extack)139{140 struct emac_adapter *adpt = netdev_priv(netdev);141 142 ring->rx_max_pending = EMAC_MAX_RX_DESCS;143 ring->tx_max_pending = EMAC_MAX_TX_DESCS;144 ring->rx_pending = adpt->rx_desc_cnt;145 ring->tx_pending = adpt->tx_desc_cnt;146}147 148static int emac_set_ringparam(struct net_device *netdev,149 struct ethtool_ringparam *ring,150 struct kernel_ethtool_ringparam *kernel_ring,151 struct netlink_ext_ack *extack)152{153 struct emac_adapter *adpt = netdev_priv(netdev);154 155 /* We don't have separate queues/rings for small/large frames, so156 * reject any attempt to specify those values separately.157 */158 if (ring->rx_mini_pending || ring->rx_jumbo_pending)159 return -EINVAL;160 161 adpt->tx_desc_cnt =162 clamp_val(ring->tx_pending, EMAC_MIN_TX_DESCS, EMAC_MAX_TX_DESCS);163 164 adpt->rx_desc_cnt =165 clamp_val(ring->rx_pending, EMAC_MIN_RX_DESCS, EMAC_MAX_RX_DESCS);166 167 if (netif_running(netdev))168 return emac_reinit_locked(adpt);169 170 return 0;171}172 173static void emac_get_pauseparam(struct net_device *netdev,174 struct ethtool_pauseparam *pause)175{176 struct emac_adapter *adpt = netdev_priv(netdev);177 178 pause->autoneg = adpt->automatic ? AUTONEG_ENABLE : AUTONEG_DISABLE;179 pause->rx_pause = adpt->rx_flow_control ? 1 : 0;180 pause->tx_pause = adpt->tx_flow_control ? 1 : 0;181}182 183static int emac_set_pauseparam(struct net_device *netdev,184 struct ethtool_pauseparam *pause)185{186 struct emac_adapter *adpt = netdev_priv(netdev);187 188 adpt->automatic = pause->autoneg == AUTONEG_ENABLE;189 adpt->rx_flow_control = pause->rx_pause != 0;190 adpt->tx_flow_control = pause->tx_pause != 0;191 192 if (netif_running(netdev))193 return emac_reinit_locked(adpt);194 195 return 0;196}197 198/* Selected registers that might want to track during runtime. */199static const u16 emac_regs[] = {200 EMAC_DMA_MAS_CTRL,201 EMAC_MAC_CTRL,202 EMAC_TXQ_CTRL_0,203 EMAC_RXQ_CTRL_0,204 EMAC_DMA_CTRL,205 EMAC_INT_MASK,206 EMAC_AXI_MAST_CTRL,207 EMAC_CORE_HW_VERSION,208 EMAC_MISC_CTRL,209};210 211/* Every time emac_regs[] above is changed, increase this version number. */212#define EMAC_REGS_VERSION 0213 214#define EMAC_MAX_REG_SIZE ARRAY_SIZE(emac_regs)215 216static void emac_get_regs(struct net_device *netdev,217 struct ethtool_regs *regs, void *buff)218{219 struct emac_adapter *adpt = netdev_priv(netdev);220 u32 *val = buff;221 unsigned int i;222 223 regs->version = EMAC_REGS_VERSION;224 regs->len = EMAC_MAX_REG_SIZE * sizeof(u32);225 226 for (i = 0; i < EMAC_MAX_REG_SIZE; i++)227 val[i] = readl(adpt->base + emac_regs[i]);228}229 230static int emac_get_regs_len(struct net_device *netdev)231{232 return EMAC_MAX_REG_SIZE * sizeof(u32);233}234 235#define EMAC_PRIV_ENABLE_SINGLE_PAUSE BIT(0)236 237static int emac_set_priv_flags(struct net_device *netdev, u32 flags)238{239 struct emac_adapter *adpt = netdev_priv(netdev);240 241 adpt->single_pause_mode = !!(flags & EMAC_PRIV_ENABLE_SINGLE_PAUSE);242 243 if (netif_running(netdev))244 return emac_reinit_locked(adpt);245 246 return 0;247}248 249static u32 emac_get_priv_flags(struct net_device *netdev)250{251 struct emac_adapter *adpt = netdev_priv(netdev);252 253 return adpt->single_pause_mode ? EMAC_PRIV_ENABLE_SINGLE_PAUSE : 0;254}255 256static const struct ethtool_ops emac_ethtool_ops = {257 .get_link_ksettings = phy_ethtool_get_link_ksettings,258 .set_link_ksettings = phy_ethtool_set_link_ksettings,259 260 .get_msglevel = emac_get_msglevel,261 .set_msglevel = emac_set_msglevel,262 263 .get_sset_count = emac_get_sset_count,264 .get_strings = emac_get_strings,265 .get_ethtool_stats = emac_get_ethtool_stats,266 267 .get_ringparam = emac_get_ringparam,268 .set_ringparam = emac_set_ringparam,269 270 .get_pauseparam = emac_get_pauseparam,271 .set_pauseparam = emac_set_pauseparam,272 273 .nway_reset = emac_nway_reset,274 275 .get_link = ethtool_op_get_link,276 277 .get_regs_len = emac_get_regs_len,278 .get_regs = emac_get_regs,279 280 .set_priv_flags = emac_set_priv_flags,281 .get_priv_flags = emac_get_priv_flags,282};283 284void emac_set_ethtool_ops(struct net_device *netdev)285{286 netdev->ethtool_ops = &emac_ethtool_ops;287}288