116359Sasami/*
256711Snyan * Copyright (c) 2017, Mellanox Technologies. All rights reserved.
316359Sasami *
450518Snyan * This software is available to you under a choice of one of two
550518Snyan * licenses.  You may choose to be licensed under the terms of the GNU
616359Sasami * General Public License (GPL) Version 2, available from the file
760717Snyan * COPYING in the main directory of this source tree, or the
850518Snyan * OpenIB.org BSD license below:
950518Snyan *
1050518Snyan *     Redistribution and use in source and binary forms, with or
1160717Snyan *     without modification, are permitted provided that the following
1250518Snyan *     conditions are met:
1350518Snyan *
1450518Snyan *      - Redistributions of source code must retain the above
1550518Snyan *        copyright notice, this list of conditions and the following
1617973Sasami *        disclaimer.
1717973Sasami *
1850477Speter *      - Redistributions in binary form must reproduce the above
1916359Sasami *        copyright notice, this list of conditions and the following
2046044Skato *        disclaimer in the documentation and/or other materials
2146044Skato *        provided with the distribution.
2246044Skato *
2346044Skato * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2446044Skato * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2560027Snyan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2638832Skato * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2716359Sasami * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2861640Speter * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2961640Speter * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3046044Skato * SOFTWARE.
3145783Skato */
3250518Snyan
3350518Snyan#include "en.h"
3450518Snyan#include "ipoib.h"
3557655Skato#include "en/fs_ethtool.h"
3650518Snyan
3750518Snyanstatic void mlx5i_get_drvinfo(struct net_device *dev,
3862198Skato			      struct ethtool_drvinfo *drvinfo)
3954877Skato{
4053744Snyan	struct mlx5e_priv *priv = mlx5i_epriv(dev);
4150518Snyan
4256533Skato	mlx5e_ethtool_get_drvinfo(priv, drvinfo);
4350518Snyan	strscpy(drvinfo->driver, KBUILD_MODNAME "[ib_ipoib]",
4450518Snyan		sizeof(drvinfo->driver));
4556533Skato}
4650518Snyan
4750518Snyanstatic void mlx5i_get_strings(struct net_device *dev, u32 stringset, u8 *data)
4856711Snyan{
4950518Snyan	struct mlx5e_priv *priv  = mlx5i_epriv(dev);
5050518Snyan
5150518Snyan	mlx5e_ethtool_get_strings(priv, stringset, data);
5250518Snyan}
5350518Snyan
5450518Snyanstatic int mlx5i_get_sset_count(struct net_device *dev, int sset)
5556533Skato{
5652833Snyan	struct mlx5e_priv *priv = mlx5i_epriv(dev);
5752833Snyan
5856327Snyan	return mlx5e_ethtool_get_sset_count(priv, sset);
5959530Snyan}
6056323Skato
6160717Snyanstatic void mlx5i_get_ethtool_stats(struct net_device *dev,
6262198Skato				    struct ethtool_stats *stats,
6318846Sasami				    u64 *data)
6442157Skato{
6550518Snyan	struct mlx5e_priv *priv = mlx5i_epriv(dev);
6650518Snyan
6742157Skato	mlx5e_ethtool_get_ethtool_stats(priv, stats, data);
6850518Snyan}
6950518Snyan
7050518Snyanstatic int mlx5i_set_ringparam(struct net_device *dev,
7150518Snyan			       struct ethtool_ringparam *param,
7242157Skato			       struct kernel_ethtool_ringparam *kernel_param,
7356442Speter			       struct netlink_ext_ack *extack)
7456442Speter{
7558290Skato	struct mlx5e_priv *priv = mlx5i_epriv(dev);
7658290Skato
7716359Sasami	return mlx5e_ethtool_set_ringparam(priv, param);
7850518Snyan}
7961640Speter
8016359Sasamistatic void mlx5i_get_ringparam(struct net_device *dev,
8150518Snyan				struct ethtool_ringparam *param,
8261640Speter				struct kernel_ethtool_ringparam *kernel_param,
8316359Sasami				struct netlink_ext_ack *extack)
8456516Speter{
8556442Speter	struct mlx5e_priv *priv = mlx5i_epriv(dev);
8656442Speter
8756442Speter	mlx5e_ethtool_get_ringparam(priv, param, kernel_param);
8816359Sasami}
8950518Snyan
9056442Speterstatic int mlx5i_set_channels(struct net_device *dev,
9156442Speter			      struct ethtool_channels *ch)
9256442Speter{
9356442Speter	struct mlx5i_priv *ipriv = netdev_priv(dev);
9456442Speter	struct mlx5e_priv *epriv = mlx5i_epriv(dev);
9556442Speter
9618846Sasami	/* rtnl lock protects from race between this ethtool op and sub
9720128Sasami	 * interface ndo_init/uninit.
9861750Snyan	 */
9961741Skato	ASSERT_RTNL();
10020128Sasami	if (ipriv->num_sub_interfaces > 0) {
10158789Snyan		mlx5_core_warn(epriv->mdev,
10261750Snyan			       "can't change number of channels for interfaces with sub interfaces (%u)\n",
10358789Snyan			       ipriv->num_sub_interfaces);
10450518Snyan		return -EINVAL;
10556442Speter	}
10656442Speter
10756442Speter	return mlx5e_ethtool_set_channels(epriv, ch);
10856442Speter}
10956442Speter
11016359Sasamistatic void mlx5i_get_channels(struct net_device *dev,
11154030Snyan			       struct ethtool_channels *ch)
11262205Skato{
11362205Skato	struct mlx5e_priv *priv = mlx5i_epriv(dev);
11462205Skato
11554030Snyan	mlx5e_ethtool_get_channels(priv, ch);
11642795Skato}
11761741Skato
11816359Sasamistatic int mlx5i_set_coalesce(struct net_device *netdev,
11961640Speter			      struct ethtool_coalesce *coal,
12042795Skato			      struct kernel_ethtool_coalesce *kernel_coal,
12145783Skato			      struct netlink_ext_ack *extack)
12261640Speter{
12342795Skato	struct mlx5e_priv *priv = mlx5i_epriv(netdev);
12453120Snyan
12561640Speter	return mlx5e_ethtool_set_coalesce(priv, coal, kernel_coal, extack);
12642795Skato}
12750518Snyan
12861640Speterstatic int mlx5i_get_coalesce(struct net_device *netdev,
12916359Sasami			      struct ethtool_coalesce *coal,
13050518Snyan			      struct kernel_ethtool_coalesce *kernel_coal,
13161640Speter			      struct netlink_ext_ack *extack)
13224432Skato{
13316359Sasami	struct mlx5e_priv *priv = mlx5i_epriv(netdev);
13456442Speter
13561640Speter	return mlx5e_ethtool_get_coalesce(priv, coal, kernel_coal);
13616359Sasami}
13750518Snyan
13853120Snyanstatic int mlx5i_get_ts_info(struct net_device *netdev,
13961750Snyan			     struct ethtool_ts_info *info)
14061640Speter{
14116359Sasami	struct mlx5e_priv *priv = mlx5i_epriv(netdev);
14261640Speter
14350518Snyan	return mlx5e_ethtool_get_ts_info(priv, info);
14448006Skato}
14561640Speter
14656711Snyanstatic int mlx5i_flash_device(struct net_device *netdev,
14756711Snyan			      struct ethtool_flash *flash)
14856711Snyan{
14956711Snyan	struct mlx5e_priv *priv = mlx5i_epriv(netdev);
15056711Snyan
15148006Skato	return mlx5e_ethtool_flash_device(priv, flash);
15248006Skato}
15361741Skato
15416359Sasamistatic inline int mlx5_ptys_width_enum_to_int(enum mlx5_ptys_width width)
15550513Skato{
15650518Snyan	switch (width) {
15756442Speter	case MLX5_PTYS_WIDTH_1X:  return  1;
15856442Speter	case MLX5_PTYS_WIDTH_2X:  return  2;
15956442Speter	case MLX5_PTYS_WIDTH_4X:  return  4;
16056442Speter	case MLX5_PTYS_WIDTH_8X:  return  8;
16156442Speter	case MLX5_PTYS_WIDTH_12X: return 12;
16251222Skato	default:		  return -1;
16351222Skato	}
16456442Speter}
16556442Speter
16656442Speterenum mlx5_ptys_rate {
16756442Speter	MLX5_PTYS_RATE_SDR	= 1 << 0,
16856442Speter	MLX5_PTYS_RATE_DDR	= 1 << 1,
16956442Speter	MLX5_PTYS_RATE_QDR	= 1 << 2,
17056442Speter	MLX5_PTYS_RATE_FDR10	= 1 << 3,
17156442Speter	MLX5_PTYS_RATE_FDR	= 1 << 4,
17256442Speter	MLX5_PTYS_RATE_EDR	= 1 << 5,
17356442Speter	MLX5_PTYS_RATE_HDR	= 1 << 6,
17416359Sasami	MLX5_PTYS_RATE_NDR	= 1 << 7,
17553056Snyan	MLX5_PTYS_RATE_XDR	= 1 << 8,
17661750Snyan};
17718095Sasami
17862007Skatostatic inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate)
17961750Snyan{
18056372Snyan	switch (rate) {
18155326Snyan	case MLX5_PTYS_RATE_SDR:   return 2500;
18261640Speter	case MLX5_PTYS_RATE_DDR:   return 5000;
18355326Snyan	case MLX5_PTYS_RATE_QDR:
18461640Speter	case MLX5_PTYS_RATE_FDR10: return 10000;
18561640Speter	case MLX5_PTYS_RATE_FDR:   return 14000;
18660717Snyan	case MLX5_PTYS_RATE_EDR:   return 25000;
18755326Snyan	case MLX5_PTYS_RATE_HDR:   return 50000;
18855086Skato	case MLX5_PTYS_RATE_NDR:   return 100000;
18954877Skato	case MLX5_PTYS_RATE_XDR:   return 200000;
19054877Skato	default:		   return -1;
19156711Snyan	}
19256323Skato}
19356323Skato
19456323Skatostatic u32 mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper)
19556323Skato{
19656323Skato	int rate, width;
19756711Snyan
19860717Snyan	rate = mlx5_ptys_rate_enum_to_int(ib_proto_oper);
19960717Snyan	if (rate < 0)
20060717Snyan		return SPEED_UNKNOWN;
20160717Snyan	width = mlx5_ptys_width_enum_to_int(ib_link_width_oper);
20218095Sasami	if (width < 0)
20356372Snyan		return SPEED_UNKNOWN;
20461750Snyan
20556442Speter	return rate * width;
20661640Speter}
20761640Speter
20861640Speterstatic int mlx5i_get_link_ksettings(struct net_device *netdev,
20961640Speter				    struct ethtool_link_ksettings *link_ksettings)
21061640Speter{
21161640Speter	struct mlx5e_priv *priv = mlx5i_epriv(netdev);
21261640Speter	struct mlx5_core_dev *mdev = priv->mdev;
21316359Sasami	u16 ib_link_width_oper;
21461640Speter	u16 ib_proto_oper;
21558458Snyan	int speed, ret;
21660711Snyan
21760711Snyan	ret = mlx5_query_ib_port_oper(mdev, &ib_link_width_oper, &ib_proto_oper,
21860711Snyan				      1);
21961640Speter	if (ret)
22060711Snyan		return ret;
22160711Snyan
22260711Snyan	ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
22361640Speter	ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
22460711Snyan
22550518Snyan	speed = mlx5i_get_speed_settings(ib_link_width_oper, ib_proto_oper);
22661640Speter	link_ksettings->base.speed = speed;
22761640Speter	link_ksettings->base.duplex = speed == SPEED_UNKNOWN ? DUPLEX_UNKNOWN : DUPLEX_FULL;
22861640Speter
22961640Speter	link_ksettings->base.port = PORT_OTHER;
23061640Speter
23161640Speter	link_ksettings->base.autoneg = AUTONEG_DISABLE;
23261640Speter
23361640Speter	return 0;
23461640Speter}
23517256Sasami
23661640Speterstatic u32 mlx5i_flow_type_mask(u32 flow_type)
23749519Skato{
23861640Speter	return flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
23950551Sphk}
24061750Snyan
24155326Snyanstatic int mlx5i_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
24255326Snyan{
24356442Speter	struct mlx5e_priv *priv = mlx5i_epriv(dev);
24456442Speter	struct ethtool_rx_flow_spec *fs = &cmd->fs;
24556442Speter
24660717Snyan	if (mlx5i_flow_type_mask(fs->flow_type) == ETHER_FLOW)
24756442Speter		return -EINVAL;
24856442Speter
24956442Speter	return mlx5e_ethtool_set_rxnfc(priv, cmd);
25056442Speter}
25156978Skato
25256442Speterstatic int mlx5i_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
25360717Snyan			   u32 *rule_locs)
25457655Skato{
25556442Speter	struct mlx5e_priv *priv = mlx5i_epriv(dev);
25656442Speter
25756442Speter	/* ETHTOOL_GRXRINGS is needed by ethtool -x which is not part
258	 * of rxnfc. We keep this logic out of mlx5e_ethtool_get_rxnfc,
259	 * to avoid breaking "ethtool -x" when mlx5e_ethtool_get_rxnfc
260	 * is compiled out via CONFIG_MLX5_EN_RXNFC=n.
261	 */
262	if (info->cmd == ETHTOOL_GRXRINGS) {
263		info->data = priv->channels.params.num_channels;
264		return 0;
265	}
266
267	return mlx5e_ethtool_get_rxnfc(priv, info, rule_locs);
268}
269
270const struct ethtool_ops mlx5i_ethtool_ops = {
271	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
272				     ETHTOOL_COALESCE_MAX_FRAMES |
273				     ETHTOOL_COALESCE_USE_ADAPTIVE,
274	.get_drvinfo        = mlx5i_get_drvinfo,
275	.get_strings        = mlx5i_get_strings,
276	.get_sset_count     = mlx5i_get_sset_count,
277	.get_ethtool_stats  = mlx5i_get_ethtool_stats,
278	.get_ringparam      = mlx5i_get_ringparam,
279	.set_ringparam      = mlx5i_set_ringparam,
280	.flash_device       = mlx5i_flash_device,
281	.get_channels       = mlx5i_get_channels,
282	.set_channels       = mlx5i_set_channels,
283	.get_coalesce       = mlx5i_get_coalesce,
284	.set_coalesce       = mlx5i_set_coalesce,
285	.get_ts_info        = mlx5i_get_ts_info,
286	.get_rxnfc          = mlx5i_get_rxnfc,
287	.set_rxnfc          = mlx5i_set_rxnfc,
288	.get_link_ksettings = mlx5i_get_link_ksettings,
289	.get_link           = ethtool_op_get_link,
290};
291
292const struct ethtool_ops mlx5i_pkey_ethtool_ops = {
293	.get_drvinfo        = mlx5i_get_drvinfo,
294	.get_link           = ethtool_op_get_link,
295	.get_ts_info        = mlx5i_get_ts_info,
296};
297