2 * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <linux/kernel.h>
34 #include <linux/ethtool.h>
35 #include <linux/netdevice.h>
40 char stat_string
[ETH_GSTRING_LEN
];
44 #define IPOIB_NETDEV_STAT(m) { \
46 .stat_offset = offsetof(struct rtnl_link_stats64, m) }
48 static const struct ipoib_stats ipoib_gstrings_stats
[] = {
49 IPOIB_NETDEV_STAT(rx_packets
),
50 IPOIB_NETDEV_STAT(tx_packets
),
51 IPOIB_NETDEV_STAT(rx_bytes
),
52 IPOIB_NETDEV_STAT(tx_bytes
),
53 IPOIB_NETDEV_STAT(tx_errors
),
54 IPOIB_NETDEV_STAT(rx_dropped
),
55 IPOIB_NETDEV_STAT(tx_dropped
),
56 IPOIB_NETDEV_STAT(multicast
),
59 #define IPOIB_GLOBAL_STATS_LEN ARRAY_SIZE(ipoib_gstrings_stats)
61 static void ipoib_get_drvinfo(struct net_device
*netdev
,
62 struct ethtool_drvinfo
*drvinfo
)
64 struct ipoib_dev_priv
*priv
= ipoib_priv(netdev
);
66 ib_get_device_fw_str(priv
->ca
, drvinfo
->fw_version
);
68 strlcpy(drvinfo
->bus_info
, dev_name(priv
->ca
->dev
.parent
),
69 sizeof(drvinfo
->bus_info
));
71 strlcpy(drvinfo
->driver
, "ib_ipoib", sizeof(drvinfo
->driver
));
74 static int ipoib_get_coalesce(struct net_device
*dev
,
75 struct ethtool_coalesce
*coal
)
77 struct ipoib_dev_priv
*priv
= ipoib_priv(dev
);
79 coal
->rx_coalesce_usecs
= priv
->ethtool
.coalesce_usecs
;
80 coal
->rx_max_coalesced_frames
= priv
->ethtool
.max_coalesced_frames
;
85 static int ipoib_set_coalesce(struct net_device
*dev
,
86 struct ethtool_coalesce
*coal
)
88 struct ipoib_dev_priv
*priv
= ipoib_priv(dev
);
92 * These values are saved in the private data and returned
93 * when ipoib_get_coalesce() is called
95 if (coal
->rx_coalesce_usecs
> 0xffff ||
96 coal
->rx_max_coalesced_frames
> 0xffff)
99 ret
= rdma_set_cq_moderation(priv
->recv_cq
,
100 coal
->rx_max_coalesced_frames
,
101 coal
->rx_coalesce_usecs
);
102 if (ret
&& ret
!= -EOPNOTSUPP
) {
103 ipoib_warn(priv
, "failed modifying CQ (%d)\n", ret
);
107 priv
->ethtool
.coalesce_usecs
= coal
->rx_coalesce_usecs
;
108 priv
->ethtool
.max_coalesced_frames
= coal
->rx_max_coalesced_frames
;
112 static void ipoib_get_ethtool_stats(struct net_device
*dev
,
113 struct ethtool_stats __always_unused
*stats
,
117 struct net_device_stats
*net_stats
= &dev
->stats
;
118 u8
*p
= (u8
*)net_stats
;
120 for (i
= 0; i
< IPOIB_GLOBAL_STATS_LEN
; i
++)
121 data
[i
] = *(u64
*)(p
+ ipoib_gstrings_stats
[i
].stat_offset
);
124 static void ipoib_get_strings(struct net_device __always_unused
*dev
,
125 u32 stringset
, u8
*data
)
132 for (i
= 0; i
< IPOIB_GLOBAL_STATS_LEN
; i
++) {
133 memcpy(p
, ipoib_gstrings_stats
[i
].stat_string
,
135 p
+= ETH_GSTRING_LEN
;
142 static int ipoib_get_sset_count(struct net_device __always_unused
*dev
,
147 return IPOIB_GLOBAL_STATS_LEN
;
154 /* Return lane speed in unit of 1e6 bit/sec */
155 static inline int ib_speed_enum_to_int(int speed
)
175 return SPEED_UNKNOWN
;
178 static int ipoib_get_link_ksettings(struct net_device
*netdev
,
179 struct ethtool_link_ksettings
*cmd
)
181 struct ipoib_dev_priv
*priv
= ipoib_priv(netdev
);
182 struct ib_port_attr attr
;
183 int ret
, speed
, width
;
185 if (!netif_carrier_ok(netdev
)) {
186 cmd
->base
.speed
= SPEED_UNKNOWN
;
187 cmd
->base
.duplex
= DUPLEX_UNKNOWN
;
191 ret
= ib_query_port(priv
->ca
, priv
->port
, &attr
);
195 speed
= ib_speed_enum_to_int(attr
.active_speed
);
196 width
= ib_width_enum_to_int(attr
.active_width
);
198 if (speed
< 0 || width
< 0)
201 /* Except the following are set, the other members of
202 * the struct ethtool_link_settings are initialized to
203 * zero in the function __ethtool_get_link_ksettings.
205 cmd
->base
.speed
= speed
* width
;
206 cmd
->base
.duplex
= DUPLEX_FULL
;
208 cmd
->base
.phy_address
= 0xFF;
210 cmd
->base
.autoneg
= AUTONEG_ENABLE
;
211 cmd
->base
.port
= PORT_OTHER
;
216 static const struct ethtool_ops ipoib_ethtool_ops
= {
217 .supported_coalesce_params
= ETHTOOL_COALESCE_RX_USECS
|
218 ETHTOOL_COALESCE_RX_MAX_FRAMES
,
219 .get_link_ksettings
= ipoib_get_link_ksettings
,
220 .get_drvinfo
= ipoib_get_drvinfo
,
221 .get_coalesce
= ipoib_get_coalesce
,
222 .set_coalesce
= ipoib_set_coalesce
,
223 .get_strings
= ipoib_get_strings
,
224 .get_ethtool_stats
= ipoib_get_ethtool_stats
,
225 .get_sset_count
= ipoib_get_sset_count
,
226 .get_link
= ethtool_op_get_link
,
229 void ipoib_set_ethtool_ops(struct net_device
*dev
)
231 dev
->ethtool_ops
= &ipoib_ethtool_ops
;