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