| /* |
| * Copyright (c) 2017, Mellanox Technologies. All rights reserved. |
| * |
| * This software is available to you under a choice of one of two |
| * licenses. You may choose to be licensed under the terms of the GNU |
| * General Public License (GPL) Version 2, available from the file |
| * COPYING in the main directory of this source tree, or the |
| * OpenIB.org BSD license below: |
| * |
| * Redistribution and use in source and binary forms, with or |
| * without modification, are permitted provided that the following |
| * conditions are met: |
| * |
| * - Redistributions of source code must retain the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials |
| * provided with the distribution. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| #include "en.h" |
| #include "ipoib.h" |
| |
| static void mlx5i_get_drvinfo(struct net_device *dev, |
| struct ethtool_drvinfo *drvinfo) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| mlx5e_ethtool_get_drvinfo(priv, drvinfo); |
| strlcpy(drvinfo->driver, KBUILD_MODNAME "[ib_ipoib]", |
| sizeof(drvinfo->driver)); |
| } |
| |
| static void mlx5i_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| mlx5e_ethtool_get_strings(priv, stringset, data); |
| } |
| |
| static int mlx5i_get_sset_count(struct net_device *dev, int sset) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| return mlx5e_ethtool_get_sset_count(priv, sset); |
| } |
| |
| static void mlx5i_get_ethtool_stats(struct net_device *dev, |
| struct ethtool_stats *stats, |
| u64 *data) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| mlx5e_ethtool_get_ethtool_stats(priv, stats, data); |
| } |
| |
| static int mlx5i_set_ringparam(struct net_device *dev, |
| struct ethtool_ringparam *param) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| return mlx5e_ethtool_set_ringparam(priv, param); |
| } |
| |
| static void mlx5i_get_ringparam(struct net_device *dev, |
| struct ethtool_ringparam *param) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| mlx5e_ethtool_get_ringparam(priv, param); |
| } |
| |
| static int mlx5i_set_channels(struct net_device *dev, |
| struct ethtool_channels *ch) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| return mlx5e_ethtool_set_channels(priv, ch); |
| } |
| |
| static void mlx5i_get_channels(struct net_device *dev, |
| struct ethtool_channels *ch) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(dev); |
| |
| mlx5e_ethtool_get_channels(priv, ch); |
| } |
| |
| static int mlx5i_set_coalesce(struct net_device *netdev, |
| struct ethtool_coalesce *coal) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(netdev); |
| |
| return mlx5e_ethtool_set_coalesce(priv, coal); |
| } |
| |
| static int mlx5i_get_coalesce(struct net_device *netdev, |
| struct ethtool_coalesce *coal) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(netdev); |
| |
| return mlx5e_ethtool_get_coalesce(priv, coal); |
| } |
| |
| static int mlx5i_get_ts_info(struct net_device *netdev, |
| struct ethtool_ts_info *info) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(netdev); |
| |
| return mlx5e_ethtool_get_ts_info(priv, info); |
| } |
| |
| static int mlx5i_flash_device(struct net_device *netdev, |
| struct ethtool_flash *flash) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(netdev); |
| |
| return mlx5e_ethtool_flash_device(priv, flash); |
| } |
| |
| static inline int mlx5_ptys_width_enum_to_int(enum mlx5_ptys_width width) |
| { |
| switch (width) { |
| case MLX5_PTYS_WIDTH_1X: return 1; |
| case MLX5_PTYS_WIDTH_2X: return 2; |
| case MLX5_PTYS_WIDTH_4X: return 4; |
| case MLX5_PTYS_WIDTH_8X: return 8; |
| case MLX5_PTYS_WIDTH_12X: return 12; |
| default: return -1; |
| } |
| } |
| |
| enum mlx5_ptys_rate { |
| MLX5_PTYS_RATE_SDR = 1 << 0, |
| MLX5_PTYS_RATE_DDR = 1 << 1, |
| MLX5_PTYS_RATE_QDR = 1 << 2, |
| MLX5_PTYS_RATE_FDR10 = 1 << 3, |
| MLX5_PTYS_RATE_FDR = 1 << 4, |
| MLX5_PTYS_RATE_EDR = 1 << 5, |
| MLX5_PTYS_RATE_HDR = 1 << 6, |
| MLX5_PTYS_RATE_NDR = 1 << 7, |
| }; |
| |
| static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate) |
| { |
| switch (rate) { |
| case MLX5_PTYS_RATE_SDR: return 2500; |
| case MLX5_PTYS_RATE_DDR: return 5000; |
| case MLX5_PTYS_RATE_QDR: |
| case MLX5_PTYS_RATE_FDR10: return 10000; |
| case MLX5_PTYS_RATE_FDR: return 14000; |
| case MLX5_PTYS_RATE_EDR: return 25000; |
| case MLX5_PTYS_RATE_HDR: return 50000; |
| case MLX5_PTYS_RATE_NDR: return 100000; |
| default: return -1; |
| } |
| } |
| |
| static int mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper) |
| { |
| int rate, width; |
| |
| rate = mlx5_ptys_rate_enum_to_int(ib_proto_oper); |
| if (rate < 0) |
| return -EINVAL; |
| width = mlx5_ptys_width_enum_to_int(ib_link_width_oper); |
| if (width < 0) |
| return -EINVAL; |
| |
| return rate * width; |
| } |
| |
| static int mlx5i_get_link_ksettings(struct net_device *netdev, |
| struct ethtool_link_ksettings *link_ksettings) |
| { |
| struct mlx5e_priv *priv = mlx5i_epriv(netdev); |
| struct mlx5_core_dev *mdev = priv->mdev; |
| u16 ib_link_width_oper; |
| u16 ib_proto_oper; |
| int speed, ret; |
| |
| ret = mlx5_query_ib_port_oper(mdev, &ib_link_width_oper, &ib_proto_oper, |
| 1); |
| if (ret) |
| return ret; |
| |
| ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); |
| ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); |
| |
| speed = mlx5i_get_speed_settings(ib_link_width_oper, ib_proto_oper); |
| if (speed < 0) |
| return -EINVAL; |
| |
| link_ksettings->base.duplex = DUPLEX_FULL; |
| link_ksettings->base.port = PORT_OTHER; |
| |
| link_ksettings->base.autoneg = AUTONEG_DISABLE; |
| |
| link_ksettings->base.speed = speed; |
| |
| return 0; |
| } |
| |
| const struct ethtool_ops mlx5i_ethtool_ops = { |
| .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
| ETHTOOL_COALESCE_MAX_FRAMES | |
| ETHTOOL_COALESCE_USE_ADAPTIVE, |
| .get_drvinfo = mlx5i_get_drvinfo, |
| .get_strings = mlx5i_get_strings, |
| .get_sset_count = mlx5i_get_sset_count, |
| .get_ethtool_stats = mlx5i_get_ethtool_stats, |
| .get_ringparam = mlx5i_get_ringparam, |
| .set_ringparam = mlx5i_set_ringparam, |
| .flash_device = mlx5i_flash_device, |
| .get_channels = mlx5i_get_channels, |
| .set_channels = mlx5i_set_channels, |
| .get_coalesce = mlx5i_get_coalesce, |
| .set_coalesce = mlx5i_set_coalesce, |
| .get_ts_info = mlx5i_get_ts_info, |
| .get_link_ksettings = mlx5i_get_link_ksettings, |
| .get_link = ethtool_op_get_link, |
| }; |
| |
| const struct ethtool_ops mlx5i_pkey_ethtool_ops = { |
| .get_drvinfo = mlx5i_get_drvinfo, |
| .get_link = ethtool_op_get_link, |
| .get_ts_info = mlx5i_get_ts_info, |
| }; |