1fe267a55SPedro F. Giffuni /*-
2fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3fe267a55SPedro F. Giffuni  *
4aa0a1e58SJeff Roberson  * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
5aa0a1e58SJeff Roberson  *
6aa0a1e58SJeff Roberson  * This software is available to you under a choice of one of two
7aa0a1e58SJeff Roberson  * licenses.  You may choose to be licensed under the terms of the GNU
8aa0a1e58SJeff Roberson  * General Public License (GPL) Version 2, available from the file
9aa0a1e58SJeff Roberson  * COPYING in the main directory of this source tree, or the
10aa0a1e58SJeff Roberson  * OpenIB.org BSD license below:
11aa0a1e58SJeff Roberson  *
12aa0a1e58SJeff Roberson  *     Redistribution and use in source and binary forms, with or
13aa0a1e58SJeff Roberson  *     without modification, are permitted provided that the following
14aa0a1e58SJeff Roberson  *     conditions are met:
15aa0a1e58SJeff Roberson  *
16aa0a1e58SJeff Roberson  *      - Redistributions of source code must retain the above
17aa0a1e58SJeff Roberson  *        copyright notice, this list of conditions and the following
18aa0a1e58SJeff Roberson  *        disclaimer.
19aa0a1e58SJeff Roberson  *
20aa0a1e58SJeff Roberson  *      - Redistributions in binary form must reproduce the above
21aa0a1e58SJeff Roberson  *        copyright notice, this list of conditions and the following
22aa0a1e58SJeff Roberson  *        disclaimer in the documentation and/or other materials
23aa0a1e58SJeff Roberson  *        provided with the distribution.
24aa0a1e58SJeff Roberson  *
25aa0a1e58SJeff Roberson  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26aa0a1e58SJeff Roberson  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27aa0a1e58SJeff Roberson  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28aa0a1e58SJeff Roberson  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29aa0a1e58SJeff Roberson  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30aa0a1e58SJeff Roberson  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31aa0a1e58SJeff Roberson  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32aa0a1e58SJeff Roberson  * SOFTWARE.
33aa0a1e58SJeff Roberson  */
34aa0a1e58SJeff Roberson 
35cda1e10cSHans Petter Selasky #include <sys/cdefs.h>
36aa0a1e58SJeff Roberson #include <linux/kernel.h>
37aa0a1e58SJeff Roberson #include <linux/netdevice.h>
38aa0a1e58SJeff Roberson 
39aa0a1e58SJeff Roberson #include "ipoib.h"
40aa0a1e58SJeff Roberson 
ipoib_get_drvinfo(if_t netdev,struct ethtool_drvinfo * drvinfo)413e142e07SJustin Hibbits static void ipoib_get_drvinfo(if_t netdev,
42aa0a1e58SJeff Roberson 			      struct ethtool_drvinfo *drvinfo)
43aa0a1e58SJeff Roberson {
44aa0a1e58SJeff Roberson 	strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1);
45aa0a1e58SJeff Roberson }
46aa0a1e58SJeff Roberson 
ipoib_get_rx_csum(if_t dev)473e142e07SJustin Hibbits static u32 ipoib_get_rx_csum(if_t dev)
48aa0a1e58SJeff Roberson {
49aa0a1e58SJeff Roberson 	struct ipoib_dev_priv *priv = dev->if_softc;
50aa0a1e58SJeff Roberson 	return test_bit(IPOIB_FLAG_CSUM, &priv->flags) &&
51aa0a1e58SJeff Roberson 		!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
52aa0a1e58SJeff Roberson }
53aa0a1e58SJeff Roberson 
ipoib_get_coalesce(if_t dev,struct ethtool_coalesce * coal)543e142e07SJustin Hibbits static int ipoib_get_coalesce(if_t dev,
55aa0a1e58SJeff Roberson 			      struct ethtool_coalesce *coal)
56aa0a1e58SJeff Roberson {
57aa0a1e58SJeff Roberson 	struct ipoib_dev_priv *priv = dev->if_softc;
58aa0a1e58SJeff Roberson 
59aa0a1e58SJeff Roberson 	coal->rx_coalesce_usecs = priv->ethtool.coalesce_usecs;
60aa0a1e58SJeff Roberson 	coal->tx_coalesce_usecs = priv->ethtool.coalesce_usecs;
61aa0a1e58SJeff Roberson 	coal->rx_max_coalesced_frames = priv->ethtool.max_coalesced_frames;
62aa0a1e58SJeff Roberson 	coal->tx_max_coalesced_frames = priv->ethtool.max_coalesced_frames;
63aa0a1e58SJeff Roberson 
64aa0a1e58SJeff Roberson 	return 0;
65aa0a1e58SJeff Roberson }
66aa0a1e58SJeff Roberson 
ipoib_set_coalesce(if_t dev,struct ethtool_coalesce * coal)673e142e07SJustin Hibbits static int ipoib_set_coalesce(if_t dev,
68aa0a1e58SJeff Roberson 			      struct ethtool_coalesce *coal)
69aa0a1e58SJeff Roberson {
70aa0a1e58SJeff Roberson 	struct ipoib_dev_priv *priv = dev->if_softc;
71aa0a1e58SJeff Roberson 	int ret;
72aa0a1e58SJeff Roberson 
73aa0a1e58SJeff Roberson 	/*
74aa0a1e58SJeff Roberson 	 * Since IPoIB uses a single CQ for both rx and tx, we assume
75aa0a1e58SJeff Roberson 	 * that rx params dictate the configuration.  These values are
76aa0a1e58SJeff Roberson 	 * saved in the private data and returned when ipoib_get_coalesce()
77aa0a1e58SJeff Roberson 	 * is called.
78aa0a1e58SJeff Roberson 	 */
79aa0a1e58SJeff Roberson 	if (coal->rx_coalesce_usecs       > 0xffff ||
80aa0a1e58SJeff Roberson 	    coal->rx_max_coalesced_frames > 0xffff)
81aa0a1e58SJeff Roberson 		return -EINVAL;
82aa0a1e58SJeff Roberson 
83aa0a1e58SJeff Roberson 	if (coal->rx_max_coalesced_frames | coal->rx_coalesce_usecs) {
84aa0a1e58SJeff Roberson 		if (!coal->rx_max_coalesced_frames)
85aa0a1e58SJeff Roberson 			coal->rx_max_coalesced_frames = 0xffff;
86aa0a1e58SJeff Roberson 		else if (!coal->rx_coalesce_usecs)
87aa0a1e58SJeff Roberson 			coal->rx_coalesce_usecs = 0xffff;
88aa0a1e58SJeff Roberson 	}
89aa0a1e58SJeff Roberson 
90aa0a1e58SJeff Roberson 	ret = ib_modify_cq(priv->recv_cq, coal->rx_max_coalesced_frames,
91aa0a1e58SJeff Roberson 			   coal->rx_coalesce_usecs);
92aa0a1e58SJeff Roberson 	if (ret && ret != -ENOSYS) {
93aa0a1e58SJeff Roberson 		ipoib_warn(priv, "failed modifying CQ (%d)\n", ret);
94aa0a1e58SJeff Roberson 		return ret;
95aa0a1e58SJeff Roberson 	}
96aa0a1e58SJeff Roberson 
97aa0a1e58SJeff Roberson 	coal->tx_coalesce_usecs       = coal->rx_coalesce_usecs;
98aa0a1e58SJeff Roberson 	coal->tx_max_coalesced_frames = coal->rx_max_coalesced_frames;
99aa0a1e58SJeff Roberson 	priv->ethtool.coalesce_usecs       = coal->rx_coalesce_usecs;
100aa0a1e58SJeff Roberson 	priv->ethtool.max_coalesced_frames = coal->rx_max_coalesced_frames;
101aa0a1e58SJeff Roberson 
102aa0a1e58SJeff Roberson 	return 0;
103aa0a1e58SJeff Roberson }
104aa0a1e58SJeff Roberson 
105aa0a1e58SJeff Roberson static const char ipoib_stats_keys[][ETH_GSTRING_LEN] = {
106aa0a1e58SJeff Roberson 	"LRO aggregated", "LRO flushed",
107aa0a1e58SJeff Roberson 	"LRO avg aggr", "LRO no desc"
108aa0a1e58SJeff Roberson };
109aa0a1e58SJeff Roberson 
ipoib_get_strings(if_t netdev,u32 stringset,u8 * data)1103e142e07SJustin Hibbits static void ipoib_get_strings(if_t netdev, u32 stringset, u8 *data)
111aa0a1e58SJeff Roberson {
112aa0a1e58SJeff Roberson 	switch (stringset) {
113aa0a1e58SJeff Roberson 	case ETH_SS_STATS:
114aa0a1e58SJeff Roberson 		memcpy(data, *ipoib_stats_keys,	sizeof(ipoib_stats_keys));
115aa0a1e58SJeff Roberson 		break;
116aa0a1e58SJeff Roberson 	}
117aa0a1e58SJeff Roberson }
118aa0a1e58SJeff Roberson 
ipoib_get_sset_count(if_t dev,int sset)1193e142e07SJustin Hibbits static int ipoib_get_sset_count(if_t dev, int sset)
120aa0a1e58SJeff Roberson {
121aa0a1e58SJeff Roberson 	switch (sset) {
122aa0a1e58SJeff Roberson 	case ETH_SS_STATS:
123aa0a1e58SJeff Roberson 		return ARRAY_SIZE(ipoib_stats_keys);
124aa0a1e58SJeff Roberson 	default:
125aa0a1e58SJeff Roberson 		return -EOPNOTSUPP;
126aa0a1e58SJeff Roberson 	}
127aa0a1e58SJeff Roberson }
128aa0a1e58SJeff Roberson 
ipoib_get_ethtool_stats(if_t dev,struct ethtool_stats * stats,uint64_t * data)1293e142e07SJustin Hibbits static void ipoib_get_ethtool_stats(if_t dev,
130aa0a1e58SJeff Roberson 				struct ethtool_stats *stats, uint64_t *data)
131aa0a1e58SJeff Roberson {
132aa0a1e58SJeff Roberson 	struct ipoib_dev_priv *priv = dev->if_softc;
133aa0a1e58SJeff Roberson 	int index = 0;
134aa0a1e58SJeff Roberson 
135aa0a1e58SJeff Roberson 	/* Get LRO statistics */
136aa0a1e58SJeff Roberson 	data[index++] = priv->lro.lro_mgr.stats.aggregated;
137aa0a1e58SJeff Roberson 	data[index++] = priv->lro.lro_mgr.stats.flushed;
138aa0a1e58SJeff Roberson 	if (priv->lro.lro_mgr.stats.flushed)
139aa0a1e58SJeff Roberson 		data[index++] = priv->lro.lro_mgr.stats.aggregated /
140aa0a1e58SJeff Roberson 				priv->lro.lro_mgr.stats.flushed;
141aa0a1e58SJeff Roberson 	else
142aa0a1e58SJeff Roberson 		data[index++] = 0;
143aa0a1e58SJeff Roberson 	data[index++] = priv->lro.lro_mgr.stats.no_desc;
144aa0a1e58SJeff Roberson }
145aa0a1e58SJeff Roberson 
146aa0a1e58SJeff Roberson static const struct ethtool_ops ipoib_ethtool_ops = {
147aa0a1e58SJeff Roberson 	.get_drvinfo		= ipoib_get_drvinfo,
148aa0a1e58SJeff Roberson 	.get_rx_csum		= ipoib_get_rx_csum,
149aa0a1e58SJeff Roberson 	.get_coalesce		= ipoib_get_coalesce,
150aa0a1e58SJeff Roberson 	.set_coalesce		= ipoib_set_coalesce,
151aa0a1e58SJeff Roberson 	.get_flags		= ethtool_op_get_flags,
152aa0a1e58SJeff Roberson 	.set_flags		= ethtool_op_set_flags,
153aa0a1e58SJeff Roberson 	.get_strings		= ipoib_get_strings,
154aa0a1e58SJeff Roberson 	.get_sset_count		= ipoib_get_sset_count,
155aa0a1e58SJeff Roberson 	.get_ethtool_stats	= ipoib_get_ethtool_stats,
156aa0a1e58SJeff Roberson };
157aa0a1e58SJeff Roberson 
ipoib_set_ethtool_ops(if_t dev)1583e142e07SJustin Hibbits void ipoib_set_ethtool_ops(if_t dev)
159aa0a1e58SJeff Roberson {
160aa0a1e58SJeff Roberson 	SET_ETHTOOL_OPS(dev, &ipoib_ethtool_ops);
161aa0a1e58SJeff Roberson }
162