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
->version
, ipoib_driver_version
,
72 sizeof(drvinfo
->version
));
74 strlcpy(drvinfo
->driver
, "ib_ipoib", sizeof(drvinfo
->driver
));
77 static int ipoib_get_coalesce(struct net_device
*dev
,
78 struct ethtool_coalesce
*coal
)
80 struct ipoib_dev_priv
*priv
= ipoib_priv(dev
);
82 coal
->rx_coalesce_usecs
= priv
->ethtool
.coalesce_usecs
;
83 coal
->rx_max_coalesced_frames
= priv
->ethtool
.max_coalesced_frames
;
88 static int ipoib_set_coalesce(struct net_device
*dev
,
89 struct ethtool_coalesce
*coal
)
91 struct ipoib_dev_priv
*priv
= ipoib_priv(dev
);
95 * These values are saved in the private data and returned
96 * when ipoib_get_coalesce() is called
98 if (coal
->rx_coalesce_usecs
> 0xffff ||
99 coal
->rx_max_coalesced_frames
> 0xffff)
102 ret
= rdma_set_cq_moderation(priv
->recv_cq
,
103 coal
->rx_max_coalesced_frames
,
104 coal
->rx_coalesce_usecs
);
105 if (ret
&& ret
!= -ENOSYS
) {
106 ipoib_warn(priv
, "failed modifying CQ (%d)\n", ret
);
110 priv
->ethtool
.coalesce_usecs
= coal
->rx_coalesce_usecs
;
111 priv
->ethtool
.max_coalesced_frames
= coal
->rx_max_coalesced_frames
;
115 static void ipoib_get_ethtool_stats(struct net_device
*dev
,
116 struct ethtool_stats __always_unused
*stats
,
120 struct net_device_stats
*net_stats
= &dev
->stats
;
121 u8
*p
= (u8
*)net_stats
;
123 for (i
= 0; i
< IPOIB_GLOBAL_STATS_LEN
; i
++)
124 data
[i
] = *(u64
*)(p
+ ipoib_gstrings_stats
[i
].stat_offset
);
127 static void ipoib_get_strings(struct net_device __always_unused
*dev
,
128 u32 stringset
, u8
*data
)
135 for (i
= 0; i
< IPOIB_GLOBAL_STATS_LEN
; i
++) {
136 memcpy(p
, ipoib_gstrings_stats
[i
].stat_string
,
138 p
+= ETH_GSTRING_LEN
;
146 static int ipoib_get_sset_count(struct net_device __always_unused
*dev
,
151 return IPOIB_GLOBAL_STATS_LEN
;
159 /* Return lane speed in unit of 1e6 bit/sec */
160 static inline int ib_speed_enum_to_int(int speed
)
176 return SPEED_UNKNOWN
;
179 static int ipoib_get_link_ksettings(struct net_device
*netdev
,
180 struct ethtool_link_ksettings
*cmd
)
182 struct ipoib_dev_priv
*priv
= ipoib_priv(netdev
);
183 struct ib_port_attr attr
;
184 int ret
, speed
, width
;
186 if (!netif_carrier_ok(netdev
)) {
187 cmd
->base
.speed
= SPEED_UNKNOWN
;
188 cmd
->base
.duplex
= DUPLEX_UNKNOWN
;
192 ret
= ib_query_port(priv
->ca
, priv
->port
, &attr
);
196 speed
= ib_speed_enum_to_int(attr
.active_speed
);
197 width
= ib_width_enum_to_int(attr
.active_width
);
199 if (speed
< 0 || width
< 0)
202 /* Except the following are set, the other members of
203 * the struct ethtool_link_settings are initialized to
204 * zero in the function __ethtool_get_link_ksettings.
206 cmd
->base
.speed
= speed
* width
;
207 cmd
->base
.duplex
= DUPLEX_FULL
;
209 cmd
->base
.phy_address
= 0xFF;
211 cmd
->base
.autoneg
= AUTONEG_ENABLE
;
212 cmd
->base
.port
= PORT_OTHER
;
217 static const struct ethtool_ops ipoib_ethtool_ops
= {
218 .get_link_ksettings
= ipoib_get_link_ksettings
,
219 .get_drvinfo
= ipoib_get_drvinfo
,
220 .get_coalesce
= ipoib_get_coalesce
,
221 .set_coalesce
= ipoib_set_coalesce
,
222 .get_strings
= ipoib_get_strings
,
223 .get_ethtool_stats
= ipoib_get_ethtool_stats
,
224 .get_sset_count
= ipoib_get_sset_count
,
227 void ipoib_set_ethtool_ops(struct net_device
*dev
)
229 dev
->ethtool_ops
= &ipoib_ethtool_ops
;