aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/mlx4/en_ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/mlx4/en_ethtool.c')
-rw-r--r--drivers/net/mlx4/en_ethtool.c286
1 files changed, 151 insertions, 135 deletions
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index b275238fe70d..2e858e4dcf4d 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -39,28 +39,13 @@
39#include "en_port.h" 39#include "en_port.h"
40 40
41 41
42static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv)
43{
44 int i;
45
46 priv->port_stats.lro_aggregated = 0;
47 priv->port_stats.lro_flushed = 0;
48 priv->port_stats.lro_no_desc = 0;
49
50 for (i = 0; i < priv->rx_ring_num; i++) {
51 priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated;
52 priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed;
53 priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc;
54 }
55}
56
57static void 42static void
58mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) 43mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
59{ 44{
60 struct mlx4_en_priv *priv = netdev_priv(dev); 45 struct mlx4_en_priv *priv = netdev_priv(dev);
61 struct mlx4_en_dev *mdev = priv->mdev; 46 struct mlx4_en_dev *mdev = priv->mdev;
62 47
63 sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); 48 strncpy(drvinfo->driver, DRV_NAME, 32);
64 strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); 49 strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32);
65 sprintf(drvinfo->fw_version, "%d.%d.%d", 50 sprintf(drvinfo->fw_version, "%d.%d.%d",
66 (u16) (mdev->dev->caps.fw_ver >> 32), 51 (u16) (mdev->dev->caps.fw_ver >> 32),
@@ -72,37 +57,6 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
72 drvinfo->eedump_len = 0; 57 drvinfo->eedump_len = 0;
73} 58}
74 59
75static u32 mlx4_en_get_tso(struct net_device *dev)
76{
77 return (dev->features & NETIF_F_TSO) != 0;
78}
79
80static int mlx4_en_set_tso(struct net_device *dev, u32 data)
81{
82 struct mlx4_en_priv *priv = netdev_priv(dev);
83
84 if (data) {
85 if (!priv->mdev->LSO_support)
86 return -EPERM;
87 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
88 } else
89 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
90 return 0;
91}
92
93static u32 mlx4_en_get_rx_csum(struct net_device *dev)
94{
95 struct mlx4_en_priv *priv = netdev_priv(dev);
96 return priv->rx_csum;
97}
98
99static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data)
100{
101 struct mlx4_en_priv *priv = netdev_priv(dev);
102 priv->rx_csum = (data != 0);
103 return 0;
104}
105
106static const char main_strings[][ETH_GSTRING_LEN] = { 60static const char main_strings[][ETH_GSTRING_LEN] = {
107 "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", 61 "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
108 "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", 62 "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -112,7 +66,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
112 "tx_heartbeat_errors", "tx_window_errors", 66 "tx_heartbeat_errors", "tx_window_errors",
113 67
114 /* port statistics */ 68 /* port statistics */
115 "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets", 69 "tso_packets",
116 "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", 70 "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
117 "rx_csum_good", "rx_csum_none", "tx_chksum_offload", 71 "rx_csum_good", "rx_csum_none", "tx_chksum_offload",
118 72
@@ -125,6 +79,14 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
125#define NUM_MAIN_STATS 21 79#define NUM_MAIN_STATS 21
126#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) 80#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)
127 81
82static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= {
83 "Interupt Test",
84 "Link Test",
85 "Speed Test",
86 "Register Test",
87 "Loopback Test",
88};
89
128static u32 mlx4_en_get_msglevel(struct net_device *dev) 90static u32 mlx4_en_get_msglevel(struct net_device *dev)
129{ 91{
130 return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; 92 return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable;
@@ -138,18 +100,80 @@ static void mlx4_en_set_msglevel(struct net_device *dev, u32 val)
138static void mlx4_en_get_wol(struct net_device *netdev, 100static void mlx4_en_get_wol(struct net_device *netdev,
139 struct ethtool_wolinfo *wol) 101 struct ethtool_wolinfo *wol)
140{ 102{
141 wol->supported = 0; 103 struct mlx4_en_priv *priv = netdev_priv(netdev);
142 wol->wolopts = 0; 104 int err = 0;
105 u64 config = 0;
106
107 if (!priv->mdev->dev->caps.wol) {
108 wol->supported = 0;
109 wol->wolopts = 0;
110 return;
111 }
112
113 err = mlx4_wol_read(priv->mdev->dev, &config, priv->port);
114 if (err) {
115 en_err(priv, "Failed to get WoL information\n");
116 return;
117 }
118
119 if (config & MLX4_EN_WOL_MAGIC)
120 wol->supported = WAKE_MAGIC;
121 else
122 wol->supported = 0;
123
124 if (config & MLX4_EN_WOL_ENABLED)
125 wol->wolopts = WAKE_MAGIC;
126 else
127 wol->wolopts = 0;
128}
129
130static int mlx4_en_set_wol(struct net_device *netdev,
131 struct ethtool_wolinfo *wol)
132{
133 struct mlx4_en_priv *priv = netdev_priv(netdev);
134 u64 config = 0;
135 int err = 0;
136
137 if (!priv->mdev->dev->caps.wol)
138 return -EOPNOTSUPP;
139
140 if (wol->supported & ~WAKE_MAGIC)
141 return -EINVAL;
142
143 err = mlx4_wol_read(priv->mdev->dev, &config, priv->port);
144 if (err) {
145 en_err(priv, "Failed to get WoL info, unable to modify\n");
146 return err;
147 }
148
149 if (wol->wolopts & WAKE_MAGIC) {
150 config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED |
151 MLX4_EN_WOL_MAGIC;
152 } else {
153 config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC);
154 config |= MLX4_EN_WOL_DO_MODIFY;
155 }
156
157 err = mlx4_wol_write(priv->mdev->dev, config, priv->port);
158 if (err)
159 en_err(priv, "Failed to set WoL information\n");
160
161 return err;
143} 162}
144 163
145static int mlx4_en_get_sset_count(struct net_device *dev, int sset) 164static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
146{ 165{
147 struct mlx4_en_priv *priv = netdev_priv(dev); 166 struct mlx4_en_priv *priv = netdev_priv(dev);
148 167
149 if (sset != ETH_SS_STATS) 168 switch (sset) {
169 case ETH_SS_STATS:
170 return NUM_ALL_STATS +
171 (priv->tx_ring_num + priv->rx_ring_num) * 2;
172 case ETH_SS_TEST:
173 return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.loopback_support) * 2;
174 default:
150 return -EOPNOTSUPP; 175 return -EOPNOTSUPP;
151 176 }
152 return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2;
153} 177}
154 178
155static void mlx4_en_get_ethtool_stats(struct net_device *dev, 179static void mlx4_en_get_ethtool_stats(struct net_device *dev,
@@ -161,8 +185,6 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
161 185
162 spin_lock_bh(&priv->stats_lock); 186 spin_lock_bh(&priv->stats_lock);
163 187
164 mlx4_en_update_lro_stats(priv);
165
166 for (i = 0; i < NUM_MAIN_STATS; i++) 188 for (i = 0; i < NUM_MAIN_STATS; i++)
167 data[index++] = ((unsigned long *) &priv->stats)[i]; 189 data[index++] = ((unsigned long *) &priv->stats)[i];
168 for (i = 0; i < NUM_PORT_STATS; i++) 190 for (i = 0; i < NUM_PORT_STATS; i++)
@@ -181,6 +203,12 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
181 203
182} 204}
183 205
206static void mlx4_en_self_test(struct net_device *dev,
207 struct ethtool_test *etest, u64 *buf)
208{
209 mlx4_en_ex_selftest(dev, &etest->flags, buf);
210}
211
184static void mlx4_en_get_strings(struct net_device *dev, 212static void mlx4_en_get_strings(struct net_device *dev,
185 uint32_t stringset, uint8_t *data) 213 uint32_t stringset, uint8_t *data)
186{ 214{
@@ -188,51 +216,84 @@ static void mlx4_en_get_strings(struct net_device *dev,
188 int index = 0; 216 int index = 0;
189 int i; 217 int i;
190 218
191 if (stringset != ETH_SS_STATS) 219 switch (stringset) {
192 return; 220 case ETH_SS_TEST:
193 221 for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++)
194 /* Add main counters */ 222 strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
195 for (i = 0; i < NUM_MAIN_STATS; i++) 223 if (priv->mdev->dev->caps.loopback_support)
196 strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); 224 for (; i < MLX4_EN_NUM_SELF_TEST; i++)
197 for (i = 0; i < NUM_PORT_STATS; i++) 225 strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
198 strcpy(data + (index++) * ETH_GSTRING_LEN, 226 break;
227
228 case ETH_SS_STATS:
229 /* Add main counters */
230 for (i = 0; i < NUM_MAIN_STATS; i++)
231 strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
232 for (i = 0; i< NUM_PORT_STATS; i++)
233 strcpy(data + (index++) * ETH_GSTRING_LEN,
199 main_strings[i + NUM_MAIN_STATS]); 234 main_strings[i + NUM_MAIN_STATS]);
200 for (i = 0; i < priv->tx_ring_num; i++) { 235 for (i = 0; i < priv->tx_ring_num; i++) {
201 sprintf(data + (index++) * ETH_GSTRING_LEN, 236 sprintf(data + (index++) * ETH_GSTRING_LEN,
202 "tx%d_packets", i); 237 "tx%d_packets", i);
203 sprintf(data + (index++) * ETH_GSTRING_LEN, 238 sprintf(data + (index++) * ETH_GSTRING_LEN,
204 "tx%d_bytes", i); 239 "tx%d_bytes", i);
205 } 240 }
206 for (i = 0; i < priv->rx_ring_num; i++) { 241 for (i = 0; i < priv->rx_ring_num; i++) {
207 sprintf(data + (index++) * ETH_GSTRING_LEN, 242 sprintf(data + (index++) * ETH_GSTRING_LEN,
208 "rx%d_packets", i); 243 "rx%d_packets", i);
209 sprintf(data + (index++) * ETH_GSTRING_LEN, 244 sprintf(data + (index++) * ETH_GSTRING_LEN,
210 "rx%d_bytes", i); 245 "rx%d_bytes", i);
211 } 246 }
212 for (i = 0; i < NUM_PKT_STATS; i++) 247 for (i = 0; i< NUM_PKT_STATS; i++)
213 strcpy(data + (index++) * ETH_GSTRING_LEN, 248 strcpy(data + (index++) * ETH_GSTRING_LEN,
214 main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); 249 main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]);
250 break;
251 }
215} 252}
216 253
217static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 254static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
218{ 255{
256 struct mlx4_en_priv *priv = netdev_priv(dev);
257 int trans_type;
258
219 cmd->autoneg = AUTONEG_DISABLE; 259 cmd->autoneg = AUTONEG_DISABLE;
220 cmd->supported = SUPPORTED_10000baseT_Full; 260 cmd->supported = SUPPORTED_10000baseT_Full;
221 cmd->advertising = ADVERTISED_1000baseT_Full; 261 cmd->advertising = ADVERTISED_10000baseT_Full;
262
263 if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
264 return -ENOMEM;
265
266 trans_type = priv->port_state.transciver;
222 if (netif_carrier_ok(dev)) { 267 if (netif_carrier_ok(dev)) {
223 cmd->speed = SPEED_10000; 268 ethtool_cmd_speed_set(cmd, priv->port_state.link_speed);
224 cmd->duplex = DUPLEX_FULL; 269 cmd->duplex = DUPLEX_FULL;
225 } else { 270 } else {
226 cmd->speed = -1; 271 ethtool_cmd_speed_set(cmd, -1);
227 cmd->duplex = -1; 272 cmd->duplex = -1;
228 } 273 }
274
275 if (trans_type > 0 && trans_type <= 0xC) {
276 cmd->port = PORT_FIBRE;
277 cmd->transceiver = XCVR_EXTERNAL;
278 cmd->supported |= SUPPORTED_FIBRE;
279 cmd->advertising |= ADVERTISED_FIBRE;
280 } else if (trans_type == 0x80 || trans_type == 0) {
281 cmd->port = PORT_TP;
282 cmd->transceiver = XCVR_INTERNAL;
283 cmd->supported |= SUPPORTED_TP;
284 cmd->advertising |= ADVERTISED_TP;
285 } else {
286 cmd->port = -1;
287 cmd->transceiver = -1;
288 }
229 return 0; 289 return 0;
230} 290}
231 291
232static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 292static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
233{ 293{
234 if ((cmd->autoneg == AUTONEG_ENABLE) || 294 if ((cmd->autoneg == AUTONEG_ENABLE) ||
235 (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL)) 295 (ethtool_cmd_speed(cmd) != SPEED_10000) ||
296 (cmd->duplex != DUPLEX_FULL))
236 return -EINVAL; 297 return -EINVAL;
237 298
238 /* Nothing to change */ 299 /* Nothing to change */
@@ -343,8 +404,9 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
343 tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); 404 tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE);
344 tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); 405 tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE);
345 406
346 if (rx_size == priv->prof->rx_ring_size && 407 if (rx_size == (priv->port_up ? priv->rx_ring[0].actual_size :
347 tx_size == priv->prof->tx_ring_size) 408 priv->rx_ring[0].size) &&
409 tx_size == priv->tx_ring[0].size)
348 return 0; 410 return 0;
349 411
350 mutex_lock(&mdev->state_lock); 412 mutex_lock(&mdev->state_lock);
@@ -353,7 +415,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
353 mlx4_en_stop_port(dev); 415 mlx4_en_stop_port(dev);
354 } 416 }
355 417
356 mlx4_en_free_resources(priv); 418 mlx4_en_free_resources(priv, true);
357 419
358 priv->prof->tx_ring_size = tx_size; 420 priv->prof->tx_ring_size = tx_size;
359 priv->prof->rx_ring_size = rx_size; 421 priv->prof->rx_ring_size = rx_size;
@@ -378,70 +440,26 @@ static void mlx4_en_get_ringparam(struct net_device *dev,
378 struct ethtool_ringparam *param) 440 struct ethtool_ringparam *param)
379{ 441{
380 struct mlx4_en_priv *priv = netdev_priv(dev); 442 struct mlx4_en_priv *priv = netdev_priv(dev);
381 struct mlx4_en_dev *mdev = priv->mdev;
382 443
383 memset(param, 0, sizeof(*param)); 444 memset(param, 0, sizeof(*param));
384 param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; 445 param->rx_max_pending = MLX4_EN_MAX_RX_SIZE;
385 param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; 446 param->tx_max_pending = MLX4_EN_MAX_TX_SIZE;
386 param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size; 447 param->rx_pending = priv->port_up ?
387 param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size; 448 priv->rx_ring[0].actual_size : priv->rx_ring[0].size;
388} 449 param->tx_pending = priv->tx_ring[0].size;
389
390static int mlx4_ethtool_op_set_flags(struct net_device *dev, u32 data)
391{
392 struct mlx4_en_priv *priv = netdev_priv(dev);
393 struct mlx4_en_dev *mdev = priv->mdev;
394 int rc = 0;
395 int changed = 0;
396
397 if (data & ~ETH_FLAG_LRO)
398 return -EOPNOTSUPP;
399
400 if (data & ETH_FLAG_LRO) {
401 if (mdev->profile.num_lro == 0)
402 return -EOPNOTSUPP;
403 if (!(dev->features & NETIF_F_LRO))
404 changed = 1;
405 } else if (dev->features & NETIF_F_LRO) {
406 changed = 1;
407 }
408
409 if (changed) {
410 if (netif_running(dev)) {
411 mutex_lock(&mdev->state_lock);
412 mlx4_en_stop_port(dev);
413 }
414 dev->features ^= NETIF_F_LRO;
415 if (netif_running(dev)) {
416 rc = mlx4_en_start_port(dev);
417 if (rc)
418 en_err(priv, "Failed to restart port\n");
419 mutex_unlock(&mdev->state_lock);
420 }
421 }
422
423 return rc;
424} 450}
425 451
426const struct ethtool_ops mlx4_en_ethtool_ops = { 452const struct ethtool_ops mlx4_en_ethtool_ops = {
427 .get_drvinfo = mlx4_en_get_drvinfo, 453 .get_drvinfo = mlx4_en_get_drvinfo,
428 .get_settings = mlx4_en_get_settings, 454 .get_settings = mlx4_en_get_settings,
429 .set_settings = mlx4_en_set_settings, 455 .set_settings = mlx4_en_set_settings,
430#ifdef NETIF_F_TSO
431 .get_tso = mlx4_en_get_tso,
432 .set_tso = mlx4_en_set_tso,
433#endif
434 .get_sg = ethtool_op_get_sg,
435 .set_sg = ethtool_op_set_sg,
436 .get_link = ethtool_op_get_link, 456 .get_link = ethtool_op_get_link,
437 .get_rx_csum = mlx4_en_get_rx_csum,
438 .set_rx_csum = mlx4_en_set_rx_csum,
439 .get_tx_csum = ethtool_op_get_tx_csum,
440 .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
441 .get_strings = mlx4_en_get_strings, 457 .get_strings = mlx4_en_get_strings,
442 .get_sset_count = mlx4_en_get_sset_count, 458 .get_sset_count = mlx4_en_get_sset_count,
443 .get_ethtool_stats = mlx4_en_get_ethtool_stats, 459 .get_ethtool_stats = mlx4_en_get_ethtool_stats,
460 .self_test = mlx4_en_self_test,
444 .get_wol = mlx4_en_get_wol, 461 .get_wol = mlx4_en_get_wol,
462 .set_wol = mlx4_en_set_wol,
445 .get_msglevel = mlx4_en_get_msglevel, 463 .get_msglevel = mlx4_en_get_msglevel,
446 .set_msglevel = mlx4_en_set_msglevel, 464 .set_msglevel = mlx4_en_set_msglevel,
447 .get_coalesce = mlx4_en_get_coalesce, 465 .get_coalesce = mlx4_en_get_coalesce,
@@ -450,8 +468,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
450 .set_pauseparam = mlx4_en_set_pauseparam, 468 .set_pauseparam = mlx4_en_set_pauseparam,
451 .get_ringparam = mlx4_en_get_ringparam, 469 .get_ringparam = mlx4_en_get_ringparam,
452 .set_ringparam = mlx4_en_set_ringparam, 470 .set_ringparam = mlx4_en_set_ringparam,
453 .get_flags = ethtool_op_get_flags,
454 .set_flags = mlx4_ethtool_op_set_flags,
455}; 471};
456 472
457 473