linux/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
<<
>>
Prefs
   1/*
   2 * Copyright(c) 2007 Atheros Corporation. All rights reserved.
   3 *
   4 * Derived from Intel e1000 driver
   5 * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published by the Free
   9 * Software Foundation; either version 2 of the License, or (at your option)
  10 * any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15 * more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along with
  18 * this program; if not, write to the Free Software Foundation, Inc., 59
  19 * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20 *
  21 */
  22
  23#include <linux/netdevice.h>
  24#include <linux/ethtool.h>
  25#include <linux/slab.h>
  26
  27#include "atl1e.h"
  28
  29static int atl1e_get_settings(struct net_device *netdev,
  30                              struct ethtool_cmd *ecmd)
  31{
  32        struct atl1e_adapter *adapter = netdev_priv(netdev);
  33        struct atl1e_hw *hw = &adapter->hw;
  34
  35        ecmd->supported = (SUPPORTED_10baseT_Half  |
  36                           SUPPORTED_10baseT_Full  |
  37                           SUPPORTED_100baseT_Half |
  38                           SUPPORTED_100baseT_Full |
  39                           SUPPORTED_Autoneg       |
  40                           SUPPORTED_TP);
  41        if (hw->nic_type == athr_l1e)
  42                ecmd->supported |= SUPPORTED_1000baseT_Full;
  43
  44        ecmd->advertising = ADVERTISED_TP;
  45
  46        ecmd->advertising |= ADVERTISED_Autoneg;
  47        ecmd->advertising |= hw->autoneg_advertised;
  48
  49        ecmd->port = PORT_TP;
  50        ecmd->phy_address = 0;
  51        ecmd->transceiver = XCVR_INTERNAL;
  52
  53        if (adapter->link_speed != SPEED_0) {
  54                ethtool_cmd_speed_set(ecmd, adapter->link_speed);
  55                if (adapter->link_duplex == FULL_DUPLEX)
  56                        ecmd->duplex = DUPLEX_FULL;
  57                else
  58                        ecmd->duplex = DUPLEX_HALF;
  59        } else {
  60                ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
  61                ecmd->duplex = DUPLEX_UNKNOWN;
  62        }
  63
  64        ecmd->autoneg = AUTONEG_ENABLE;
  65        return 0;
  66}
  67
  68static int atl1e_set_settings(struct net_device *netdev,
  69                              struct ethtool_cmd *ecmd)
  70{
  71        struct atl1e_adapter *adapter = netdev_priv(netdev);
  72        struct atl1e_hw *hw = &adapter->hw;
  73
  74        while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
  75                msleep(1);
  76
  77        if (ecmd->autoneg == AUTONEG_ENABLE) {
  78                u16 adv4, adv9;
  79
  80                if ((ecmd->advertising&ADVERTISE_1000_FULL)) {
  81                        if (hw->nic_type == athr_l1e) {
  82                                hw->autoneg_advertised =
  83                                        ecmd->advertising & AT_ADV_MASK;
  84                        } else {
  85                                clear_bit(__AT_RESETTING, &adapter->flags);
  86                                return -EINVAL;
  87                        }
  88                } else if (ecmd->advertising&ADVERTISE_1000_HALF) {
  89                        clear_bit(__AT_RESETTING, &adapter->flags);
  90                        return -EINVAL;
  91                } else {
  92                        hw->autoneg_advertised =
  93                                ecmd->advertising & AT_ADV_MASK;
  94                }
  95                ecmd->advertising = hw->autoneg_advertised |
  96                                    ADVERTISED_TP | ADVERTISED_Autoneg;
  97
  98                adv4 = hw->mii_autoneg_adv_reg & ~ADVERTISE_ALL;
  99                adv9 = hw->mii_1000t_ctrl_reg & ~MII_AT001_CR_1000T_SPEED_MASK;
 100                if (hw->autoneg_advertised & ADVERTISE_10_HALF)
 101                        adv4 |= ADVERTISE_10HALF;
 102                if (hw->autoneg_advertised & ADVERTISE_10_FULL)
 103                        adv4 |= ADVERTISE_10FULL;
 104                if (hw->autoneg_advertised & ADVERTISE_100_HALF)
 105                        adv4 |= ADVERTISE_100HALF;
 106                if (hw->autoneg_advertised & ADVERTISE_100_FULL)
 107                        adv4 |= ADVERTISE_100FULL;
 108                if (hw->autoneg_advertised & ADVERTISE_1000_FULL)
 109                        adv9 |= ADVERTISE_1000FULL;
 110
 111                if (adv4 != hw->mii_autoneg_adv_reg ||
 112                                adv9 != hw->mii_1000t_ctrl_reg) {
 113                        hw->mii_autoneg_adv_reg = adv4;
 114                        hw->mii_1000t_ctrl_reg = adv9;
 115                        hw->re_autoneg = true;
 116                }
 117
 118        } else {
 119                clear_bit(__AT_RESETTING, &adapter->flags);
 120                return -EINVAL;
 121        }
 122
 123        /* reset the link */
 124
 125        if (netif_running(adapter->netdev)) {
 126                atl1e_down(adapter);
 127                atl1e_up(adapter);
 128        } else
 129                atl1e_reset_hw(&adapter->hw);
 130
 131        clear_bit(__AT_RESETTING, &adapter->flags);
 132        return 0;
 133}
 134
 135static u32 atl1e_get_msglevel(struct net_device *netdev)
 136{
 137#ifdef DBG
 138        return 1;
 139#else
 140        return 0;
 141#endif
 142}
 143
 144static int atl1e_get_regs_len(struct net_device *netdev)
 145{
 146        return AT_REGS_LEN * sizeof(u32);
 147}
 148
 149static void atl1e_get_regs(struct net_device *netdev,
 150                           struct ethtool_regs *regs, void *p)
 151{
 152        struct atl1e_adapter *adapter = netdev_priv(netdev);
 153        struct atl1e_hw *hw = &adapter->hw;
 154        u32 *regs_buff = p;
 155        u16 phy_data;
 156
 157        memset(p, 0, AT_REGS_LEN * sizeof(u32));
 158
 159        regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
 160
 161        regs_buff[0]  = AT_READ_REG(hw, REG_VPD_CAP);
 162        regs_buff[1]  = AT_READ_REG(hw, REG_SPI_FLASH_CTRL);
 163        regs_buff[2]  = AT_READ_REG(hw, REG_SPI_FLASH_CONFIG);
 164        regs_buff[3]  = AT_READ_REG(hw, REG_TWSI_CTRL);
 165        regs_buff[4]  = AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL);
 166        regs_buff[5]  = AT_READ_REG(hw, REG_MASTER_CTRL);
 167        regs_buff[6]  = AT_READ_REG(hw, REG_MANUAL_TIMER_INIT);
 168        regs_buff[7]  = AT_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT);
 169        regs_buff[8]  = AT_READ_REG(hw, REG_GPHY_CTRL);
 170        regs_buff[9]  = AT_READ_REG(hw, REG_CMBDISDMA_TIMER);
 171        regs_buff[10] = AT_READ_REG(hw, REG_IDLE_STATUS);
 172        regs_buff[11] = AT_READ_REG(hw, REG_MDIO_CTRL);
 173        regs_buff[12] = AT_READ_REG(hw, REG_SERDES_LOCK);
 174        regs_buff[13] = AT_READ_REG(hw, REG_MAC_CTRL);
 175        regs_buff[14] = AT_READ_REG(hw, REG_MAC_IPG_IFG);
 176        regs_buff[15] = AT_READ_REG(hw, REG_MAC_STA_ADDR);
 177        regs_buff[16] = AT_READ_REG(hw, REG_MAC_STA_ADDR+4);
 178        regs_buff[17] = AT_READ_REG(hw, REG_RX_HASH_TABLE);
 179        regs_buff[18] = AT_READ_REG(hw, REG_RX_HASH_TABLE+4);
 180        regs_buff[19] = AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL);
 181        regs_buff[20] = AT_READ_REG(hw, REG_MTU);
 182        regs_buff[21] = AT_READ_REG(hw, REG_WOL_CTRL);
 183        regs_buff[22] = AT_READ_REG(hw, REG_SRAM_TRD_ADDR);
 184        regs_buff[23] = AT_READ_REG(hw, REG_SRAM_TRD_LEN);
 185        regs_buff[24] = AT_READ_REG(hw, REG_SRAM_RXF_ADDR);
 186        regs_buff[25] = AT_READ_REG(hw, REG_SRAM_RXF_LEN);
 187        regs_buff[26] = AT_READ_REG(hw, REG_SRAM_TXF_ADDR);
 188        regs_buff[27] = AT_READ_REG(hw, REG_SRAM_TXF_LEN);
 189        regs_buff[28] = AT_READ_REG(hw, REG_SRAM_TCPH_ADDR);
 190        regs_buff[29] = AT_READ_REG(hw, REG_SRAM_PKTH_ADDR);
 191
 192        atl1e_read_phy_reg(hw, MII_BMCR, &phy_data);
 193        regs_buff[73] = (u32)phy_data;
 194        atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
 195        regs_buff[74] = (u32)phy_data;
 196}
 197
 198static int atl1e_get_eeprom_len(struct net_device *netdev)
 199{
 200        struct atl1e_adapter *adapter = netdev_priv(netdev);
 201
 202        if (!atl1e_check_eeprom_exist(&adapter->hw))
 203                return AT_EEPROM_LEN;
 204        else
 205                return 0;
 206}
 207
 208static int atl1e_get_eeprom(struct net_device *netdev,
 209                struct ethtool_eeprom *eeprom, u8 *bytes)
 210{
 211        struct atl1e_adapter *adapter = netdev_priv(netdev);
 212        struct atl1e_hw *hw = &adapter->hw;
 213        u32 *eeprom_buff;
 214        int first_dword, last_dword;
 215        int ret_val = 0;
 216        int i;
 217
 218        if (eeprom->len == 0)
 219                return -EINVAL;
 220
 221        if (atl1e_check_eeprom_exist(hw)) /* not exist */
 222                return -EINVAL;
 223
 224        eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 225
 226        first_dword = eeprom->offset >> 2;
 227        last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
 228
 229        eeprom_buff = kmalloc(sizeof(u32) *
 230                        (last_dword - first_dword + 1), GFP_KERNEL);
 231        if (eeprom_buff == NULL)
 232                return -ENOMEM;
 233
 234        for (i = first_dword; i < last_dword; i++) {
 235                if (!atl1e_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) {
 236                        kfree(eeprom_buff);
 237                        return -EIO;
 238                }
 239        }
 240
 241        memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
 242                        eeprom->len);
 243        kfree(eeprom_buff);
 244
 245        return ret_val;
 246}
 247
 248static int atl1e_set_eeprom(struct net_device *netdev,
 249                            struct ethtool_eeprom *eeprom, u8 *bytes)
 250{
 251        struct atl1e_adapter *adapter = netdev_priv(netdev);
 252        struct atl1e_hw *hw = &adapter->hw;
 253        u32 *eeprom_buff;
 254        u32 *ptr;
 255        int first_dword, last_dword;
 256        int ret_val = 0;
 257        int i;
 258
 259        if (eeprom->len == 0)
 260                return -EOPNOTSUPP;
 261
 262        if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
 263                return -EINVAL;
 264
 265        first_dword = eeprom->offset >> 2;
 266        last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
 267        eeprom_buff = kmalloc(AT_EEPROM_LEN, GFP_KERNEL);
 268        if (eeprom_buff == NULL)
 269                return -ENOMEM;
 270
 271        ptr = eeprom_buff;
 272
 273        if (eeprom->offset & 3) {
 274                /* need read/modify/write of first changed EEPROM word */
 275                /* only the second byte of the word is being modified */
 276                if (!atl1e_read_eeprom(hw, first_dword * 4, &(eeprom_buff[0]))) {
 277                        ret_val = -EIO;
 278                        goto out;
 279                }
 280                ptr++;
 281        }
 282        if (((eeprom->offset + eeprom->len) & 3)) {
 283                /* need read/modify/write of last changed EEPROM word */
 284                /* only the first byte of the word is being modified */
 285
 286                if (!atl1e_read_eeprom(hw, last_dword * 4,
 287                                &(eeprom_buff[last_dword - first_dword]))) {
 288                        ret_val = -EIO;
 289                        goto out;
 290                }
 291        }
 292
 293        /* Device's eeprom is always little-endian, word addressable */
 294        memcpy(ptr, bytes, eeprom->len);
 295
 296        for (i = 0; i < last_dword - first_dword + 1; i++) {
 297                if (!atl1e_write_eeprom(hw, ((first_dword + i) * 4),
 298                                  eeprom_buff[i])) {
 299                        ret_val = -EIO;
 300                        goto out;
 301                }
 302        }
 303out:
 304        kfree(eeprom_buff);
 305        return ret_val;
 306}
 307
 308static void atl1e_get_drvinfo(struct net_device *netdev,
 309                struct ethtool_drvinfo *drvinfo)
 310{
 311        struct atl1e_adapter *adapter = netdev_priv(netdev);
 312
 313        strlcpy(drvinfo->driver,  atl1e_driver_name, sizeof(drvinfo->driver));
 314        strlcpy(drvinfo->version, atl1e_driver_version,
 315                sizeof(drvinfo->version));
 316        strlcpy(drvinfo->fw_version, "L1e", sizeof(drvinfo->fw_version));
 317        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
 318                sizeof(drvinfo->bus_info));
 319        drvinfo->n_stats = 0;
 320        drvinfo->testinfo_len = 0;
 321        drvinfo->regdump_len = atl1e_get_regs_len(netdev);
 322        drvinfo->eedump_len = atl1e_get_eeprom_len(netdev);
 323}
 324
 325static void atl1e_get_wol(struct net_device *netdev,
 326                          struct ethtool_wolinfo *wol)
 327{
 328        struct atl1e_adapter *adapter = netdev_priv(netdev);
 329
 330        wol->supported = WAKE_MAGIC | WAKE_PHY;
 331        wol->wolopts = 0;
 332
 333        if (adapter->wol & AT_WUFC_EX)
 334                wol->wolopts |= WAKE_UCAST;
 335        if (adapter->wol & AT_WUFC_MC)
 336                wol->wolopts |= WAKE_MCAST;
 337        if (adapter->wol & AT_WUFC_BC)
 338                wol->wolopts |= WAKE_BCAST;
 339        if (adapter->wol & AT_WUFC_MAG)
 340                wol->wolopts |= WAKE_MAGIC;
 341        if (adapter->wol & AT_WUFC_LNKC)
 342                wol->wolopts |= WAKE_PHY;
 343}
 344
 345static int atl1e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 346{
 347        struct atl1e_adapter *adapter = netdev_priv(netdev);
 348
 349        if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
 350                            WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
 351                return -EOPNOTSUPP;
 352        /* these settings will always override what we currently have */
 353        adapter->wol = 0;
 354
 355        if (wol->wolopts & WAKE_MAGIC)
 356                adapter->wol |= AT_WUFC_MAG;
 357        if (wol->wolopts & WAKE_PHY)
 358                adapter->wol |= AT_WUFC_LNKC;
 359
 360        device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 361
 362        return 0;
 363}
 364
 365static int atl1e_nway_reset(struct net_device *netdev)
 366{
 367        struct atl1e_adapter *adapter = netdev_priv(netdev);
 368        if (netif_running(netdev))
 369                atl1e_reinit_locked(adapter);
 370        return 0;
 371}
 372
 373static const struct ethtool_ops atl1e_ethtool_ops = {
 374        .get_settings           = atl1e_get_settings,
 375        .set_settings           = atl1e_set_settings,
 376        .get_drvinfo            = atl1e_get_drvinfo,
 377        .get_regs_len           = atl1e_get_regs_len,
 378        .get_regs               = atl1e_get_regs,
 379        .get_wol                = atl1e_get_wol,
 380        .set_wol                = atl1e_set_wol,
 381        .get_msglevel           = atl1e_get_msglevel,
 382        .nway_reset             = atl1e_nway_reset,
 383        .get_link               = ethtool_op_get_link,
 384        .get_eeprom_len         = atl1e_get_eeprom_len,
 385        .get_eeprom             = atl1e_get_eeprom,
 386        .set_eeprom             = atl1e_set_eeprom,
 387};
 388
 389void atl1e_set_ethtool_ops(struct net_device *netdev)
 390{
 391        netdev->ethtool_ops = &atl1e_ethtool_ops;
 392}
 393