root/drivers/net/ethernet/atheros/alx/ethtool.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. alx_get_supported_speeds
  2. alx_get_link_ksettings
  3. alx_set_link_ksettings
  4. alx_get_pauseparam
  5. alx_set_pauseparam
  6. alx_get_msglevel
  7. alx_set_msglevel
  8. alx_get_ethtool_stats
  9. alx_get_strings
  10. alx_get_sset_count

   1 /*
   2  * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
   3  *
   4  *  This file is free software: you may copy, redistribute and/or modify it
   5  *  under the terms of the GNU General Public License as published by the
   6  *  Free Software Foundation, either version 2 of the License, or (at your
   7  *  option) any later version.
   8  *
   9  *  This file is distributed in the hope that it will be useful, but
  10  *  WITHOUT ANY WARRANTY; without even the implied warranty of
  11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  *  General Public License for more details.
  13  *
  14  *  You should have received a copy of the GNU General Public License
  15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16  *
  17  * This file incorporates work covered by the following copyright and
  18  * permission notice:
  19  *
  20  * Copyright (c) 2012 Qualcomm Atheros, Inc.
  21  *
  22  * Permission to use, copy, modify, and/or distribute this software for any
  23  * purpose with or without fee is hereby granted, provided that the above
  24  * copyright notice and this permission notice appear in all copies.
  25  *
  26  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  27  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  28  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  29  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  30  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  31  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  32  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33  */
  34 
  35 #include <linux/pci.h>
  36 #include <linux/ip.h>
  37 #include <linux/tcp.h>
  38 #include <linux/netdevice.h>
  39 #include <linux/etherdevice.h>
  40 #include <linux/ethtool.h>
  41 #include <linux/mdio.h>
  42 #include <linux/interrupt.h>
  43 #include <asm/byteorder.h>
  44 
  45 #include "alx.h"
  46 #include "reg.h"
  47 #include "hw.h"
  48 
  49 /* The order of these strings must match the order of the fields in
  50  * struct alx_hw_stats
  51  * See hw.h
  52  */
  53 static const char alx_gstrings_stats[][ETH_GSTRING_LEN] = {
  54         "rx_packets",
  55         "rx_bcast_packets",
  56         "rx_mcast_packets",
  57         "rx_pause_packets",
  58         "rx_ctrl_packets",
  59         "rx_fcs_errors",
  60         "rx_length_errors",
  61         "rx_bytes",
  62         "rx_runt_packets",
  63         "rx_fragments",
  64         "rx_64B_or_less_packets",
  65         "rx_65B_to_127B_packets",
  66         "rx_128B_to_255B_packets",
  67         "rx_256B_to_511B_packets",
  68         "rx_512B_to_1023B_packets",
  69         "rx_1024B_to_1518B_packets",
  70         "rx_1519B_to_mtu_packets",
  71         "rx_oversize_packets",
  72         "rx_rxf_ov_drop_packets",
  73         "rx_rrd_ov_drop_packets",
  74         "rx_align_errors",
  75         "rx_bcast_bytes",
  76         "rx_mcast_bytes",
  77         "rx_address_errors",
  78         "tx_packets",
  79         "tx_bcast_packets",
  80         "tx_mcast_packets",
  81         "tx_pause_packets",
  82         "tx_exc_defer_packets",
  83         "tx_ctrl_packets",
  84         "tx_defer_packets",
  85         "tx_bytes",
  86         "tx_64B_or_less_packets",
  87         "tx_65B_to_127B_packets",
  88         "tx_128B_to_255B_packets",
  89         "tx_256B_to_511B_packets",
  90         "tx_512B_to_1023B_packets",
  91         "tx_1024B_to_1518B_packets",
  92         "tx_1519B_to_mtu_packets",
  93         "tx_single_collision",
  94         "tx_multiple_collisions",
  95         "tx_late_collision",
  96         "tx_abort_collision",
  97         "tx_underrun",
  98         "tx_trd_eop",
  99         "tx_length_errors",
 100         "tx_trunc_packets",
 101         "tx_bcast_bytes",
 102         "tx_mcast_bytes",
 103         "tx_update",
 104 };
 105 
 106 #define ALX_NUM_STATS ARRAY_SIZE(alx_gstrings_stats)
 107 
 108 
 109 static u32 alx_get_supported_speeds(struct alx_hw *hw)
 110 {
 111         u32 supported = SUPPORTED_10baseT_Half |
 112                         SUPPORTED_10baseT_Full |
 113                         SUPPORTED_100baseT_Half |
 114                         SUPPORTED_100baseT_Full;
 115 
 116         if (alx_hw_giga(hw))
 117                 supported |= SUPPORTED_1000baseT_Full;
 118 
 119         BUILD_BUG_ON(SUPPORTED_10baseT_Half != ADVERTISED_10baseT_Half);
 120         BUILD_BUG_ON(SUPPORTED_10baseT_Full != ADVERTISED_10baseT_Full);
 121         BUILD_BUG_ON(SUPPORTED_100baseT_Half != ADVERTISED_100baseT_Half);
 122         BUILD_BUG_ON(SUPPORTED_100baseT_Full != ADVERTISED_100baseT_Full);
 123         BUILD_BUG_ON(SUPPORTED_1000baseT_Full != ADVERTISED_1000baseT_Full);
 124 
 125         return supported;
 126 }
 127 
 128 static int alx_get_link_ksettings(struct net_device *netdev,
 129                                   struct ethtool_link_ksettings *cmd)
 130 {
 131         struct alx_priv *alx = netdev_priv(netdev);
 132         struct alx_hw *hw = &alx->hw;
 133         u32 supported, advertising;
 134 
 135         supported = SUPPORTED_Autoneg |
 136                           SUPPORTED_TP |
 137                           SUPPORTED_Pause |
 138                           SUPPORTED_Asym_Pause;
 139         if (alx_hw_giga(hw))
 140                 supported |= SUPPORTED_1000baseT_Full;
 141         supported |= alx_get_supported_speeds(hw);
 142 
 143         advertising = ADVERTISED_TP;
 144         if (hw->adv_cfg & ADVERTISED_Autoneg)
 145                 advertising |= hw->adv_cfg;
 146 
 147         cmd->base.port = PORT_TP;
 148         cmd->base.phy_address = 0;
 149 
 150         if (hw->adv_cfg & ADVERTISED_Autoneg)
 151                 cmd->base.autoneg = AUTONEG_ENABLE;
 152         else
 153                 cmd->base.autoneg = AUTONEG_DISABLE;
 154 
 155         if (hw->flowctrl & ALX_FC_ANEG && hw->adv_cfg & ADVERTISED_Autoneg) {
 156                 if (hw->flowctrl & ALX_FC_RX) {
 157                         advertising |= ADVERTISED_Pause;
 158 
 159                         if (!(hw->flowctrl & ALX_FC_TX))
 160                                 advertising |= ADVERTISED_Asym_Pause;
 161                 } else if (hw->flowctrl & ALX_FC_TX) {
 162                         advertising |= ADVERTISED_Asym_Pause;
 163                 }
 164         }
 165 
 166         cmd->base.speed = hw->link_speed;
 167         cmd->base.duplex = hw->duplex;
 168 
 169         ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
 170                                                 supported);
 171         ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
 172                                                 advertising);
 173 
 174         return 0;
 175 }
 176 
 177 static int alx_set_link_ksettings(struct net_device *netdev,
 178                                   const struct ethtool_link_ksettings *cmd)
 179 {
 180         struct alx_priv *alx = netdev_priv(netdev);
 181         struct alx_hw *hw = &alx->hw;
 182         u32 adv_cfg;
 183         u32 advertising;
 184 
 185         ASSERT_RTNL();
 186 
 187         ethtool_convert_link_mode_to_legacy_u32(&advertising,
 188                                                 cmd->link_modes.advertising);
 189 
 190         if (cmd->base.autoneg == AUTONEG_ENABLE) {
 191                 if (advertising & ~alx_get_supported_speeds(hw))
 192                         return -EINVAL;
 193                 adv_cfg = advertising | ADVERTISED_Autoneg;
 194         } else {
 195                 adv_cfg = alx_speed_to_ethadv(cmd->base.speed,
 196                                               cmd->base.duplex);
 197 
 198                 if (!adv_cfg || adv_cfg == ADVERTISED_1000baseT_Full)
 199                         return -EINVAL;
 200         }
 201 
 202         hw->adv_cfg = adv_cfg;
 203         return alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl);
 204 }
 205 
 206 static void alx_get_pauseparam(struct net_device *netdev,
 207                                struct ethtool_pauseparam *pause)
 208 {
 209         struct alx_priv *alx = netdev_priv(netdev);
 210         struct alx_hw *hw = &alx->hw;
 211 
 212         pause->autoneg = !!(hw->flowctrl & ALX_FC_ANEG &&
 213                             hw->adv_cfg & ADVERTISED_Autoneg);
 214         pause->tx_pause = !!(hw->flowctrl & ALX_FC_TX);
 215         pause->rx_pause = !!(hw->flowctrl & ALX_FC_RX);
 216 }
 217 
 218 
 219 static int alx_set_pauseparam(struct net_device *netdev,
 220                               struct ethtool_pauseparam *pause)
 221 {
 222         struct alx_priv *alx = netdev_priv(netdev);
 223         struct alx_hw *hw = &alx->hw;
 224         int err = 0;
 225         bool reconfig_phy = false;
 226         u8 fc = 0;
 227 
 228         if (pause->tx_pause)
 229                 fc |= ALX_FC_TX;
 230         if (pause->rx_pause)
 231                 fc |= ALX_FC_RX;
 232         if (pause->autoneg)
 233                 fc |= ALX_FC_ANEG;
 234 
 235         ASSERT_RTNL();
 236 
 237         /* restart auto-neg for auto-mode */
 238         if (hw->adv_cfg & ADVERTISED_Autoneg) {
 239                 if (!((fc ^ hw->flowctrl) & ALX_FC_ANEG))
 240                         reconfig_phy = true;
 241                 if (fc & hw->flowctrl & ALX_FC_ANEG &&
 242                     (fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX))
 243                         reconfig_phy = true;
 244         }
 245 
 246         if (reconfig_phy) {
 247                 err = alx_setup_speed_duplex(hw, hw->adv_cfg, fc);
 248                 if (err)
 249                         return err;
 250         }
 251 
 252         /* flow control on mac */
 253         if ((fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX))
 254                 alx_cfg_mac_flowcontrol(hw, fc);
 255 
 256         hw->flowctrl = fc;
 257 
 258         return 0;
 259 }
 260 
 261 static u32 alx_get_msglevel(struct net_device *netdev)
 262 {
 263         struct alx_priv *alx = netdev_priv(netdev);
 264 
 265         return alx->msg_enable;
 266 }
 267 
 268 static void alx_set_msglevel(struct net_device *netdev, u32 data)
 269 {
 270         struct alx_priv *alx = netdev_priv(netdev);
 271 
 272         alx->msg_enable = data;
 273 }
 274 
 275 static void alx_get_ethtool_stats(struct net_device *netdev,
 276                                   struct ethtool_stats *estats, u64 *data)
 277 {
 278         struct alx_priv *alx = netdev_priv(netdev);
 279         struct alx_hw *hw = &alx->hw;
 280 
 281         spin_lock(&alx->stats_lock);
 282 
 283         alx_update_hw_stats(hw);
 284         BUILD_BUG_ON(sizeof(hw->stats) - offsetof(struct alx_hw_stats, rx_ok) <
 285                      ALX_NUM_STATS * sizeof(u64));
 286         memcpy(data, &hw->stats.rx_ok, ALX_NUM_STATS * sizeof(u64));
 287 
 288         spin_unlock(&alx->stats_lock);
 289 }
 290 
 291 static void alx_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
 292 {
 293         switch (stringset) {
 294         case ETH_SS_STATS:
 295                 memcpy(buf, &alx_gstrings_stats, sizeof(alx_gstrings_stats));
 296                 break;
 297         default:
 298                 WARN_ON(1);
 299                 break;
 300         }
 301 }
 302 
 303 static int alx_get_sset_count(struct net_device *netdev, int sset)
 304 {
 305         switch (sset) {
 306         case ETH_SS_STATS:
 307                 return ALX_NUM_STATS;
 308         default:
 309                 return -EINVAL;
 310         }
 311 }
 312 
 313 const struct ethtool_ops alx_ethtool_ops = {
 314         .get_pauseparam = alx_get_pauseparam,
 315         .set_pauseparam = alx_set_pauseparam,
 316         .get_msglevel   = alx_get_msglevel,
 317         .set_msglevel   = alx_set_msglevel,
 318         .get_link       = ethtool_op_get_link,
 319         .get_strings    = alx_get_strings,
 320         .get_sset_count = alx_get_sset_count,
 321         .get_ethtool_stats      = alx_get_ethtool_stats,
 322         .get_link_ksettings     = alx_get_link_ksettings,
 323         .set_link_ksettings     = alx_set_link_ksettings,
 324 };

/* [<][>][^][v][top][bottom][index][help] */