1/******************************************************************************* 2 STMMAC Ethtool support 3 4 Copyright (C) 2007-2009 STMicroelectronics Ltd 5 6 This program is free software; you can redistribute it and/or modify it 7 under the terms and conditions of the GNU General Public License, 8 version 2, as published by the Free Software Foundation. 9 10 This program is distributed in the hope it will be useful, but WITHOUT 11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 more details. 14 15 You should have received a copy of the GNU General Public License along with 16 this program; if not, write to the Free Software Foundation, Inc., 17 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 19 The full GNU General Public License is included in this distribution in 20 the file called "COPYING". 21 22 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> 23*******************************************************************************/ 24 25#include <linux/etherdevice.h> 26#include <linux/ethtool.h> 27#include <linux/mii.h> 28#include <linux/phy.h> 29 30#include "stmmac.h" 31#include "dwmac_dma.h" 32 33#define REG_SPACE_SIZE 0x1054 34#define MAC100_ETHTOOL_NAME "st_mac100" 35#define GMAC_ETHTOOL_NAME "st_gmac" 36 37struct stmmac_stats { 38 char stat_string[ETH_GSTRING_LEN]; 39 int sizeof_stat; 40 int stat_offset; 41}; 42 43#define STMMAC_STAT(m) \ 44 { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \ 45 offsetof(struct stmmac_priv, xstats.m)} 46 47static const struct stmmac_stats stmmac_gstrings_stats[] = { 48 STMMAC_STAT(tx_underflow), 49 STMMAC_STAT(tx_carrier), 50 STMMAC_STAT(tx_losscarrier), 51 STMMAC_STAT(tx_heartbeat), 52 STMMAC_STAT(tx_deferred), 53 STMMAC_STAT(tx_vlan), 54 STMMAC_STAT(rx_vlan), 55 STMMAC_STAT(tx_jabber), 56 STMMAC_STAT(tx_frame_flushed), 57 STMMAC_STAT(tx_payload_error), 58 STMMAC_STAT(tx_ip_header_error), 59 STMMAC_STAT(rx_desc), 60 STMMAC_STAT(rx_partial), 61 STMMAC_STAT(rx_runt), 62 STMMAC_STAT(rx_toolong), 63 STMMAC_STAT(rx_collision), 64 STMMAC_STAT(rx_crc), 65 STMMAC_STAT(rx_length), 66 STMMAC_STAT(rx_mii), 67 STMMAC_STAT(rx_multicast), 68 STMMAC_STAT(rx_gmac_overflow), 69 STMMAC_STAT(rx_watchdog), 70 STMMAC_STAT(da_rx_filter_fail), 71 STMMAC_STAT(sa_rx_filter_fail), 72 STMMAC_STAT(rx_missed_cntr), 73 STMMAC_STAT(rx_overflow_cntr), 74 STMMAC_STAT(tx_undeflow_irq), 75 STMMAC_STAT(tx_process_stopped_irq), 76 STMMAC_STAT(tx_jabber_irq), 77 STMMAC_STAT(rx_overflow_irq), 78 STMMAC_STAT(rx_buf_unav_irq), 79 STMMAC_STAT(rx_process_stopped_irq), 80 STMMAC_STAT(rx_watchdog_irq), 81 STMMAC_STAT(tx_early_irq), 82 STMMAC_STAT(fatal_bus_error_irq), 83 STMMAC_STAT(threshold), 84 STMMAC_STAT(tx_pkt_n), 85 STMMAC_STAT(rx_pkt_n), 86 STMMAC_STAT(poll_n), 87 STMMAC_STAT(sched_timer_n), 88 STMMAC_STAT(normal_irq_n), 89}; 90#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) 91 92void stmmac_ethtool_getdrvinfo(struct net_device *dev, 93 struct ethtool_drvinfo *info) 94{ 95 struct stmmac_priv *priv = netdev_priv(dev); 96 97 if (!priv->is_gmac) 98 strcpy(info->driver, MAC100_ETHTOOL_NAME); 99 else 100 strcpy(info->driver, GMAC_ETHTOOL_NAME); 101 102 strcpy(info->version, DRV_MODULE_VERSION); 103 info->fw_version[0] = '\0'; 104 info->n_stats = STMMAC_STATS_LEN; 105} 106 107int stmmac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) 108{ 109 struct stmmac_priv *priv = netdev_priv(dev); 110 struct phy_device *phy = priv->phydev; 111 int rc; 112 if (phy == NULL) { 113 pr_err("%s: %s: PHY is not registered\n", 114 __func__, dev->name); 115 return -ENODEV; 116 } 117 if (!netif_running(dev)) { 118 pr_err("%s: interface is disabled: we cannot track " 119 "link speed / duplex setting\n", dev->name); 120 return -EBUSY; 121 } 122 cmd->transceiver = XCVR_INTERNAL; 123 spin_lock_irq(&priv->lock); 124 rc = phy_ethtool_gset(phy, cmd); 125 spin_unlock_irq(&priv->lock); 126 return rc; 127} 128 129int stmmac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) 130{ 131 struct stmmac_priv *priv = netdev_priv(dev); 132 struct phy_device *phy = priv->phydev; 133 int rc; 134 135 spin_lock(&priv->lock); 136 rc = phy_ethtool_sset(phy, cmd); 137 spin_unlock(&priv->lock); 138 139 return rc; 140} 141 142u32 stmmac_ethtool_getmsglevel(struct net_device *dev) 143{ 144 struct stmmac_priv *priv = netdev_priv(dev); 145 return priv->msg_enable; 146} 147 148void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level) 149{ 150 struct stmmac_priv *priv = netdev_priv(dev); 151 priv->msg_enable = level; 152 153} 154 155int stmmac_check_if_running(struct net_device *dev) 156{ 157 if (!netif_running(dev)) 158 return -EBUSY; 159 return 0; 160} 161 162int stmmac_ethtool_get_regs_len(struct net_device *dev) 163{ 164 return REG_SPACE_SIZE; 165} 166 167void stmmac_ethtool_gregs(struct net_device *dev, 168 struct ethtool_regs *regs, void *space) 169{ 170 int i; 171 u32 *reg_space = (u32 *) space; 172 173 struct stmmac_priv *priv = netdev_priv(dev); 174 175 memset(reg_space, 0x0, REG_SPACE_SIZE); 176 177 if (!priv->is_gmac) { 178 /* MAC registers */ 179 for (i = 0; i < 12; i++) 180 reg_space[i] = readl(dev->base_addr + (i * 4)); 181 /* DMA registers */ 182 for (i = 0; i < 9; i++) 183 reg_space[i + 12] = 184 readl(dev->base_addr + (DMA_BUS_MODE + (i * 4))); 185 reg_space[22] = readl(dev->base_addr + DMA_CUR_TX_BUF_ADDR); 186 reg_space[23] = readl(dev->base_addr + DMA_CUR_RX_BUF_ADDR); 187 } else { 188 /* MAC registers */ 189 for (i = 0; i < 55; i++) 190 reg_space[i] = readl(dev->base_addr + (i * 4)); 191 /* DMA registers */ 192 for (i = 0; i < 22; i++) 193 reg_space[i + 55] = 194 readl(dev->base_addr + (DMA_BUS_MODE + (i * 4))); 195 } 196} 197 198int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data) 199{ 200 if (data) 201 netdev->features |= NETIF_F_HW_CSUM; 202 else 203 netdev->features &= ~NETIF_F_HW_CSUM; 204 205 return 0; 206} 207 208u32 stmmac_ethtool_get_rx_csum(struct net_device *dev) 209{ 210 struct stmmac_priv *priv = netdev_priv(dev); 211 212 return priv->rx_csum; 213} 214 215static void 216stmmac_get_pauseparam(struct net_device *netdev, 217 struct ethtool_pauseparam *pause) 218{ 219 struct stmmac_priv *priv = netdev_priv(netdev); 220 221 spin_lock(&priv->lock); 222 223 pause->rx_pause = 0; 224 pause->tx_pause = 0; 225 pause->autoneg = priv->phydev->autoneg; 226 227 if (priv->flow_ctrl & FLOW_RX) 228 pause->rx_pause = 1; 229 if (priv->flow_ctrl & FLOW_TX) 230 pause->tx_pause = 1; 231 232 spin_unlock(&priv->lock); 233} 234 235static int 236stmmac_set_pauseparam(struct net_device *netdev, 237 struct ethtool_pauseparam *pause) 238{ 239 struct stmmac_priv *priv = netdev_priv(netdev); 240 struct phy_device *phy = priv->phydev; 241 int new_pause = FLOW_OFF; 242 int ret = 0; 243 244 spin_lock(&priv->lock); 245 246 if (pause->rx_pause) 247 new_pause |= FLOW_RX; 248 if (pause->tx_pause) 249 new_pause |= FLOW_TX; 250 251 priv->flow_ctrl = new_pause; 252 253 if (phy->autoneg) { 254 if (netif_running(netdev)) { 255 struct ethtool_cmd cmd; 256 /* auto-negotiation automatically restarted */ 257 cmd.cmd = ETHTOOL_NWAY_RST; 258 cmd.supported = phy->supported; 259 cmd.advertising = phy->advertising; 260 cmd.autoneg = phy->autoneg; 261 cmd.speed = phy->speed; 262 cmd.duplex = phy->duplex; 263 cmd.phy_address = phy->addr; 264 ret = phy_ethtool_sset(phy, &cmd); 265 } 266 } else { 267 unsigned long ioaddr = netdev->base_addr; 268 priv->hw->mac->flow_ctrl(ioaddr, phy->duplex, 269 priv->flow_ctrl, priv->pause); 270 } 271 spin_unlock(&priv->lock); 272 return ret; 273} 274 275static void stmmac_get_ethtool_stats(struct net_device *dev, 276 struct ethtool_stats *dummy, u64 *data) 277{ 278 struct stmmac_priv *priv = netdev_priv(dev); 279 unsigned long ioaddr = dev->base_addr; 280 int i; 281 282 /* Update HW stats if supported */ 283 priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats, 284 ioaddr); 285 286 for (i = 0; i < STMMAC_STATS_LEN; i++) { 287 char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset; 288 data[i] = (stmmac_gstrings_stats[i].sizeof_stat == 289 sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); 290 } 291} 292 293static int stmmac_get_sset_count(struct net_device *netdev, int sset) 294{ 295 switch (sset) { 296 case ETH_SS_STATS: 297 return STMMAC_STATS_LEN; 298 default: 299 return -EOPNOTSUPP; 300 } 301} 302 303static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) 304{ 305 int i; 306 u8 *p = data; 307 308 switch (stringset) { 309 case ETH_SS_STATS: 310 for (i = 0; i < STMMAC_STATS_LEN; i++) { 311 memcpy(p, stmmac_gstrings_stats[i].stat_string, 312 ETH_GSTRING_LEN); 313 p += ETH_GSTRING_LEN; 314 } 315 break; 316 default: 317 WARN_ON(1); 318 break; 319 } 320} 321 322/* Currently only support WOL through Magic packet. */ 323static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 324{ 325 struct stmmac_priv *priv = netdev_priv(dev); 326 327 spin_lock_irq(&priv->lock); 328 if (priv->wolenabled == PMT_SUPPORTED) { 329 wol->supported = WAKE_MAGIC; 330 wol->wolopts = priv->wolopts; 331 } 332 spin_unlock_irq(&priv->lock); 333} 334 335static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 336{ 337 struct stmmac_priv *priv = netdev_priv(dev); 338 u32 support = WAKE_MAGIC; 339 340 if (priv->wolenabled == PMT_NOT_SUPPORTED) 341 return -EINVAL; 342 343 if (wol->wolopts & ~support) 344 return -EINVAL; 345 346 if (wol->wolopts == 0) 347 device_set_wakeup_enable(priv->device, 0); 348 else 349 device_set_wakeup_enable(priv->device, 1); 350 351 spin_lock_irq(&priv->lock); 352 priv->wolopts = wol->wolopts; 353 spin_unlock_irq(&priv->lock); 354 355 return 0; 356} 357 358static struct ethtool_ops stmmac_ethtool_ops = { 359 .begin = stmmac_check_if_running, 360 .get_drvinfo = stmmac_ethtool_getdrvinfo, 361 .get_settings = stmmac_ethtool_getsettings, 362 .set_settings = stmmac_ethtool_setsettings, 363 .get_msglevel = stmmac_ethtool_getmsglevel, 364 .set_msglevel = stmmac_ethtool_setmsglevel, 365 .get_regs = stmmac_ethtool_gregs, 366 .get_regs_len = stmmac_ethtool_get_regs_len, 367 .get_link = ethtool_op_get_link, 368 .get_rx_csum = stmmac_ethtool_get_rx_csum, 369 .get_tx_csum = ethtool_op_get_tx_csum, 370 .set_tx_csum = stmmac_ethtool_set_tx_csum, 371 .get_sg = ethtool_op_get_sg, 372 .set_sg = ethtool_op_set_sg, 373 .get_pauseparam = stmmac_get_pauseparam, 374 .set_pauseparam = stmmac_set_pauseparam, 375 .get_ethtool_stats = stmmac_get_ethtool_stats, 376 .get_strings = stmmac_get_strings, 377 .get_wol = stmmac_get_wol, 378 .set_wol = stmmac_set_wol, 379 .get_sset_count = stmmac_get_sset_count, 380#ifdef NETIF_F_TSO 381 .get_tso = ethtool_op_get_tso, 382 .set_tso = ethtool_op_set_tso, 383#endif 384}; 385 386void stmmac_set_ethtool_ops(struct net_device *netdev) 387{ 388 SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops); 389} 390