blob: b756840e2a16ba5636d617a797d9471b1c9cde65 [file] [log] [blame]
Ben Hutchings8ceee662008-04-27 12:55:59 +01001/****************************************************************************
2 * Driver for Solarflare Solarstorm network controllers and boards
3 * Copyright 2005-2006 Fen Systems Ltd.
4 * Copyright 2006-2008 Solarflare Communications Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation, incorporated herein by reference.
9 */
10
11#include <linux/netdevice.h>
12#include <linux/ethtool.h>
13#include <linux/rtnetlink.h>
14#include "net_driver.h"
15#include "efx.h"
16#include "ethtool.h"
17#include "falcon.h"
18#include "gmii.h"
19#include "mac.h"
20
21static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
22
23struct ethtool_string {
24 char name[ETH_GSTRING_LEN];
25};
26
27struct efx_ethtool_stat {
28 const char *name;
29 enum {
30 EFX_ETHTOOL_STAT_SOURCE_mac_stats,
31 EFX_ETHTOOL_STAT_SOURCE_nic,
32 EFX_ETHTOOL_STAT_SOURCE_channel
33 } source;
34 unsigned offset;
35 u64(*get_stat) (void *field); /* Reader function */
36};
37
38/* Initialiser for a struct #efx_ethtool_stat with type-checking */
39#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \
40 get_stat_function) { \
41 .name = #stat_name, \
42 .source = EFX_ETHTOOL_STAT_SOURCE_##source_name, \
43 .offset = ((((field_type *) 0) == \
44 &((struct efx_##source_name *)0)->field) ? \
45 offsetof(struct efx_##source_name, field) : \
46 offsetof(struct efx_##source_name, field)), \
47 .get_stat = get_stat_function, \
48}
49
50static u64 efx_get_uint_stat(void *field)
51{
52 return *(unsigned int *)field;
53}
54
55static u64 efx_get_ulong_stat(void *field)
56{
57 return *(unsigned long *)field;
58}
59
60static u64 efx_get_u64_stat(void *field)
61{
62 return *(u64 *) field;
63}
64
65static u64 efx_get_atomic_stat(void *field)
66{
67 return atomic_read((atomic_t *) field);
68}
69
70#define EFX_ETHTOOL_ULONG_MAC_STAT(field) \
71 EFX_ETHTOOL_STAT(field, mac_stats, field, \
72 unsigned long, efx_get_ulong_stat)
73
74#define EFX_ETHTOOL_U64_MAC_STAT(field) \
75 EFX_ETHTOOL_STAT(field, mac_stats, field, \
76 u64, efx_get_u64_stat)
77
78#define EFX_ETHTOOL_UINT_NIC_STAT(name) \
79 EFX_ETHTOOL_STAT(name, nic, n_##name, \
80 unsigned int, efx_get_uint_stat)
81
82#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \
83 EFX_ETHTOOL_STAT(field, nic, field, \
84 atomic_t, efx_get_atomic_stat)
85
86#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \
87 EFX_ETHTOOL_STAT(field, channel, n_##field, \
88 unsigned int, efx_get_uint_stat)
89
90static struct efx_ethtool_stat efx_ethtool_stats[] = {
91 EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
92 EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
93 EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes),
94 EFX_ETHTOOL_ULONG_MAC_STAT(tx_packets),
95 EFX_ETHTOOL_ULONG_MAC_STAT(tx_bad),
96 EFX_ETHTOOL_ULONG_MAC_STAT(tx_pause),
97 EFX_ETHTOOL_ULONG_MAC_STAT(tx_control),
98 EFX_ETHTOOL_ULONG_MAC_STAT(tx_unicast),
99 EFX_ETHTOOL_ULONG_MAC_STAT(tx_multicast),
100 EFX_ETHTOOL_ULONG_MAC_STAT(tx_broadcast),
101 EFX_ETHTOOL_ULONG_MAC_STAT(tx_lt64),
102 EFX_ETHTOOL_ULONG_MAC_STAT(tx_64),
103 EFX_ETHTOOL_ULONG_MAC_STAT(tx_65_to_127),
104 EFX_ETHTOOL_ULONG_MAC_STAT(tx_128_to_255),
105 EFX_ETHTOOL_ULONG_MAC_STAT(tx_256_to_511),
106 EFX_ETHTOOL_ULONG_MAC_STAT(tx_512_to_1023),
107 EFX_ETHTOOL_ULONG_MAC_STAT(tx_1024_to_15xx),
108 EFX_ETHTOOL_ULONG_MAC_STAT(tx_15xx_to_jumbo),
109 EFX_ETHTOOL_ULONG_MAC_STAT(tx_gtjumbo),
110 EFX_ETHTOOL_ULONG_MAC_STAT(tx_collision),
111 EFX_ETHTOOL_ULONG_MAC_STAT(tx_single_collision),
112 EFX_ETHTOOL_ULONG_MAC_STAT(tx_multiple_collision),
113 EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_collision),
114 EFX_ETHTOOL_ULONG_MAC_STAT(tx_deferred),
115 EFX_ETHTOOL_ULONG_MAC_STAT(tx_late_collision),
116 EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_deferred),
117 EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp),
118 EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error),
119 EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error),
120 EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
121 EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
122 EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
123 EFX_ETHTOOL_ULONG_MAC_STAT(rx_packets),
124 EFX_ETHTOOL_ULONG_MAC_STAT(rx_good),
125 EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad),
126 EFX_ETHTOOL_ULONG_MAC_STAT(rx_pause),
127 EFX_ETHTOOL_ULONG_MAC_STAT(rx_control),
128 EFX_ETHTOOL_ULONG_MAC_STAT(rx_unicast),
129 EFX_ETHTOOL_ULONG_MAC_STAT(rx_multicast),
130 EFX_ETHTOOL_ULONG_MAC_STAT(rx_broadcast),
131 EFX_ETHTOOL_ULONG_MAC_STAT(rx_lt64),
132 EFX_ETHTOOL_ULONG_MAC_STAT(rx_64),
133 EFX_ETHTOOL_ULONG_MAC_STAT(rx_65_to_127),
134 EFX_ETHTOOL_ULONG_MAC_STAT(rx_128_to_255),
135 EFX_ETHTOOL_ULONG_MAC_STAT(rx_256_to_511),
136 EFX_ETHTOOL_ULONG_MAC_STAT(rx_512_to_1023),
137 EFX_ETHTOOL_ULONG_MAC_STAT(rx_1024_to_15xx),
138 EFX_ETHTOOL_ULONG_MAC_STAT(rx_15xx_to_jumbo),
139 EFX_ETHTOOL_ULONG_MAC_STAT(rx_gtjumbo),
140 EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_lt64),
141 EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_64_to_15xx),
142 EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_15xx_to_jumbo),
143 EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_gtjumbo),
144 EFX_ETHTOOL_ULONG_MAC_STAT(rx_overflow),
145 EFX_ETHTOOL_ULONG_MAC_STAT(rx_missed),
146 EFX_ETHTOOL_ULONG_MAC_STAT(rx_false_carrier),
147 EFX_ETHTOOL_ULONG_MAC_STAT(rx_symbol_error),
148 EFX_ETHTOOL_ULONG_MAC_STAT(rx_align_error),
149 EFX_ETHTOOL_ULONG_MAC_STAT(rx_length_error),
150 EFX_ETHTOOL_ULONG_MAC_STAT(rx_internal_error),
151 EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt),
152 EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),
153 EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
154 EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
155 EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
156 EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
157};
158
159/* Number of ethtool statistics */
160#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
161
162/**************************************************************************
163 *
164 * Ethtool operations
165 *
166 **************************************************************************
167 */
168
169/* Identify device by flashing LEDs */
170static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
171{
172 struct efx_nic *efx = net_dev->priv;
173
174 efx->board_info.blink(efx, 1);
175 schedule_timeout_interruptible(seconds * HZ);
176 efx->board_info.blink(efx, 0);
177 return 0;
178}
179
180/* This must be called with rtnl_lock held. */
181int efx_ethtool_get_settings(struct net_device *net_dev,
182 struct ethtool_cmd *ecmd)
183{
184 struct efx_nic *efx = net_dev->priv;
185 int rc;
186
187 mutex_lock(&efx->mac_lock);
188 rc = falcon_xmac_get_settings(efx, ecmd);
189 mutex_unlock(&efx->mac_lock);
190
191 return rc;
192}
193
194/* This must be called with rtnl_lock held. */
195int efx_ethtool_set_settings(struct net_device *net_dev,
196 struct ethtool_cmd *ecmd)
197{
198 struct efx_nic *efx = net_dev->priv;
199 int rc;
200
201 mutex_lock(&efx->mac_lock);
202 rc = falcon_xmac_set_settings(efx, ecmd);
203 mutex_unlock(&efx->mac_lock);
204 if (!rc)
205 efx_reconfigure_port(efx);
206
207 return rc;
208}
209
210static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
211 struct ethtool_drvinfo *info)
212{
213 struct efx_nic *efx = net_dev->priv;
214
215 strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
216 strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
217 strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
218}
219
220static int efx_ethtool_get_stats_count(struct net_device *net_dev)
221{
222 return EFX_ETHTOOL_NUM_STATS;
223}
224
225static void efx_ethtool_get_strings(struct net_device *net_dev,
226 u32 string_set, u8 *strings)
227{
228 struct ethtool_string *ethtool_strings =
229 (struct ethtool_string *)strings;
230 int i;
231
232 if (string_set == ETH_SS_STATS)
233 for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
234 strncpy(ethtool_strings[i].name,
235 efx_ethtool_stats[i].name,
236 sizeof(ethtool_strings[i].name));
237}
238
239static void efx_ethtool_get_stats(struct net_device *net_dev,
240 struct ethtool_stats *stats,
241 u64 *data)
242{
243 struct efx_nic *efx = net_dev->priv;
244 struct efx_mac_stats *mac_stats = &efx->mac_stats;
245 struct efx_ethtool_stat *stat;
246 struct efx_channel *channel;
247 int i;
248
249 EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
250
251 /* Update MAC and NIC statistics */
252 net_dev->get_stats(net_dev);
253
254 /* Fill detailed statistics buffer */
255 for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
256 stat = &efx_ethtool_stats[i];
257 switch (stat->source) {
258 case EFX_ETHTOOL_STAT_SOURCE_mac_stats:
259 data[i] = stat->get_stat((void *)mac_stats +
260 stat->offset);
261 break;
262 case EFX_ETHTOOL_STAT_SOURCE_nic:
263 data[i] = stat->get_stat((void *)efx + stat->offset);
264 break;
265 case EFX_ETHTOOL_STAT_SOURCE_channel:
266 data[i] = 0;
267 efx_for_each_channel(channel, efx)
268 data[i] += stat->get_stat((void *)channel +
269 stat->offset);
270 break;
271 }
272 }
273}
274
Ben Hutchingsb9b39b62008-05-07 12:51:12 +0100275static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
276{
277 int rc;
278
279 /* Our TSO requires TX checksumming, so force TX checksumming
280 * on when TSO is enabled.
281 */
282 if (enable) {
283 rc = efx_ethtool_set_tx_csum(net_dev, 1);
284 if (rc)
285 return rc;
286 }
287
288 return ethtool_op_set_tso(net_dev, enable);
289}
290
Ben Hutchings8ceee662008-04-27 12:55:59 +0100291static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
292{
293 struct efx_nic *efx = net_dev->priv;
294 int rc;
295
296 rc = ethtool_op_set_tx_csum(net_dev, enable);
297 if (rc)
298 return rc;
299
300 efx_flush_queues(efx);
301
Ben Hutchingsb9b39b62008-05-07 12:51:12 +0100302 /* Our TSO requires TX checksumming, so disable TSO when
303 * checksumming is disabled
304 */
305 if (!enable) {
306 rc = efx_ethtool_set_tso(net_dev, 0);
307 if (rc)
308 return rc;
309 }
310
Ben Hutchings8ceee662008-04-27 12:55:59 +0100311 return 0;
312}
313
314static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
315{
316 struct efx_nic *efx = net_dev->priv;
317
318 /* No way to stop the hardware doing the checks; we just
319 * ignore the result.
320 */
321 efx->rx_checksum_enabled = (enable ? 1 : 0);
322
323 return 0;
324}
325
326static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
327{
328 struct efx_nic *efx = net_dev->priv;
329
330 return efx->rx_checksum_enabled;
331}
332
333/* Restart autonegotiation */
334static int efx_ethtool_nway_reset(struct net_device *net_dev)
335{
336 struct efx_nic *efx = net_dev->priv;
337
338 return mii_nway_restart(&efx->mii);
339}
340
341static u32 efx_ethtool_get_link(struct net_device *net_dev)
342{
343 struct efx_nic *efx = net_dev->priv;
344
345 return efx->link_up;
346}
347
348static int efx_ethtool_get_coalesce(struct net_device *net_dev,
349 struct ethtool_coalesce *coalesce)
350{
351 struct efx_nic *efx = net_dev->priv;
352 struct efx_tx_queue *tx_queue;
353 struct efx_rx_queue *rx_queue;
354 struct efx_channel *channel;
355
356 memset(coalesce, 0, sizeof(*coalesce));
357
358 /* Find lowest IRQ moderation across all used TX queues */
359 coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
360 efx_for_each_tx_queue(tx_queue, efx) {
361 channel = tx_queue->channel;
362 if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
363 if (channel->used_flags != EFX_USED_BY_RX_TX)
364 coalesce->tx_coalesce_usecs_irq =
365 channel->irq_moderation;
366 else
367 coalesce->tx_coalesce_usecs_irq = 0;
368 }
369 }
370
371 /* Find lowest IRQ moderation across all used RX queues */
372 coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
373 efx_for_each_rx_queue(rx_queue, efx) {
374 channel = rx_queue->channel;
375 if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
376 coalesce->rx_coalesce_usecs_irq =
377 channel->irq_moderation;
378 }
379
380 return 0;
381}
382
383/* Set coalescing parameters
384 * The difficulties occur for shared channels
385 */
386static int efx_ethtool_set_coalesce(struct net_device *net_dev,
387 struct ethtool_coalesce *coalesce)
388{
389 struct efx_nic *efx = net_dev->priv;
390 struct efx_channel *channel;
391 struct efx_tx_queue *tx_queue;
392 unsigned tx_usecs, rx_usecs;
393
394 if (coalesce->use_adaptive_rx_coalesce ||
395 coalesce->use_adaptive_tx_coalesce)
396 return -EOPNOTSUPP;
397
398 if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
399 EFX_ERR(efx, "invalid coalescing setting. "
400 "Only rx/tx_coalesce_usecs_irq are supported\n");
401 return -EOPNOTSUPP;
402 }
403
404 rx_usecs = coalesce->rx_coalesce_usecs_irq;
405 tx_usecs = coalesce->tx_coalesce_usecs_irq;
406
407 /* If the channel is shared only allow RX parameters to be set */
408 efx_for_each_tx_queue(tx_queue, efx) {
409 if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
410 tx_usecs) {
411 EFX_ERR(efx, "Channel is shared. "
412 "Only RX coalescing may be set\n");
413 return -EOPNOTSUPP;
414 }
415 }
416
417 efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
418
419 /* Reset channel to pick up new moderation value. Note that
420 * this may change the value of the irq_moderation field
421 * (e.g. to allow for hardware timer granularity).
422 */
423 efx_for_each_channel(channel, efx)
424 falcon_set_int_moderation(channel);
425
426 return 0;
427}
428
429static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
430 struct ethtool_pauseparam *pause)
431{
432 struct efx_nic *efx = net_dev->priv;
433 enum efx_fc_type flow_control = efx->flow_control;
434 int rc;
435
436 flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
437 flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
438 flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
439 flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
440
441 /* Try to push the pause parameters */
442 mutex_lock(&efx->mac_lock);
443 rc = falcon_xmac_set_pause(efx, flow_control);
444 mutex_unlock(&efx->mac_lock);
445
446 if (!rc)
447 efx_reconfigure_port(efx);
448
449 return rc;
450}
451
452static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
453 struct ethtool_pauseparam *pause)
454{
455 struct efx_nic *efx = net_dev->priv;
456
457 pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
458 pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
459 pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
460}
461
462
463struct ethtool_ops efx_ethtool_ops = {
464 .get_settings = efx_ethtool_get_settings,
465 .set_settings = efx_ethtool_set_settings,
466 .get_drvinfo = efx_ethtool_get_drvinfo,
467 .nway_reset = efx_ethtool_nway_reset,
468 .get_link = efx_ethtool_get_link,
469 .get_coalesce = efx_ethtool_get_coalesce,
470 .set_coalesce = efx_ethtool_set_coalesce,
471 .get_pauseparam = efx_ethtool_get_pauseparam,
472 .set_pauseparam = efx_ethtool_set_pauseparam,
473 .get_rx_csum = efx_ethtool_get_rx_csum,
474 .set_rx_csum = efx_ethtool_set_rx_csum,
475 .get_tx_csum = ethtool_op_get_tx_csum,
476 .set_tx_csum = efx_ethtool_set_tx_csum,
477 .get_sg = ethtool_op_get_sg,
478 .set_sg = ethtool_op_set_sg,
Ben Hutchingsb9b39b62008-05-07 12:51:12 +0100479 .get_tso = ethtool_op_get_tso,
480 .set_tso = efx_ethtool_set_tso,
Ben Hutchings8ceee662008-04-27 12:55:59 +0100481 .get_flags = ethtool_op_get_flags,
482 .set_flags = ethtool_op_set_flags,
483 .get_strings = efx_ethtool_get_strings,
484 .phys_id = efx_ethtool_phys_id,
485 .get_stats_count = efx_ethtool_get_stats_count,
486 .get_ethtool_stats = efx_ethtool_get_stats,
487};