Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  */
0032 
0033 #include <linux/kernel.h>
0034 #include <linux/ethtool.h>
0035 #include <linux/netdevice.h>
0036 
0037 #include "ipoib.h"
0038 
0039 struct ipoib_stats {
0040     char stat_string[ETH_GSTRING_LEN];
0041     int stat_offset;
0042 };
0043 
0044 #define IPOIB_NETDEV_STAT(m) { \
0045         .stat_string = #m, \
0046         .stat_offset = offsetof(struct rtnl_link_stats64, m) }
0047 
0048 static const struct ipoib_stats ipoib_gstrings_stats[] = {
0049     IPOIB_NETDEV_STAT(rx_packets),
0050     IPOIB_NETDEV_STAT(tx_packets),
0051     IPOIB_NETDEV_STAT(rx_bytes),
0052     IPOIB_NETDEV_STAT(tx_bytes),
0053     IPOIB_NETDEV_STAT(tx_errors),
0054     IPOIB_NETDEV_STAT(rx_dropped),
0055     IPOIB_NETDEV_STAT(tx_dropped),
0056     IPOIB_NETDEV_STAT(multicast),
0057 };
0058 
0059 #define IPOIB_GLOBAL_STATS_LEN  ARRAY_SIZE(ipoib_gstrings_stats)
0060 
0061 static void ipoib_get_drvinfo(struct net_device *netdev,
0062                   struct ethtool_drvinfo *drvinfo)
0063 {
0064     struct ipoib_dev_priv *priv = ipoib_priv(netdev);
0065 
0066     ib_get_device_fw_str(priv->ca, drvinfo->fw_version);
0067 
0068     strlcpy(drvinfo->bus_info, dev_name(priv->ca->dev.parent),
0069         sizeof(drvinfo->bus_info));
0070 
0071     strlcpy(drvinfo->driver, "ib_ipoib", sizeof(drvinfo->driver));
0072 }
0073 
0074 static int ipoib_get_coalesce(struct net_device *dev,
0075                   struct ethtool_coalesce *coal,
0076                   struct kernel_ethtool_coalesce *kernel_coal,
0077                   struct netlink_ext_ack *extack)
0078 {
0079     struct ipoib_dev_priv *priv = ipoib_priv(dev);
0080 
0081     coal->rx_coalesce_usecs = priv->ethtool.coalesce_usecs;
0082     coal->rx_max_coalesced_frames = priv->ethtool.max_coalesced_frames;
0083 
0084     return 0;
0085 }
0086 
0087 static int ipoib_set_coalesce(struct net_device *dev,
0088                   struct ethtool_coalesce *coal,
0089                   struct kernel_ethtool_coalesce *kernel_coal,
0090                   struct netlink_ext_ack *extack)
0091 {
0092     struct ipoib_dev_priv *priv = ipoib_priv(dev);
0093     int ret;
0094 
0095     /*
0096      * These values are saved in the private data and returned
0097      * when ipoib_get_coalesce() is called
0098      */
0099     if (coal->rx_coalesce_usecs       > 0xffff ||
0100         coal->rx_max_coalesced_frames > 0xffff)
0101         return -EINVAL;
0102 
0103     ret = rdma_set_cq_moderation(priv->recv_cq,
0104                      coal->rx_max_coalesced_frames,
0105                      coal->rx_coalesce_usecs);
0106     if (ret && ret != -EOPNOTSUPP) {
0107         ipoib_warn(priv, "failed modifying CQ (%d)\n", ret);
0108         return ret;
0109     }
0110 
0111     priv->ethtool.coalesce_usecs       = coal->rx_coalesce_usecs;
0112     priv->ethtool.max_coalesced_frames = coal->rx_max_coalesced_frames;
0113 
0114     return 0;
0115 }
0116 static void ipoib_get_ethtool_stats(struct net_device *dev,
0117                     struct ethtool_stats __always_unused *stats,
0118                     u64 *data)
0119 {
0120     int i;
0121     struct net_device_stats *net_stats = &dev->stats;
0122     u8 *p = (u8 *)net_stats;
0123 
0124     for (i = 0; i < IPOIB_GLOBAL_STATS_LEN; i++)
0125         data[i] = *(u64 *)(p + ipoib_gstrings_stats[i].stat_offset);
0126 
0127 }
0128 static void ipoib_get_strings(struct net_device __always_unused *dev,
0129                   u32 stringset, u8 *data)
0130 {
0131     u8 *p = data;
0132     int i;
0133 
0134     switch (stringset) {
0135     case ETH_SS_STATS:
0136         for (i = 0; i < IPOIB_GLOBAL_STATS_LEN; i++) {
0137             memcpy(p, ipoib_gstrings_stats[i].stat_string,
0138                 ETH_GSTRING_LEN);
0139             p += ETH_GSTRING_LEN;
0140         }
0141         break;
0142     default:
0143         break;
0144     }
0145 }
0146 static int ipoib_get_sset_count(struct net_device __always_unused *dev,
0147                  int sset)
0148 {
0149     switch (sset) {
0150     case ETH_SS_STATS:
0151         return IPOIB_GLOBAL_STATS_LEN;
0152     default:
0153         break;
0154     }
0155     return -EOPNOTSUPP;
0156 }
0157 
0158 /* Return lane speed in unit of 1e6 bit/sec */
0159 static inline int ib_speed_enum_to_int(int speed)
0160 {
0161     switch (speed) {
0162     case IB_SPEED_SDR:
0163         return SPEED_2500;
0164     case IB_SPEED_DDR:
0165         return SPEED_5000;
0166     case IB_SPEED_QDR:
0167     case IB_SPEED_FDR10:
0168         return SPEED_10000;
0169     case IB_SPEED_FDR:
0170         return SPEED_14000;
0171     case IB_SPEED_EDR:
0172         return SPEED_25000;
0173     case IB_SPEED_HDR:
0174         return SPEED_50000;
0175     case IB_SPEED_NDR:
0176         return SPEED_100000;
0177     }
0178 
0179     return SPEED_UNKNOWN;
0180 }
0181 
0182 static int ipoib_get_link_ksettings(struct net_device *netdev,
0183                     struct ethtool_link_ksettings *cmd)
0184 {
0185     struct ipoib_dev_priv *priv = ipoib_priv(netdev);
0186     struct ib_port_attr attr;
0187     int ret, speed, width;
0188 
0189     if (!netif_carrier_ok(netdev)) {
0190         cmd->base.speed = SPEED_UNKNOWN;
0191         cmd->base.duplex = DUPLEX_UNKNOWN;
0192         return 0;
0193     }
0194 
0195     ret = ib_query_port(priv->ca, priv->port, &attr);
0196     if (ret < 0)
0197         return -EINVAL;
0198 
0199     speed = ib_speed_enum_to_int(attr.active_speed);
0200     width = ib_width_enum_to_int(attr.active_width);
0201 
0202     if (speed < 0 || width < 0)
0203         return -EINVAL;
0204 
0205     /* Except the following are set, the other members of
0206      * the struct ethtool_link_settings are initialized to
0207      * zero in the function __ethtool_get_link_ksettings.
0208      */
0209     cmd->base.speed      = speed * width;
0210     cmd->base.duplex     = DUPLEX_FULL;
0211 
0212     cmd->base.phy_address    = 0xFF;
0213 
0214     cmd->base.autoneg    = AUTONEG_ENABLE;
0215     cmd->base.port       = PORT_OTHER;
0216 
0217     return 0;
0218 }
0219 
0220 static const struct ethtool_ops ipoib_ethtool_ops = {
0221     .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
0222                      ETHTOOL_COALESCE_RX_MAX_FRAMES,
0223     .get_link_ksettings = ipoib_get_link_ksettings,
0224     .get_drvinfo        = ipoib_get_drvinfo,
0225     .get_coalesce       = ipoib_get_coalesce,
0226     .set_coalesce       = ipoib_set_coalesce,
0227     .get_strings        = ipoib_get_strings,
0228     .get_ethtool_stats  = ipoib_get_ethtool_stats,
0229     .get_sset_count     = ipoib_get_sset_count,
0230     .get_link       = ethtool_op_get_link,
0231 };
0232 
0233 void ipoib_set_ethtool_ops(struct net_device *dev)
0234 {
0235     dev->ethtool_ops = &ipoib_ethtool_ops;
0236 }