emac-ethtool.c (6523B)
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 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, so 156 * 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 0 213 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}