Merge branch 'for-linus' of git://www.linux-m32r.org/git/takata/linux-2.6_dev
[linux-2.6] / drivers / net / sfc / ethtool.c
1 /****************************************************************************
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
21 static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
22
23 struct ethtool_string {
24         char name[ETH_GSTRING_LEN];
25 };
26
27 struct 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
50 static u64 efx_get_uint_stat(void *field)
51 {
52         return *(unsigned int *)field;
53 }
54
55 static u64 efx_get_ulong_stat(void *field)
56 {
57         return *(unsigned long *)field;
58 }
59
60 static u64 efx_get_u64_stat(void *field)
61 {
62         return *(u64 *) field;
63 }
64
65 static 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
90 static 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 */
170 static 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. */
181 int 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. */
195 int 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
210 static 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
220 static int efx_ethtool_get_stats_count(struct net_device *net_dev)
221 {
222         return EFX_ETHTOOL_NUM_STATS;
223 }
224
225 static 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
239 static 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
275 static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
276 {
277         struct efx_nic *efx = net_dev->priv;
278         int rc;
279
280         rc = ethtool_op_set_tx_csum(net_dev, enable);
281         if (rc)
282                 return rc;
283
284         efx_flush_queues(efx);
285
286         return 0;
287 }
288
289 static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
290 {
291         struct efx_nic *efx = net_dev->priv;
292
293         /* No way to stop the hardware doing the checks; we just
294          * ignore the result.
295          */
296         efx->rx_checksum_enabled = (enable ? 1 : 0);
297
298         return 0;
299 }
300
301 static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
302 {
303         struct efx_nic *efx = net_dev->priv;
304
305         return efx->rx_checksum_enabled;
306 }
307
308 /* Restart autonegotiation */
309 static int efx_ethtool_nway_reset(struct net_device *net_dev)
310 {
311         struct efx_nic *efx = net_dev->priv;
312
313         return mii_nway_restart(&efx->mii);
314 }
315
316 static u32 efx_ethtool_get_link(struct net_device *net_dev)
317 {
318         struct efx_nic *efx = net_dev->priv;
319
320         return efx->link_up;
321 }
322
323 static int efx_ethtool_get_coalesce(struct net_device *net_dev,
324                                     struct ethtool_coalesce *coalesce)
325 {
326         struct efx_nic *efx = net_dev->priv;
327         struct efx_tx_queue *tx_queue;
328         struct efx_rx_queue *rx_queue;
329         struct efx_channel *channel;
330
331         memset(coalesce, 0, sizeof(*coalesce));
332
333         /* Find lowest IRQ moderation across all used TX queues */
334         coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
335         efx_for_each_tx_queue(tx_queue, efx) {
336                 channel = tx_queue->channel;
337                 if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
338                         if (channel->used_flags != EFX_USED_BY_RX_TX)
339                                 coalesce->tx_coalesce_usecs_irq =
340                                         channel->irq_moderation;
341                         else
342                                 coalesce->tx_coalesce_usecs_irq = 0;
343                 }
344         }
345
346         /* Find lowest IRQ moderation across all used RX queues */
347         coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
348         efx_for_each_rx_queue(rx_queue, efx) {
349                 channel = rx_queue->channel;
350                 if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
351                         coalesce->rx_coalesce_usecs_irq =
352                                 channel->irq_moderation;
353         }
354
355         return 0;
356 }
357
358 /* Set coalescing parameters
359  * The difficulties occur for shared channels
360  */
361 static int efx_ethtool_set_coalesce(struct net_device *net_dev,
362                                     struct ethtool_coalesce *coalesce)
363 {
364         struct efx_nic *efx = net_dev->priv;
365         struct efx_channel *channel;
366         struct efx_tx_queue *tx_queue;
367         unsigned tx_usecs, rx_usecs;
368
369         if (coalesce->use_adaptive_rx_coalesce ||
370             coalesce->use_adaptive_tx_coalesce)
371                 return -EOPNOTSUPP;
372
373         if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
374                 EFX_ERR(efx, "invalid coalescing setting. "
375                         "Only rx/tx_coalesce_usecs_irq are supported\n");
376                 return -EOPNOTSUPP;
377         }
378
379         rx_usecs = coalesce->rx_coalesce_usecs_irq;
380         tx_usecs = coalesce->tx_coalesce_usecs_irq;
381
382         /* If the channel is shared only allow RX parameters to be set */
383         efx_for_each_tx_queue(tx_queue, efx) {
384                 if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
385                     tx_usecs) {
386                         EFX_ERR(efx, "Channel is shared. "
387                                 "Only RX coalescing may be set\n");
388                         return -EOPNOTSUPP;
389                 }
390         }
391
392         efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
393
394         /* Reset channel to pick up new moderation value.  Note that
395          * this may change the value of the irq_moderation field
396          * (e.g. to allow for hardware timer granularity).
397          */
398         efx_for_each_channel(channel, efx)
399                 falcon_set_int_moderation(channel);
400
401         return 0;
402 }
403
404 static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
405                                       struct ethtool_pauseparam *pause)
406 {
407         struct efx_nic *efx = net_dev->priv;
408         enum efx_fc_type flow_control = efx->flow_control;
409         int rc;
410
411         flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
412         flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
413         flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
414         flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
415
416         /* Try to push the pause parameters */
417         mutex_lock(&efx->mac_lock);
418         rc = falcon_xmac_set_pause(efx, flow_control);
419         mutex_unlock(&efx->mac_lock);
420
421         if (!rc)
422                 efx_reconfigure_port(efx);
423
424         return rc;
425 }
426
427 static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
428                                        struct ethtool_pauseparam *pause)
429 {
430         struct efx_nic *efx = net_dev->priv;
431
432         pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
433         pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
434         pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
435 }
436
437
438 struct ethtool_ops efx_ethtool_ops = {
439         .get_settings           = efx_ethtool_get_settings,
440         .set_settings           = efx_ethtool_set_settings,
441         .get_drvinfo            = efx_ethtool_get_drvinfo,
442         .nway_reset             = efx_ethtool_nway_reset,
443         .get_link               = efx_ethtool_get_link,
444         .get_coalesce           = efx_ethtool_get_coalesce,
445         .set_coalesce           = efx_ethtool_set_coalesce,
446         .get_pauseparam         = efx_ethtool_get_pauseparam,
447         .set_pauseparam         = efx_ethtool_set_pauseparam,
448         .get_rx_csum            = efx_ethtool_get_rx_csum,
449         .set_rx_csum            = efx_ethtool_set_rx_csum,
450         .get_tx_csum            = ethtool_op_get_tx_csum,
451         .set_tx_csum            = efx_ethtool_set_tx_csum,
452         .get_sg                 = ethtool_op_get_sg,
453         .set_sg                 = ethtool_op_set_sg,
454         .get_flags              = ethtool_op_get_flags,
455         .set_flags              = ethtool_op_set_flags,
456         .get_strings            = efx_ethtool_get_strings,
457         .phys_id                = efx_ethtool_phys_id,
458         .get_stats_count        = efx_ethtool_get_stats_count,
459         .get_ethtool_stats      = efx_ethtool_get_stats,
460 };