.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /**************************************************************************** |
---|
2 | 3 | * Driver for Solarflare network controllers and boards |
---|
3 | 4 | * Copyright 2005-2006 Fen Systems Ltd. |
---|
4 | 5 | * Copyright 2006-2013 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 | 6 | */ |
---|
10 | 7 | |
---|
11 | 8 | #include <linux/netdevice.h> |
---|
.. | .. |
---|
16 | 13 | #include "workarounds.h" |
---|
17 | 14 | #include "selftest.h" |
---|
18 | 15 | #include "efx.h" |
---|
| 16 | +#include "efx_channels.h" |
---|
| 17 | +#include "rx_common.h" |
---|
| 18 | +#include "tx_common.h" |
---|
| 19 | +#include "ethtool_common.h" |
---|
19 | 20 | #include "filter.h" |
---|
20 | 21 | #include "nic.h" |
---|
21 | | - |
---|
22 | | -struct efx_sw_stat_desc { |
---|
23 | | - const char *name; |
---|
24 | | - enum { |
---|
25 | | - EFX_ETHTOOL_STAT_SOURCE_nic, |
---|
26 | | - EFX_ETHTOOL_STAT_SOURCE_channel, |
---|
27 | | - EFX_ETHTOOL_STAT_SOURCE_tx_queue |
---|
28 | | - } source; |
---|
29 | | - unsigned offset; |
---|
30 | | - u64(*get_stat) (void *field); /* Reader function */ |
---|
31 | | -}; |
---|
32 | | - |
---|
33 | | -/* Initialiser for a struct efx_sw_stat_desc with type-checking */ |
---|
34 | | -#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \ |
---|
35 | | - get_stat_function) { \ |
---|
36 | | - .name = #stat_name, \ |
---|
37 | | - .source = EFX_ETHTOOL_STAT_SOURCE_##source_name, \ |
---|
38 | | - .offset = ((((field_type *) 0) == \ |
---|
39 | | - &((struct efx_##source_name *)0)->field) ? \ |
---|
40 | | - offsetof(struct efx_##source_name, field) : \ |
---|
41 | | - offsetof(struct efx_##source_name, field)), \ |
---|
42 | | - .get_stat = get_stat_function, \ |
---|
43 | | -} |
---|
44 | | - |
---|
45 | | -static u64 efx_get_uint_stat(void *field) |
---|
46 | | -{ |
---|
47 | | - return *(unsigned int *)field; |
---|
48 | | -} |
---|
49 | | - |
---|
50 | | -static u64 efx_get_atomic_stat(void *field) |
---|
51 | | -{ |
---|
52 | | - return atomic_read((atomic_t *) field); |
---|
53 | | -} |
---|
54 | | - |
---|
55 | | -#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \ |
---|
56 | | - EFX_ETHTOOL_STAT(field, nic, field, \ |
---|
57 | | - atomic_t, efx_get_atomic_stat) |
---|
58 | | - |
---|
59 | | -#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \ |
---|
60 | | - EFX_ETHTOOL_STAT(field, channel, n_##field, \ |
---|
61 | | - unsigned int, efx_get_uint_stat) |
---|
62 | | - |
---|
63 | | -#define EFX_ETHTOOL_UINT_TXQ_STAT(field) \ |
---|
64 | | - EFX_ETHTOOL_STAT(tx_##field, tx_queue, field, \ |
---|
65 | | - unsigned int, efx_get_uint_stat) |
---|
66 | | - |
---|
67 | | -static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { |
---|
68 | | - EFX_ETHTOOL_UINT_TXQ_STAT(merge_events), |
---|
69 | | - EFX_ETHTOOL_UINT_TXQ_STAT(tso_bursts), |
---|
70 | | - EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers), |
---|
71 | | - EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets), |
---|
72 | | - EFX_ETHTOOL_UINT_TXQ_STAT(tso_fallbacks), |
---|
73 | | - EFX_ETHTOOL_UINT_TXQ_STAT(pushes), |
---|
74 | | - EFX_ETHTOOL_UINT_TXQ_STAT(pio_packets), |
---|
75 | | - EFX_ETHTOOL_UINT_TXQ_STAT(cb_packets), |
---|
76 | | - EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset), |
---|
77 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), |
---|
78 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), |
---|
79 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), |
---|
80 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_inner_ip_hdr_chksum_err), |
---|
81 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_inner_tcp_udp_chksum_err), |
---|
82 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_outer_ip_hdr_chksum_err), |
---|
83 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_outer_tcp_udp_chksum_err), |
---|
84 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_eth_crc_err), |
---|
85 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), |
---|
86 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), |
---|
87 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_events), |
---|
88 | | - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_packets), |
---|
89 | | -}; |
---|
90 | | - |
---|
91 | | -#define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc) |
---|
92 | 22 | |
---|
93 | 23 | #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB |
---|
94 | 24 | |
---|
.. | .. |
---|
120 | 50 | return 1; /* cycle on/off once per second */ |
---|
121 | 51 | } |
---|
122 | 52 | |
---|
123 | | - efx->type->set_id_led(efx, mode); |
---|
124 | | - return 0; |
---|
125 | | -} |
---|
126 | | - |
---|
127 | | -/* This must be called with rtnl_lock held. */ |
---|
128 | | -static int |
---|
129 | | -efx_ethtool_get_link_ksettings(struct net_device *net_dev, |
---|
130 | | - struct ethtool_link_ksettings *cmd) |
---|
131 | | -{ |
---|
132 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
133 | | - struct efx_link_state *link_state = &efx->link_state; |
---|
134 | | - |
---|
135 | | - mutex_lock(&efx->mac_lock); |
---|
136 | | - efx->phy_op->get_link_ksettings(efx, cmd); |
---|
137 | | - mutex_unlock(&efx->mac_lock); |
---|
138 | | - |
---|
139 | | - /* Both MACs support pause frames (bidirectional and respond-only) */ |
---|
140 | | - ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); |
---|
141 | | - ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause); |
---|
142 | | - |
---|
143 | | - if (LOOPBACK_INTERNAL(efx)) { |
---|
144 | | - cmd->base.speed = link_state->speed; |
---|
145 | | - cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; |
---|
146 | | - } |
---|
147 | | - |
---|
148 | | - return 0; |
---|
149 | | -} |
---|
150 | | - |
---|
151 | | -/* This must be called with rtnl_lock held. */ |
---|
152 | | -static int |
---|
153 | | -efx_ethtool_set_link_ksettings(struct net_device *net_dev, |
---|
154 | | - const struct ethtool_link_ksettings *cmd) |
---|
155 | | -{ |
---|
156 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
157 | | - int rc; |
---|
158 | | - |
---|
159 | | - /* GMAC does not support 1000Mbps HD */ |
---|
160 | | - if ((cmd->base.speed == SPEED_1000) && |
---|
161 | | - (cmd->base.duplex != DUPLEX_FULL)) { |
---|
162 | | - netif_dbg(efx, drv, efx->net_dev, |
---|
163 | | - "rejecting unsupported 1000Mbps HD setting\n"); |
---|
164 | | - return -EINVAL; |
---|
165 | | - } |
---|
166 | | - |
---|
167 | | - mutex_lock(&efx->mac_lock); |
---|
168 | | - rc = efx->phy_op->set_link_ksettings(efx, cmd); |
---|
169 | | - mutex_unlock(&efx->mac_lock); |
---|
170 | | - return rc; |
---|
171 | | -} |
---|
172 | | - |
---|
173 | | -static void efx_ethtool_get_drvinfo(struct net_device *net_dev, |
---|
174 | | - struct ethtool_drvinfo *info) |
---|
175 | | -{ |
---|
176 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
177 | | - |
---|
178 | | - strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); |
---|
179 | | - strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); |
---|
180 | | - efx_mcdi_print_fwver(efx, info->fw_version, |
---|
181 | | - sizeof(info->fw_version)); |
---|
182 | | - strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); |
---|
| 53 | + return efx_mcdi_set_id_led(efx, mode); |
---|
183 | 54 | } |
---|
184 | 55 | |
---|
185 | 56 | static int efx_ethtool_get_regs_len(struct net_device *net_dev) |
---|
.. | .. |
---|
194 | 65 | |
---|
195 | 66 | regs->version = efx->type->revision; |
---|
196 | 67 | efx_nic_get_regs(efx, buf); |
---|
197 | | -} |
---|
198 | | - |
---|
199 | | -static u32 efx_ethtool_get_msglevel(struct net_device *net_dev) |
---|
200 | | -{ |
---|
201 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
202 | | - return efx->msg_enable; |
---|
203 | | -} |
---|
204 | | - |
---|
205 | | -static void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable) |
---|
206 | | -{ |
---|
207 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
208 | | - efx->msg_enable = msg_enable; |
---|
209 | | -} |
---|
210 | | - |
---|
211 | | -/** |
---|
212 | | - * efx_fill_test - fill in an individual self-test entry |
---|
213 | | - * @test_index: Index of the test |
---|
214 | | - * @strings: Ethtool strings, or %NULL |
---|
215 | | - * @data: Ethtool test results, or %NULL |
---|
216 | | - * @test: Pointer to test result (used only if data != %NULL) |
---|
217 | | - * @unit_format: Unit name format (e.g. "chan\%d") |
---|
218 | | - * @unit_id: Unit id (e.g. 0 for "chan0") |
---|
219 | | - * @test_format: Test name format (e.g. "loopback.\%s.tx.sent") |
---|
220 | | - * @test_id: Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent") |
---|
221 | | - * |
---|
222 | | - * Fill in an individual self-test entry. |
---|
223 | | - */ |
---|
224 | | -static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data, |
---|
225 | | - int *test, const char *unit_format, int unit_id, |
---|
226 | | - const char *test_format, const char *test_id) |
---|
227 | | -{ |
---|
228 | | - char unit_str[ETH_GSTRING_LEN], test_str[ETH_GSTRING_LEN]; |
---|
229 | | - |
---|
230 | | - /* Fill data value, if applicable */ |
---|
231 | | - if (data) |
---|
232 | | - data[test_index] = *test; |
---|
233 | | - |
---|
234 | | - /* Fill string, if applicable */ |
---|
235 | | - if (strings) { |
---|
236 | | - if (strchr(unit_format, '%')) |
---|
237 | | - snprintf(unit_str, sizeof(unit_str), |
---|
238 | | - unit_format, unit_id); |
---|
239 | | - else |
---|
240 | | - strcpy(unit_str, unit_format); |
---|
241 | | - snprintf(test_str, sizeof(test_str), test_format, test_id); |
---|
242 | | - snprintf(strings + test_index * ETH_GSTRING_LEN, |
---|
243 | | - ETH_GSTRING_LEN, |
---|
244 | | - "%-6s %-24s", unit_str, test_str); |
---|
245 | | - } |
---|
246 | | -} |
---|
247 | | - |
---|
248 | | -#define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel |
---|
249 | | -#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue |
---|
250 | | -#define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue |
---|
251 | | -#define EFX_LOOPBACK_NAME(_mode, _counter) \ |
---|
252 | | - "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode) |
---|
253 | | - |
---|
254 | | -/** |
---|
255 | | - * efx_fill_loopback_test - fill in a block of loopback self-test entries |
---|
256 | | - * @efx: Efx NIC |
---|
257 | | - * @lb_tests: Efx loopback self-test results structure |
---|
258 | | - * @mode: Loopback test mode |
---|
259 | | - * @test_index: Starting index of the test |
---|
260 | | - * @strings: Ethtool strings, or %NULL |
---|
261 | | - * @data: Ethtool test results, or %NULL |
---|
262 | | - * |
---|
263 | | - * Fill in a block of loopback self-test entries. Return new test |
---|
264 | | - * index. |
---|
265 | | - */ |
---|
266 | | -static int efx_fill_loopback_test(struct efx_nic *efx, |
---|
267 | | - struct efx_loopback_self_tests *lb_tests, |
---|
268 | | - enum efx_loopback_mode mode, |
---|
269 | | - unsigned int test_index, |
---|
270 | | - u8 *strings, u64 *data) |
---|
271 | | -{ |
---|
272 | | - struct efx_channel *channel = |
---|
273 | | - efx_get_channel(efx, efx->tx_channel_offset); |
---|
274 | | - struct efx_tx_queue *tx_queue; |
---|
275 | | - |
---|
276 | | - efx_for_each_channel_tx_queue(tx_queue, channel) { |
---|
277 | | - efx_fill_test(test_index++, strings, data, |
---|
278 | | - &lb_tests->tx_sent[tx_queue->queue], |
---|
279 | | - EFX_TX_QUEUE_NAME(tx_queue), |
---|
280 | | - EFX_LOOPBACK_NAME(mode, "tx_sent")); |
---|
281 | | - efx_fill_test(test_index++, strings, data, |
---|
282 | | - &lb_tests->tx_done[tx_queue->queue], |
---|
283 | | - EFX_TX_QUEUE_NAME(tx_queue), |
---|
284 | | - EFX_LOOPBACK_NAME(mode, "tx_done")); |
---|
285 | | - } |
---|
286 | | - efx_fill_test(test_index++, strings, data, |
---|
287 | | - &lb_tests->rx_good, |
---|
288 | | - "rx", 0, |
---|
289 | | - EFX_LOOPBACK_NAME(mode, "rx_good")); |
---|
290 | | - efx_fill_test(test_index++, strings, data, |
---|
291 | | - &lb_tests->rx_bad, |
---|
292 | | - "rx", 0, |
---|
293 | | - EFX_LOOPBACK_NAME(mode, "rx_bad")); |
---|
294 | | - |
---|
295 | | - return test_index; |
---|
296 | | -} |
---|
297 | | - |
---|
298 | | -/** |
---|
299 | | - * efx_ethtool_fill_self_tests - get self-test details |
---|
300 | | - * @efx: Efx NIC |
---|
301 | | - * @tests: Efx self-test results structure, or %NULL |
---|
302 | | - * @strings: Ethtool strings, or %NULL |
---|
303 | | - * @data: Ethtool test results, or %NULL |
---|
304 | | - * |
---|
305 | | - * Get self-test number of strings, strings, and/or test results. |
---|
306 | | - * Return number of strings (== number of test results). |
---|
307 | | - * |
---|
308 | | - * The reason for merging these three functions is to make sure that |
---|
309 | | - * they can never be inconsistent. |
---|
310 | | - */ |
---|
311 | | -static int efx_ethtool_fill_self_tests(struct efx_nic *efx, |
---|
312 | | - struct efx_self_tests *tests, |
---|
313 | | - u8 *strings, u64 *data) |
---|
314 | | -{ |
---|
315 | | - struct efx_channel *channel; |
---|
316 | | - unsigned int n = 0, i; |
---|
317 | | - enum efx_loopback_mode mode; |
---|
318 | | - |
---|
319 | | - efx_fill_test(n++, strings, data, &tests->phy_alive, |
---|
320 | | - "phy", 0, "alive", NULL); |
---|
321 | | - efx_fill_test(n++, strings, data, &tests->nvram, |
---|
322 | | - "core", 0, "nvram", NULL); |
---|
323 | | - efx_fill_test(n++, strings, data, &tests->interrupt, |
---|
324 | | - "core", 0, "interrupt", NULL); |
---|
325 | | - |
---|
326 | | - /* Event queues */ |
---|
327 | | - efx_for_each_channel(channel, efx) { |
---|
328 | | - efx_fill_test(n++, strings, data, |
---|
329 | | - &tests->eventq_dma[channel->channel], |
---|
330 | | - EFX_CHANNEL_NAME(channel), |
---|
331 | | - "eventq.dma", NULL); |
---|
332 | | - efx_fill_test(n++, strings, data, |
---|
333 | | - &tests->eventq_int[channel->channel], |
---|
334 | | - EFX_CHANNEL_NAME(channel), |
---|
335 | | - "eventq.int", NULL); |
---|
336 | | - } |
---|
337 | | - |
---|
338 | | - efx_fill_test(n++, strings, data, &tests->memory, |
---|
339 | | - "core", 0, "memory", NULL); |
---|
340 | | - efx_fill_test(n++, strings, data, &tests->registers, |
---|
341 | | - "core", 0, "registers", NULL); |
---|
342 | | - |
---|
343 | | - if (efx->phy_op->run_tests != NULL) { |
---|
344 | | - EFX_WARN_ON_PARANOID(efx->phy_op->test_name == NULL); |
---|
345 | | - |
---|
346 | | - for (i = 0; true; ++i) { |
---|
347 | | - const char *name; |
---|
348 | | - |
---|
349 | | - EFX_WARN_ON_PARANOID(i >= EFX_MAX_PHY_TESTS); |
---|
350 | | - name = efx->phy_op->test_name(efx, i); |
---|
351 | | - if (name == NULL) |
---|
352 | | - break; |
---|
353 | | - |
---|
354 | | - efx_fill_test(n++, strings, data, &tests->phy_ext[i], |
---|
355 | | - "phy", 0, name, NULL); |
---|
356 | | - } |
---|
357 | | - } |
---|
358 | | - |
---|
359 | | - /* Loopback tests */ |
---|
360 | | - for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { |
---|
361 | | - if (!(efx->loopback_modes & (1 << mode))) |
---|
362 | | - continue; |
---|
363 | | - n = efx_fill_loopback_test(efx, |
---|
364 | | - &tests->loopback[mode], mode, n, |
---|
365 | | - strings, data); |
---|
366 | | - } |
---|
367 | | - |
---|
368 | | - return n; |
---|
369 | | -} |
---|
370 | | - |
---|
371 | | -static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) |
---|
372 | | -{ |
---|
373 | | - size_t n_stats = 0; |
---|
374 | | - struct efx_channel *channel; |
---|
375 | | - |
---|
376 | | - efx_for_each_channel(channel, efx) { |
---|
377 | | - if (efx_channel_has_tx_queues(channel)) { |
---|
378 | | - n_stats++; |
---|
379 | | - if (strings != NULL) { |
---|
380 | | - snprintf(strings, ETH_GSTRING_LEN, |
---|
381 | | - "tx-%u.tx_packets", |
---|
382 | | - channel->tx_queue[0].queue / |
---|
383 | | - EFX_TXQ_TYPES); |
---|
384 | | - |
---|
385 | | - strings += ETH_GSTRING_LEN; |
---|
386 | | - } |
---|
387 | | - } |
---|
388 | | - } |
---|
389 | | - efx_for_each_channel(channel, efx) { |
---|
390 | | - if (efx_channel_has_rx_queue(channel)) { |
---|
391 | | - n_stats++; |
---|
392 | | - if (strings != NULL) { |
---|
393 | | - snprintf(strings, ETH_GSTRING_LEN, |
---|
394 | | - "rx-%d.rx_packets", channel->channel); |
---|
395 | | - strings += ETH_GSTRING_LEN; |
---|
396 | | - } |
---|
397 | | - } |
---|
398 | | - } |
---|
399 | | - return n_stats; |
---|
400 | | -} |
---|
401 | | - |
---|
402 | | -static int efx_ethtool_get_sset_count(struct net_device *net_dev, |
---|
403 | | - int string_set) |
---|
404 | | -{ |
---|
405 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
406 | | - |
---|
407 | | - switch (string_set) { |
---|
408 | | - case ETH_SS_STATS: |
---|
409 | | - return efx->type->describe_stats(efx, NULL) + |
---|
410 | | - EFX_ETHTOOL_SW_STAT_COUNT + |
---|
411 | | - efx_describe_per_queue_stats(efx, NULL) + |
---|
412 | | - efx_ptp_describe_stats(efx, NULL); |
---|
413 | | - case ETH_SS_TEST: |
---|
414 | | - return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL); |
---|
415 | | - default: |
---|
416 | | - return -EINVAL; |
---|
417 | | - } |
---|
418 | | -} |
---|
419 | | - |
---|
420 | | -static void efx_ethtool_get_strings(struct net_device *net_dev, |
---|
421 | | - u32 string_set, u8 *strings) |
---|
422 | | -{ |
---|
423 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
424 | | - int i; |
---|
425 | | - |
---|
426 | | - switch (string_set) { |
---|
427 | | - case ETH_SS_STATS: |
---|
428 | | - strings += (efx->type->describe_stats(efx, strings) * |
---|
429 | | - ETH_GSTRING_LEN); |
---|
430 | | - for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++) |
---|
431 | | - strlcpy(strings + i * ETH_GSTRING_LEN, |
---|
432 | | - efx_sw_stat_desc[i].name, ETH_GSTRING_LEN); |
---|
433 | | - strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN; |
---|
434 | | - strings += (efx_describe_per_queue_stats(efx, strings) * |
---|
435 | | - ETH_GSTRING_LEN); |
---|
436 | | - efx_ptp_describe_stats(efx, strings); |
---|
437 | | - break; |
---|
438 | | - case ETH_SS_TEST: |
---|
439 | | - efx_ethtool_fill_self_tests(efx, NULL, strings, NULL); |
---|
440 | | - break; |
---|
441 | | - default: |
---|
442 | | - /* No other string sets */ |
---|
443 | | - break; |
---|
444 | | - } |
---|
445 | | -} |
---|
446 | | - |
---|
447 | | -static void efx_ethtool_get_stats(struct net_device *net_dev, |
---|
448 | | - struct ethtool_stats *stats, |
---|
449 | | - u64 *data) |
---|
450 | | -{ |
---|
451 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
452 | | - const struct efx_sw_stat_desc *stat; |
---|
453 | | - struct efx_channel *channel; |
---|
454 | | - struct efx_tx_queue *tx_queue; |
---|
455 | | - struct efx_rx_queue *rx_queue; |
---|
456 | | - int i; |
---|
457 | | - |
---|
458 | | - spin_lock_bh(&efx->stats_lock); |
---|
459 | | - |
---|
460 | | - /* Get NIC statistics */ |
---|
461 | | - data += efx->type->update_stats(efx, data, NULL); |
---|
462 | | - |
---|
463 | | - /* Get software statistics */ |
---|
464 | | - for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++) { |
---|
465 | | - stat = &efx_sw_stat_desc[i]; |
---|
466 | | - switch (stat->source) { |
---|
467 | | - case EFX_ETHTOOL_STAT_SOURCE_nic: |
---|
468 | | - data[i] = stat->get_stat((void *)efx + stat->offset); |
---|
469 | | - break; |
---|
470 | | - case EFX_ETHTOOL_STAT_SOURCE_channel: |
---|
471 | | - data[i] = 0; |
---|
472 | | - efx_for_each_channel(channel, efx) |
---|
473 | | - data[i] += stat->get_stat((void *)channel + |
---|
474 | | - stat->offset); |
---|
475 | | - break; |
---|
476 | | - case EFX_ETHTOOL_STAT_SOURCE_tx_queue: |
---|
477 | | - data[i] = 0; |
---|
478 | | - efx_for_each_channel(channel, efx) { |
---|
479 | | - efx_for_each_channel_tx_queue(tx_queue, channel) |
---|
480 | | - data[i] += |
---|
481 | | - stat->get_stat((void *)tx_queue |
---|
482 | | - + stat->offset); |
---|
483 | | - } |
---|
484 | | - break; |
---|
485 | | - } |
---|
486 | | - } |
---|
487 | | - data += EFX_ETHTOOL_SW_STAT_COUNT; |
---|
488 | | - |
---|
489 | | - spin_unlock_bh(&efx->stats_lock); |
---|
490 | | - |
---|
491 | | - efx_for_each_channel(channel, efx) { |
---|
492 | | - if (efx_channel_has_tx_queues(channel)) { |
---|
493 | | - *data = 0; |
---|
494 | | - efx_for_each_channel_tx_queue(tx_queue, channel) { |
---|
495 | | - *data += tx_queue->tx_packets; |
---|
496 | | - } |
---|
497 | | - data++; |
---|
498 | | - } |
---|
499 | | - } |
---|
500 | | - efx_for_each_channel(channel, efx) { |
---|
501 | | - if (efx_channel_has_rx_queue(channel)) { |
---|
502 | | - *data = 0; |
---|
503 | | - efx_for_each_channel_rx_queue(rx_queue, channel) { |
---|
504 | | - *data += rx_queue->rx_packets; |
---|
505 | | - } |
---|
506 | | - data++; |
---|
507 | | - } |
---|
508 | | - } |
---|
509 | | - |
---|
510 | | - efx_ptp_update_stats(efx, data); |
---|
511 | | -} |
---|
512 | | - |
---|
513 | | -static void efx_ethtool_self_test(struct net_device *net_dev, |
---|
514 | | - struct ethtool_test *test, u64 *data) |
---|
515 | | -{ |
---|
516 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
517 | | - struct efx_self_tests *efx_tests; |
---|
518 | | - bool already_up; |
---|
519 | | - int rc = -ENOMEM; |
---|
520 | | - |
---|
521 | | - efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL); |
---|
522 | | - if (!efx_tests) |
---|
523 | | - goto fail; |
---|
524 | | - |
---|
525 | | - if (efx->state != STATE_READY) { |
---|
526 | | - rc = -EBUSY; |
---|
527 | | - goto out; |
---|
528 | | - } |
---|
529 | | - |
---|
530 | | - netif_info(efx, drv, efx->net_dev, "starting %sline testing\n", |
---|
531 | | - (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); |
---|
532 | | - |
---|
533 | | - /* We need rx buffers and interrupts. */ |
---|
534 | | - already_up = (efx->net_dev->flags & IFF_UP); |
---|
535 | | - if (!already_up) { |
---|
536 | | - rc = dev_open(efx->net_dev); |
---|
537 | | - if (rc) { |
---|
538 | | - netif_err(efx, drv, efx->net_dev, |
---|
539 | | - "failed opening device.\n"); |
---|
540 | | - goto out; |
---|
541 | | - } |
---|
542 | | - } |
---|
543 | | - |
---|
544 | | - rc = efx_selftest(efx, efx_tests, test->flags); |
---|
545 | | - |
---|
546 | | - if (!already_up) |
---|
547 | | - dev_close(efx->net_dev); |
---|
548 | | - |
---|
549 | | - netif_info(efx, drv, efx->net_dev, "%s %sline self-tests\n", |
---|
550 | | - rc == 0 ? "passed" : "failed", |
---|
551 | | - (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); |
---|
552 | | - |
---|
553 | | -out: |
---|
554 | | - efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data); |
---|
555 | | - kfree(efx_tests); |
---|
556 | | -fail: |
---|
557 | | - if (rc) |
---|
558 | | - test->flags |= ETH_TEST_FL_FAILED; |
---|
559 | | -} |
---|
560 | | - |
---|
561 | | -/* Restart autonegotiation */ |
---|
562 | | -static int efx_ethtool_nway_reset(struct net_device *net_dev) |
---|
563 | | -{ |
---|
564 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
565 | | - |
---|
566 | | - return mdio45_nway_restart(&efx->mdio); |
---|
567 | 68 | } |
---|
568 | 69 | |
---|
569 | 70 | /* |
---|
.. | .. |
---|
621 | 122 | unsigned int tx_usecs, rx_usecs; |
---|
622 | 123 | bool adaptive, rx_may_override_tx; |
---|
623 | 124 | int rc; |
---|
624 | | - |
---|
625 | | - if (coalesce->use_adaptive_tx_coalesce) |
---|
626 | | - return -EINVAL; |
---|
627 | 125 | |
---|
628 | 126 | efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive); |
---|
629 | 127 | |
---|
.. | .. |
---|
693 | 191 | return efx_realloc_channels(efx, ring->rx_pending, txq_entries); |
---|
694 | 192 | } |
---|
695 | 193 | |
---|
696 | | -static int efx_ethtool_set_pauseparam(struct net_device *net_dev, |
---|
697 | | - struct ethtool_pauseparam *pause) |
---|
698 | | -{ |
---|
699 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
700 | | - u8 wanted_fc, old_fc; |
---|
701 | | - u32 old_adv; |
---|
702 | | - int rc = 0; |
---|
703 | | - |
---|
704 | | - mutex_lock(&efx->mac_lock); |
---|
705 | | - |
---|
706 | | - wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | |
---|
707 | | - (pause->tx_pause ? EFX_FC_TX : 0) | |
---|
708 | | - (pause->autoneg ? EFX_FC_AUTO : 0)); |
---|
709 | | - |
---|
710 | | - if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { |
---|
711 | | - netif_dbg(efx, drv, efx->net_dev, |
---|
712 | | - "Flow control unsupported: tx ON rx OFF\n"); |
---|
713 | | - rc = -EINVAL; |
---|
714 | | - goto out; |
---|
715 | | - } |
---|
716 | | - |
---|
717 | | - if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising[0]) { |
---|
718 | | - netif_dbg(efx, drv, efx->net_dev, |
---|
719 | | - "Autonegotiation is disabled\n"); |
---|
720 | | - rc = -EINVAL; |
---|
721 | | - goto out; |
---|
722 | | - } |
---|
723 | | - |
---|
724 | | - /* Hook for Falcon bug 11482 workaround */ |
---|
725 | | - if (efx->type->prepare_enable_fc_tx && |
---|
726 | | - (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX)) |
---|
727 | | - efx->type->prepare_enable_fc_tx(efx); |
---|
728 | | - |
---|
729 | | - old_adv = efx->link_advertising[0]; |
---|
730 | | - old_fc = efx->wanted_fc; |
---|
731 | | - efx_link_set_wanted_fc(efx, wanted_fc); |
---|
732 | | - if (efx->link_advertising[0] != old_adv || |
---|
733 | | - (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { |
---|
734 | | - rc = efx->phy_op->reconfigure(efx); |
---|
735 | | - if (rc) { |
---|
736 | | - netif_err(efx, drv, efx->net_dev, |
---|
737 | | - "Unable to advertise requested flow " |
---|
738 | | - "control setting\n"); |
---|
739 | | - goto out; |
---|
740 | | - } |
---|
741 | | - } |
---|
742 | | - |
---|
743 | | - /* Reconfigure the MAC. The PHY *may* generate a link state change event |
---|
744 | | - * if the user just changed the advertised capabilities, but there's no |
---|
745 | | - * harm doing this twice */ |
---|
746 | | - efx_mac_reconfigure(efx); |
---|
747 | | - |
---|
748 | | -out: |
---|
749 | | - mutex_unlock(&efx->mac_lock); |
---|
750 | | - |
---|
751 | | - return rc; |
---|
752 | | -} |
---|
753 | | - |
---|
754 | | -static void efx_ethtool_get_pauseparam(struct net_device *net_dev, |
---|
755 | | - struct ethtool_pauseparam *pause) |
---|
756 | | -{ |
---|
757 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
758 | | - |
---|
759 | | - pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX); |
---|
760 | | - pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX); |
---|
761 | | - pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); |
---|
762 | | -} |
---|
763 | | - |
---|
764 | 194 | static void efx_ethtool_get_wol(struct net_device *net_dev, |
---|
765 | 195 | struct ethtool_wolinfo *wol) |
---|
766 | 196 | { |
---|
.. | .. |
---|
774 | 204 | { |
---|
775 | 205 | struct efx_nic *efx = netdev_priv(net_dev); |
---|
776 | 206 | return efx->type->set_wol(efx, wol->wolopts); |
---|
777 | | -} |
---|
778 | | - |
---|
779 | | -static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) |
---|
780 | | -{ |
---|
781 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
782 | | - int rc; |
---|
783 | | - |
---|
784 | | - rc = efx->type->map_reset_flags(flags); |
---|
785 | | - if (rc < 0) |
---|
786 | | - return rc; |
---|
787 | | - |
---|
788 | | - return efx_reset(efx, rc); |
---|
789 | | -} |
---|
790 | | - |
---|
791 | | -/* MAC address mask including only I/G bit */ |
---|
792 | | -static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0}; |
---|
793 | | - |
---|
794 | | -#define IP4_ADDR_FULL_MASK ((__force __be32)~0) |
---|
795 | | -#define IP_PROTO_FULL_MASK 0xFF |
---|
796 | | -#define PORT_FULL_MASK ((__force __be16)~0) |
---|
797 | | -#define ETHER_TYPE_FULL_MASK ((__force __be16)~0) |
---|
798 | | - |
---|
799 | | -static inline void ip6_fill_mask(__be32 *mask) |
---|
800 | | -{ |
---|
801 | | - mask[0] = mask[1] = mask[2] = mask[3] = ~(__be32)0; |
---|
802 | | -} |
---|
803 | | - |
---|
804 | | -static int efx_ethtool_get_class_rule(struct efx_nic *efx, |
---|
805 | | - struct ethtool_rx_flow_spec *rule, |
---|
806 | | - u32 *rss_context) |
---|
807 | | -{ |
---|
808 | | - struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; |
---|
809 | | - struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; |
---|
810 | | - struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; |
---|
811 | | - struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; |
---|
812 | | - struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; |
---|
813 | | - struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; |
---|
814 | | - struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; |
---|
815 | | - struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec; |
---|
816 | | - struct ethhdr *mac_entry = &rule->h_u.ether_spec; |
---|
817 | | - struct ethhdr *mac_mask = &rule->m_u.ether_spec; |
---|
818 | | - struct efx_filter_spec spec; |
---|
819 | | - int rc; |
---|
820 | | - |
---|
821 | | - rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL, |
---|
822 | | - rule->location, &spec); |
---|
823 | | - if (rc) |
---|
824 | | - return rc; |
---|
825 | | - |
---|
826 | | - if (spec.dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP) |
---|
827 | | - rule->ring_cookie = RX_CLS_FLOW_DISC; |
---|
828 | | - else |
---|
829 | | - rule->ring_cookie = spec.dmaq_id; |
---|
830 | | - |
---|
831 | | - if ((spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) && |
---|
832 | | - spec.ether_type == htons(ETH_P_IP) && |
---|
833 | | - (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) && |
---|
834 | | - (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) && |
---|
835 | | - !(spec.match_flags & |
---|
836 | | - ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | |
---|
837 | | - EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST | |
---|
838 | | - EFX_FILTER_MATCH_IP_PROTO | |
---|
839 | | - EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) { |
---|
840 | | - rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ? |
---|
841 | | - TCP_V4_FLOW : UDP_V4_FLOW); |
---|
842 | | - if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) { |
---|
843 | | - ip_entry->ip4dst = spec.loc_host[0]; |
---|
844 | | - ip_mask->ip4dst = IP4_ADDR_FULL_MASK; |
---|
845 | | - } |
---|
846 | | - if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) { |
---|
847 | | - ip_entry->ip4src = spec.rem_host[0]; |
---|
848 | | - ip_mask->ip4src = IP4_ADDR_FULL_MASK; |
---|
849 | | - } |
---|
850 | | - if (spec.match_flags & EFX_FILTER_MATCH_LOC_PORT) { |
---|
851 | | - ip_entry->pdst = spec.loc_port; |
---|
852 | | - ip_mask->pdst = PORT_FULL_MASK; |
---|
853 | | - } |
---|
854 | | - if (spec.match_flags & EFX_FILTER_MATCH_REM_PORT) { |
---|
855 | | - ip_entry->psrc = spec.rem_port; |
---|
856 | | - ip_mask->psrc = PORT_FULL_MASK; |
---|
857 | | - } |
---|
858 | | - } else if ((spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) && |
---|
859 | | - spec.ether_type == htons(ETH_P_IPV6) && |
---|
860 | | - (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) && |
---|
861 | | - (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) && |
---|
862 | | - !(spec.match_flags & |
---|
863 | | - ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | |
---|
864 | | - EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST | |
---|
865 | | - EFX_FILTER_MATCH_IP_PROTO | |
---|
866 | | - EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) { |
---|
867 | | - rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ? |
---|
868 | | - TCP_V6_FLOW : UDP_V6_FLOW); |
---|
869 | | - if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) { |
---|
870 | | - memcpy(ip6_entry->ip6dst, spec.loc_host, |
---|
871 | | - sizeof(ip6_entry->ip6dst)); |
---|
872 | | - ip6_fill_mask(ip6_mask->ip6dst); |
---|
873 | | - } |
---|
874 | | - if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) { |
---|
875 | | - memcpy(ip6_entry->ip6src, spec.rem_host, |
---|
876 | | - sizeof(ip6_entry->ip6src)); |
---|
877 | | - ip6_fill_mask(ip6_mask->ip6src); |
---|
878 | | - } |
---|
879 | | - if (spec.match_flags & EFX_FILTER_MATCH_LOC_PORT) { |
---|
880 | | - ip6_entry->pdst = spec.loc_port; |
---|
881 | | - ip6_mask->pdst = PORT_FULL_MASK; |
---|
882 | | - } |
---|
883 | | - if (spec.match_flags & EFX_FILTER_MATCH_REM_PORT) { |
---|
884 | | - ip6_entry->psrc = spec.rem_port; |
---|
885 | | - ip6_mask->psrc = PORT_FULL_MASK; |
---|
886 | | - } |
---|
887 | | - } else if (!(spec.match_flags & |
---|
888 | | - ~(EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG | |
---|
889 | | - EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_ETHER_TYPE | |
---|
890 | | - EFX_FILTER_MATCH_OUTER_VID))) { |
---|
891 | | - rule->flow_type = ETHER_FLOW; |
---|
892 | | - if (spec.match_flags & |
---|
893 | | - (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) { |
---|
894 | | - ether_addr_copy(mac_entry->h_dest, spec.loc_mac); |
---|
895 | | - if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC) |
---|
896 | | - eth_broadcast_addr(mac_mask->h_dest); |
---|
897 | | - else |
---|
898 | | - ether_addr_copy(mac_mask->h_dest, |
---|
899 | | - mac_addr_ig_mask); |
---|
900 | | - } |
---|
901 | | - if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) { |
---|
902 | | - ether_addr_copy(mac_entry->h_source, spec.rem_mac); |
---|
903 | | - eth_broadcast_addr(mac_mask->h_source); |
---|
904 | | - } |
---|
905 | | - if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) { |
---|
906 | | - mac_entry->h_proto = spec.ether_type; |
---|
907 | | - mac_mask->h_proto = ETHER_TYPE_FULL_MASK; |
---|
908 | | - } |
---|
909 | | - } else if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE && |
---|
910 | | - spec.ether_type == htons(ETH_P_IP) && |
---|
911 | | - !(spec.match_flags & |
---|
912 | | - ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | |
---|
913 | | - EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST | |
---|
914 | | - EFX_FILTER_MATCH_IP_PROTO))) { |
---|
915 | | - rule->flow_type = IPV4_USER_FLOW; |
---|
916 | | - uip_entry->ip_ver = ETH_RX_NFC_IP4; |
---|
917 | | - if (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) { |
---|
918 | | - uip_mask->proto = IP_PROTO_FULL_MASK; |
---|
919 | | - uip_entry->proto = spec.ip_proto; |
---|
920 | | - } |
---|
921 | | - if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) { |
---|
922 | | - uip_entry->ip4dst = spec.loc_host[0]; |
---|
923 | | - uip_mask->ip4dst = IP4_ADDR_FULL_MASK; |
---|
924 | | - } |
---|
925 | | - if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) { |
---|
926 | | - uip_entry->ip4src = spec.rem_host[0]; |
---|
927 | | - uip_mask->ip4src = IP4_ADDR_FULL_MASK; |
---|
928 | | - } |
---|
929 | | - } else if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE && |
---|
930 | | - spec.ether_type == htons(ETH_P_IPV6) && |
---|
931 | | - !(spec.match_flags & |
---|
932 | | - ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | |
---|
933 | | - EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST | |
---|
934 | | - EFX_FILTER_MATCH_IP_PROTO))) { |
---|
935 | | - rule->flow_type = IPV6_USER_FLOW; |
---|
936 | | - if (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) { |
---|
937 | | - uip6_mask->l4_proto = IP_PROTO_FULL_MASK; |
---|
938 | | - uip6_entry->l4_proto = spec.ip_proto; |
---|
939 | | - } |
---|
940 | | - if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) { |
---|
941 | | - memcpy(uip6_entry->ip6dst, spec.loc_host, |
---|
942 | | - sizeof(uip6_entry->ip6dst)); |
---|
943 | | - ip6_fill_mask(uip6_mask->ip6dst); |
---|
944 | | - } |
---|
945 | | - if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) { |
---|
946 | | - memcpy(uip6_entry->ip6src, spec.rem_host, |
---|
947 | | - sizeof(uip6_entry->ip6src)); |
---|
948 | | - ip6_fill_mask(uip6_mask->ip6src); |
---|
949 | | - } |
---|
950 | | - } else { |
---|
951 | | - /* The above should handle all filters that we insert */ |
---|
952 | | - WARN_ON(1); |
---|
953 | | - return -EINVAL; |
---|
954 | | - } |
---|
955 | | - |
---|
956 | | - if (spec.match_flags & EFX_FILTER_MATCH_OUTER_VID) { |
---|
957 | | - rule->flow_type |= FLOW_EXT; |
---|
958 | | - rule->h_ext.vlan_tci = spec.outer_vid; |
---|
959 | | - rule->m_ext.vlan_tci = htons(0xfff); |
---|
960 | | - } |
---|
961 | | - |
---|
962 | | - if (spec.flags & EFX_FILTER_FLAG_RX_RSS) { |
---|
963 | | - rule->flow_type |= FLOW_RSS; |
---|
964 | | - *rss_context = spec.rss_context; |
---|
965 | | - } |
---|
966 | | - |
---|
967 | | - return rc; |
---|
968 | | -} |
---|
969 | | - |
---|
970 | | -static int |
---|
971 | | -efx_ethtool_get_rxnfc(struct net_device *net_dev, |
---|
972 | | - struct ethtool_rxnfc *info, u32 *rule_locs) |
---|
973 | | -{ |
---|
974 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
975 | | - u32 rss_context = 0; |
---|
976 | | - s32 rc = 0; |
---|
977 | | - |
---|
978 | | - switch (info->cmd) { |
---|
979 | | - case ETHTOOL_GRXRINGS: |
---|
980 | | - info->data = efx->n_rx_channels; |
---|
981 | | - return 0; |
---|
982 | | - |
---|
983 | | - case ETHTOOL_GRXFH: { |
---|
984 | | - struct efx_rss_context *ctx = &efx->rss_context; |
---|
985 | | - |
---|
986 | | - mutex_lock(&efx->rss_lock); |
---|
987 | | - if (info->flow_type & FLOW_RSS && info->rss_context) { |
---|
988 | | - ctx = efx_find_rss_context_entry(efx, info->rss_context); |
---|
989 | | - if (!ctx) { |
---|
990 | | - rc = -ENOENT; |
---|
991 | | - goto out_unlock; |
---|
992 | | - } |
---|
993 | | - } |
---|
994 | | - info->data = 0; |
---|
995 | | - if (!efx_rss_active(ctx)) /* No RSS */ |
---|
996 | | - goto out_unlock; |
---|
997 | | - switch (info->flow_type & ~FLOW_RSS) { |
---|
998 | | - case UDP_V4_FLOW: |
---|
999 | | - if (ctx->rx_hash_udp_4tuple) |
---|
1000 | | - /* fall through */ |
---|
1001 | | - case TCP_V4_FLOW: |
---|
1002 | | - info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
---|
1003 | | - /* fall through */ |
---|
1004 | | - case SCTP_V4_FLOW: |
---|
1005 | | - case AH_ESP_V4_FLOW: |
---|
1006 | | - case IPV4_FLOW: |
---|
1007 | | - info->data |= RXH_IP_SRC | RXH_IP_DST; |
---|
1008 | | - break; |
---|
1009 | | - case UDP_V6_FLOW: |
---|
1010 | | - if (ctx->rx_hash_udp_4tuple) |
---|
1011 | | - /* fall through */ |
---|
1012 | | - case TCP_V6_FLOW: |
---|
1013 | | - info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
---|
1014 | | - /* fall through */ |
---|
1015 | | - case SCTP_V6_FLOW: |
---|
1016 | | - case AH_ESP_V6_FLOW: |
---|
1017 | | - case IPV6_FLOW: |
---|
1018 | | - info->data |= RXH_IP_SRC | RXH_IP_DST; |
---|
1019 | | - break; |
---|
1020 | | - default: |
---|
1021 | | - break; |
---|
1022 | | - } |
---|
1023 | | -out_unlock: |
---|
1024 | | - mutex_unlock(&efx->rss_lock); |
---|
1025 | | - return rc; |
---|
1026 | | - } |
---|
1027 | | - |
---|
1028 | | - case ETHTOOL_GRXCLSRLCNT: |
---|
1029 | | - info->data = efx_filter_get_rx_id_limit(efx); |
---|
1030 | | - if (info->data == 0) |
---|
1031 | | - return -EOPNOTSUPP; |
---|
1032 | | - info->data |= RX_CLS_LOC_SPECIAL; |
---|
1033 | | - info->rule_cnt = |
---|
1034 | | - efx_filter_count_rx_used(efx, EFX_FILTER_PRI_MANUAL); |
---|
1035 | | - return 0; |
---|
1036 | | - |
---|
1037 | | - case ETHTOOL_GRXCLSRULE: |
---|
1038 | | - if (efx_filter_get_rx_id_limit(efx) == 0) |
---|
1039 | | - return -EOPNOTSUPP; |
---|
1040 | | - rc = efx_ethtool_get_class_rule(efx, &info->fs, &rss_context); |
---|
1041 | | - if (rc < 0) |
---|
1042 | | - return rc; |
---|
1043 | | - if (info->fs.flow_type & FLOW_RSS) |
---|
1044 | | - info->rss_context = rss_context; |
---|
1045 | | - return 0; |
---|
1046 | | - |
---|
1047 | | - case ETHTOOL_GRXCLSRLALL: |
---|
1048 | | - info->data = efx_filter_get_rx_id_limit(efx); |
---|
1049 | | - if (info->data == 0) |
---|
1050 | | - return -EOPNOTSUPP; |
---|
1051 | | - rc = efx_filter_get_rx_ids(efx, EFX_FILTER_PRI_MANUAL, |
---|
1052 | | - rule_locs, info->rule_cnt); |
---|
1053 | | - if (rc < 0) |
---|
1054 | | - return rc; |
---|
1055 | | - info->rule_cnt = rc; |
---|
1056 | | - return 0; |
---|
1057 | | - |
---|
1058 | | - default: |
---|
1059 | | - return -EOPNOTSUPP; |
---|
1060 | | - } |
---|
1061 | | -} |
---|
1062 | | - |
---|
1063 | | -static inline bool ip6_mask_is_full(__be32 mask[4]) |
---|
1064 | | -{ |
---|
1065 | | - return !~(mask[0] & mask[1] & mask[2] & mask[3]); |
---|
1066 | | -} |
---|
1067 | | - |
---|
1068 | | -static inline bool ip6_mask_is_empty(__be32 mask[4]) |
---|
1069 | | -{ |
---|
1070 | | - return !(mask[0] | mask[1] | mask[2] | mask[3]); |
---|
1071 | | -} |
---|
1072 | | - |
---|
1073 | | -static int efx_ethtool_set_class_rule(struct efx_nic *efx, |
---|
1074 | | - struct ethtool_rx_flow_spec *rule, |
---|
1075 | | - u32 rss_context) |
---|
1076 | | -{ |
---|
1077 | | - struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; |
---|
1078 | | - struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; |
---|
1079 | | - struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; |
---|
1080 | | - struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; |
---|
1081 | | - struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; |
---|
1082 | | - struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; |
---|
1083 | | - struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; |
---|
1084 | | - struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec; |
---|
1085 | | - u32 flow_type = rule->flow_type & ~(FLOW_EXT | FLOW_RSS); |
---|
1086 | | - struct ethhdr *mac_entry = &rule->h_u.ether_spec; |
---|
1087 | | - struct ethhdr *mac_mask = &rule->m_u.ether_spec; |
---|
1088 | | - enum efx_filter_flags flags = 0; |
---|
1089 | | - struct efx_filter_spec spec; |
---|
1090 | | - int rc; |
---|
1091 | | - |
---|
1092 | | - /* Check that user wants us to choose the location */ |
---|
1093 | | - if (rule->location != RX_CLS_LOC_ANY) |
---|
1094 | | - return -EINVAL; |
---|
1095 | | - |
---|
1096 | | - /* Range-check ring_cookie */ |
---|
1097 | | - if (rule->ring_cookie >= efx->n_rx_channels && |
---|
1098 | | - rule->ring_cookie != RX_CLS_FLOW_DISC) |
---|
1099 | | - return -EINVAL; |
---|
1100 | | - |
---|
1101 | | - /* Check for unsupported extensions */ |
---|
1102 | | - if ((rule->flow_type & FLOW_EXT) && |
---|
1103 | | - (rule->m_ext.vlan_etype || rule->m_ext.data[0] || |
---|
1104 | | - rule->m_ext.data[1])) |
---|
1105 | | - return -EINVAL; |
---|
1106 | | - |
---|
1107 | | - if (efx->rx_scatter) |
---|
1108 | | - flags |= EFX_FILTER_FLAG_RX_SCATTER; |
---|
1109 | | - if (rule->flow_type & FLOW_RSS) |
---|
1110 | | - flags |= EFX_FILTER_FLAG_RX_RSS; |
---|
1111 | | - |
---|
1112 | | - efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, flags, |
---|
1113 | | - (rule->ring_cookie == RX_CLS_FLOW_DISC) ? |
---|
1114 | | - EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie); |
---|
1115 | | - |
---|
1116 | | - if (rule->flow_type & FLOW_RSS) |
---|
1117 | | - spec.rss_context = rss_context; |
---|
1118 | | - |
---|
1119 | | - switch (flow_type) { |
---|
1120 | | - case TCP_V4_FLOW: |
---|
1121 | | - case UDP_V4_FLOW: |
---|
1122 | | - spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE | |
---|
1123 | | - EFX_FILTER_MATCH_IP_PROTO); |
---|
1124 | | - spec.ether_type = htons(ETH_P_IP); |
---|
1125 | | - spec.ip_proto = flow_type == TCP_V4_FLOW ? IPPROTO_TCP |
---|
1126 | | - : IPPROTO_UDP; |
---|
1127 | | - if (ip_mask->ip4dst) { |
---|
1128 | | - if (ip_mask->ip4dst != IP4_ADDR_FULL_MASK) |
---|
1129 | | - return -EINVAL; |
---|
1130 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST; |
---|
1131 | | - spec.loc_host[0] = ip_entry->ip4dst; |
---|
1132 | | - } |
---|
1133 | | - if (ip_mask->ip4src) { |
---|
1134 | | - if (ip_mask->ip4src != IP4_ADDR_FULL_MASK) |
---|
1135 | | - return -EINVAL; |
---|
1136 | | - spec.match_flags |= EFX_FILTER_MATCH_REM_HOST; |
---|
1137 | | - spec.rem_host[0] = ip_entry->ip4src; |
---|
1138 | | - } |
---|
1139 | | - if (ip_mask->pdst) { |
---|
1140 | | - if (ip_mask->pdst != PORT_FULL_MASK) |
---|
1141 | | - return -EINVAL; |
---|
1142 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_PORT; |
---|
1143 | | - spec.loc_port = ip_entry->pdst; |
---|
1144 | | - } |
---|
1145 | | - if (ip_mask->psrc) { |
---|
1146 | | - if (ip_mask->psrc != PORT_FULL_MASK) |
---|
1147 | | - return -EINVAL; |
---|
1148 | | - spec.match_flags |= EFX_FILTER_MATCH_REM_PORT; |
---|
1149 | | - spec.rem_port = ip_entry->psrc; |
---|
1150 | | - } |
---|
1151 | | - if (ip_mask->tos) |
---|
1152 | | - return -EINVAL; |
---|
1153 | | - break; |
---|
1154 | | - |
---|
1155 | | - case TCP_V6_FLOW: |
---|
1156 | | - case UDP_V6_FLOW: |
---|
1157 | | - spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE | |
---|
1158 | | - EFX_FILTER_MATCH_IP_PROTO); |
---|
1159 | | - spec.ether_type = htons(ETH_P_IPV6); |
---|
1160 | | - spec.ip_proto = flow_type == TCP_V6_FLOW ? IPPROTO_TCP |
---|
1161 | | - : IPPROTO_UDP; |
---|
1162 | | - if (!ip6_mask_is_empty(ip6_mask->ip6dst)) { |
---|
1163 | | - if (!ip6_mask_is_full(ip6_mask->ip6dst)) |
---|
1164 | | - return -EINVAL; |
---|
1165 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST; |
---|
1166 | | - memcpy(spec.loc_host, ip6_entry->ip6dst, sizeof(spec.loc_host)); |
---|
1167 | | - } |
---|
1168 | | - if (!ip6_mask_is_empty(ip6_mask->ip6src)) { |
---|
1169 | | - if (!ip6_mask_is_full(ip6_mask->ip6src)) |
---|
1170 | | - return -EINVAL; |
---|
1171 | | - spec.match_flags |= EFX_FILTER_MATCH_REM_HOST; |
---|
1172 | | - memcpy(spec.rem_host, ip6_entry->ip6src, sizeof(spec.rem_host)); |
---|
1173 | | - } |
---|
1174 | | - if (ip6_mask->pdst) { |
---|
1175 | | - if (ip6_mask->pdst != PORT_FULL_MASK) |
---|
1176 | | - return -EINVAL; |
---|
1177 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_PORT; |
---|
1178 | | - spec.loc_port = ip6_entry->pdst; |
---|
1179 | | - } |
---|
1180 | | - if (ip6_mask->psrc) { |
---|
1181 | | - if (ip6_mask->psrc != PORT_FULL_MASK) |
---|
1182 | | - return -EINVAL; |
---|
1183 | | - spec.match_flags |= EFX_FILTER_MATCH_REM_PORT; |
---|
1184 | | - spec.rem_port = ip6_entry->psrc; |
---|
1185 | | - } |
---|
1186 | | - if (ip6_mask->tclass) |
---|
1187 | | - return -EINVAL; |
---|
1188 | | - break; |
---|
1189 | | - |
---|
1190 | | - case IPV4_USER_FLOW: |
---|
1191 | | - if (uip_mask->l4_4_bytes || uip_mask->tos || uip_mask->ip_ver || |
---|
1192 | | - uip_entry->ip_ver != ETH_RX_NFC_IP4) |
---|
1193 | | - return -EINVAL; |
---|
1194 | | - spec.match_flags = EFX_FILTER_MATCH_ETHER_TYPE; |
---|
1195 | | - spec.ether_type = htons(ETH_P_IP); |
---|
1196 | | - if (uip_mask->ip4dst) { |
---|
1197 | | - if (uip_mask->ip4dst != IP4_ADDR_FULL_MASK) |
---|
1198 | | - return -EINVAL; |
---|
1199 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST; |
---|
1200 | | - spec.loc_host[0] = uip_entry->ip4dst; |
---|
1201 | | - } |
---|
1202 | | - if (uip_mask->ip4src) { |
---|
1203 | | - if (uip_mask->ip4src != IP4_ADDR_FULL_MASK) |
---|
1204 | | - return -EINVAL; |
---|
1205 | | - spec.match_flags |= EFX_FILTER_MATCH_REM_HOST; |
---|
1206 | | - spec.rem_host[0] = uip_entry->ip4src; |
---|
1207 | | - } |
---|
1208 | | - if (uip_mask->proto) { |
---|
1209 | | - if (uip_mask->proto != IP_PROTO_FULL_MASK) |
---|
1210 | | - return -EINVAL; |
---|
1211 | | - spec.match_flags |= EFX_FILTER_MATCH_IP_PROTO; |
---|
1212 | | - spec.ip_proto = uip_entry->proto; |
---|
1213 | | - } |
---|
1214 | | - break; |
---|
1215 | | - |
---|
1216 | | - case IPV6_USER_FLOW: |
---|
1217 | | - if (uip6_mask->l4_4_bytes || uip6_mask->tclass) |
---|
1218 | | - return -EINVAL; |
---|
1219 | | - spec.match_flags = EFX_FILTER_MATCH_ETHER_TYPE; |
---|
1220 | | - spec.ether_type = htons(ETH_P_IPV6); |
---|
1221 | | - if (!ip6_mask_is_empty(uip6_mask->ip6dst)) { |
---|
1222 | | - if (!ip6_mask_is_full(uip6_mask->ip6dst)) |
---|
1223 | | - return -EINVAL; |
---|
1224 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST; |
---|
1225 | | - memcpy(spec.loc_host, uip6_entry->ip6dst, sizeof(spec.loc_host)); |
---|
1226 | | - } |
---|
1227 | | - if (!ip6_mask_is_empty(uip6_mask->ip6src)) { |
---|
1228 | | - if (!ip6_mask_is_full(uip6_mask->ip6src)) |
---|
1229 | | - return -EINVAL; |
---|
1230 | | - spec.match_flags |= EFX_FILTER_MATCH_REM_HOST; |
---|
1231 | | - memcpy(spec.rem_host, uip6_entry->ip6src, sizeof(spec.rem_host)); |
---|
1232 | | - } |
---|
1233 | | - if (uip6_mask->l4_proto) { |
---|
1234 | | - if (uip6_mask->l4_proto != IP_PROTO_FULL_MASK) |
---|
1235 | | - return -EINVAL; |
---|
1236 | | - spec.match_flags |= EFX_FILTER_MATCH_IP_PROTO; |
---|
1237 | | - spec.ip_proto = uip6_entry->l4_proto; |
---|
1238 | | - } |
---|
1239 | | - break; |
---|
1240 | | - |
---|
1241 | | - case ETHER_FLOW: |
---|
1242 | | - if (!is_zero_ether_addr(mac_mask->h_dest)) { |
---|
1243 | | - if (ether_addr_equal(mac_mask->h_dest, |
---|
1244 | | - mac_addr_ig_mask)) |
---|
1245 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG; |
---|
1246 | | - else if (is_broadcast_ether_addr(mac_mask->h_dest)) |
---|
1247 | | - spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC; |
---|
1248 | | - else |
---|
1249 | | - return -EINVAL; |
---|
1250 | | - ether_addr_copy(spec.loc_mac, mac_entry->h_dest); |
---|
1251 | | - } |
---|
1252 | | - if (!is_zero_ether_addr(mac_mask->h_source)) { |
---|
1253 | | - if (!is_broadcast_ether_addr(mac_mask->h_source)) |
---|
1254 | | - return -EINVAL; |
---|
1255 | | - spec.match_flags |= EFX_FILTER_MATCH_REM_MAC; |
---|
1256 | | - ether_addr_copy(spec.rem_mac, mac_entry->h_source); |
---|
1257 | | - } |
---|
1258 | | - if (mac_mask->h_proto) { |
---|
1259 | | - if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK) |
---|
1260 | | - return -EINVAL; |
---|
1261 | | - spec.match_flags |= EFX_FILTER_MATCH_ETHER_TYPE; |
---|
1262 | | - spec.ether_type = mac_entry->h_proto; |
---|
1263 | | - } |
---|
1264 | | - break; |
---|
1265 | | - |
---|
1266 | | - default: |
---|
1267 | | - return -EINVAL; |
---|
1268 | | - } |
---|
1269 | | - |
---|
1270 | | - if ((rule->flow_type & FLOW_EXT) && rule->m_ext.vlan_tci) { |
---|
1271 | | - if (rule->m_ext.vlan_tci != htons(0xfff)) |
---|
1272 | | - return -EINVAL; |
---|
1273 | | - spec.match_flags |= EFX_FILTER_MATCH_OUTER_VID; |
---|
1274 | | - spec.outer_vid = rule->h_ext.vlan_tci; |
---|
1275 | | - } |
---|
1276 | | - |
---|
1277 | | - rc = efx_filter_insert_filter(efx, &spec, true); |
---|
1278 | | - if (rc < 0) |
---|
1279 | | - return rc; |
---|
1280 | | - |
---|
1281 | | - rule->location = rc; |
---|
1282 | | - return 0; |
---|
1283 | | -} |
---|
1284 | | - |
---|
1285 | | -static int efx_ethtool_set_rxnfc(struct net_device *net_dev, |
---|
1286 | | - struct ethtool_rxnfc *info) |
---|
1287 | | -{ |
---|
1288 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1289 | | - |
---|
1290 | | - if (efx_filter_get_rx_id_limit(efx) == 0) |
---|
1291 | | - return -EOPNOTSUPP; |
---|
1292 | | - |
---|
1293 | | - switch (info->cmd) { |
---|
1294 | | - case ETHTOOL_SRXCLSRLINS: |
---|
1295 | | - return efx_ethtool_set_class_rule(efx, &info->fs, |
---|
1296 | | - info->rss_context); |
---|
1297 | | - |
---|
1298 | | - case ETHTOOL_SRXCLSRLDEL: |
---|
1299 | | - return efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_MANUAL, |
---|
1300 | | - info->fs.location); |
---|
1301 | | - |
---|
1302 | | - default: |
---|
1303 | | - return -EOPNOTSUPP; |
---|
1304 | | - } |
---|
1305 | | -} |
---|
1306 | | - |
---|
1307 | | -static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) |
---|
1308 | | -{ |
---|
1309 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1310 | | - |
---|
1311 | | - if (efx->n_rx_channels == 1) |
---|
1312 | | - return 0; |
---|
1313 | | - return ARRAY_SIZE(efx->rss_context.rx_indir_table); |
---|
1314 | | -} |
---|
1315 | | - |
---|
1316 | | -static u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev) |
---|
1317 | | -{ |
---|
1318 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1319 | | - |
---|
1320 | | - return efx->type->rx_hash_key_size; |
---|
1321 | | -} |
---|
1322 | | - |
---|
1323 | | -static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key, |
---|
1324 | | - u8 *hfunc) |
---|
1325 | | -{ |
---|
1326 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1327 | | - int rc; |
---|
1328 | | - |
---|
1329 | | - rc = efx->type->rx_pull_rss_config(efx); |
---|
1330 | | - if (rc) |
---|
1331 | | - return rc; |
---|
1332 | | - |
---|
1333 | | - if (hfunc) |
---|
1334 | | - *hfunc = ETH_RSS_HASH_TOP; |
---|
1335 | | - if (indir) |
---|
1336 | | - memcpy(indir, efx->rss_context.rx_indir_table, |
---|
1337 | | - sizeof(efx->rss_context.rx_indir_table)); |
---|
1338 | | - if (key) |
---|
1339 | | - memcpy(key, efx->rss_context.rx_hash_key, |
---|
1340 | | - efx->type->rx_hash_key_size); |
---|
1341 | | - return 0; |
---|
1342 | | -} |
---|
1343 | | - |
---|
1344 | | -static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir, |
---|
1345 | | - const u8 *key, const u8 hfunc) |
---|
1346 | | -{ |
---|
1347 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1348 | | - |
---|
1349 | | - /* Hash function is Toeplitz, cannot be changed */ |
---|
1350 | | - if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) |
---|
1351 | | - return -EOPNOTSUPP; |
---|
1352 | | - if (!indir && !key) |
---|
1353 | | - return 0; |
---|
1354 | | - |
---|
1355 | | - if (!key) |
---|
1356 | | - key = efx->rss_context.rx_hash_key; |
---|
1357 | | - if (!indir) |
---|
1358 | | - indir = efx->rss_context.rx_indir_table; |
---|
1359 | | - |
---|
1360 | | - return efx->type->rx_push_rss_config(efx, true, indir, key); |
---|
1361 | | -} |
---|
1362 | | - |
---|
1363 | | -static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir, |
---|
1364 | | - u8 *key, u8 *hfunc, u32 rss_context) |
---|
1365 | | -{ |
---|
1366 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1367 | | - struct efx_rss_context *ctx; |
---|
1368 | | - int rc = 0; |
---|
1369 | | - |
---|
1370 | | - if (!efx->type->rx_pull_rss_context_config) |
---|
1371 | | - return -EOPNOTSUPP; |
---|
1372 | | - |
---|
1373 | | - mutex_lock(&efx->rss_lock); |
---|
1374 | | - ctx = efx_find_rss_context_entry(efx, rss_context); |
---|
1375 | | - if (!ctx) { |
---|
1376 | | - rc = -ENOENT; |
---|
1377 | | - goto out_unlock; |
---|
1378 | | - } |
---|
1379 | | - rc = efx->type->rx_pull_rss_context_config(efx, ctx); |
---|
1380 | | - if (rc) |
---|
1381 | | - goto out_unlock; |
---|
1382 | | - |
---|
1383 | | - if (hfunc) |
---|
1384 | | - *hfunc = ETH_RSS_HASH_TOP; |
---|
1385 | | - if (indir) |
---|
1386 | | - memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table)); |
---|
1387 | | - if (key) |
---|
1388 | | - memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size); |
---|
1389 | | -out_unlock: |
---|
1390 | | - mutex_unlock(&efx->rss_lock); |
---|
1391 | | - return rc; |
---|
1392 | | -} |
---|
1393 | | - |
---|
1394 | | -static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, |
---|
1395 | | - const u32 *indir, const u8 *key, |
---|
1396 | | - const u8 hfunc, u32 *rss_context, |
---|
1397 | | - bool delete) |
---|
1398 | | -{ |
---|
1399 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1400 | | - struct efx_rss_context *ctx; |
---|
1401 | | - bool allocated = false; |
---|
1402 | | - int rc; |
---|
1403 | | - |
---|
1404 | | - if (!efx->type->rx_push_rss_context_config) |
---|
1405 | | - return -EOPNOTSUPP; |
---|
1406 | | - /* Hash function is Toeplitz, cannot be changed */ |
---|
1407 | | - if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) |
---|
1408 | | - return -EOPNOTSUPP; |
---|
1409 | | - |
---|
1410 | | - mutex_lock(&efx->rss_lock); |
---|
1411 | | - |
---|
1412 | | - if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) { |
---|
1413 | | - if (delete) { |
---|
1414 | | - /* alloc + delete == Nothing to do */ |
---|
1415 | | - rc = -EINVAL; |
---|
1416 | | - goto out_unlock; |
---|
1417 | | - } |
---|
1418 | | - ctx = efx_alloc_rss_context_entry(efx); |
---|
1419 | | - if (!ctx) { |
---|
1420 | | - rc = -ENOMEM; |
---|
1421 | | - goto out_unlock; |
---|
1422 | | - } |
---|
1423 | | - ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID; |
---|
1424 | | - /* Initialise indir table and key to defaults */ |
---|
1425 | | - efx_set_default_rx_indir_table(efx, ctx); |
---|
1426 | | - netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key)); |
---|
1427 | | - allocated = true; |
---|
1428 | | - } else { |
---|
1429 | | - ctx = efx_find_rss_context_entry(efx, *rss_context); |
---|
1430 | | - if (!ctx) { |
---|
1431 | | - rc = -ENOENT; |
---|
1432 | | - goto out_unlock; |
---|
1433 | | - } |
---|
1434 | | - } |
---|
1435 | | - |
---|
1436 | | - if (delete) { |
---|
1437 | | - /* delete this context */ |
---|
1438 | | - rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL); |
---|
1439 | | - if (!rc) |
---|
1440 | | - efx_free_rss_context_entry(ctx); |
---|
1441 | | - goto out_unlock; |
---|
1442 | | - } |
---|
1443 | | - |
---|
1444 | | - if (!key) |
---|
1445 | | - key = ctx->rx_hash_key; |
---|
1446 | | - if (!indir) |
---|
1447 | | - indir = ctx->rx_indir_table; |
---|
1448 | | - |
---|
1449 | | - rc = efx->type->rx_push_rss_context_config(efx, ctx, indir, key); |
---|
1450 | | - if (rc && allocated) |
---|
1451 | | - efx_free_rss_context_entry(ctx); |
---|
1452 | | - else |
---|
1453 | | - *rss_context = ctx->user_id; |
---|
1454 | | -out_unlock: |
---|
1455 | | - mutex_unlock(&efx->rss_lock); |
---|
1456 | | - return rc; |
---|
1457 | 207 | } |
---|
1458 | 208 | |
---|
1459 | 209 | static int efx_ethtool_get_ts_info(struct net_device *net_dev, |
---|
.. | .. |
---|
1470 | 220 | return 0; |
---|
1471 | 221 | } |
---|
1472 | 222 | |
---|
1473 | | -static int efx_ethtool_get_module_eeprom(struct net_device *net_dev, |
---|
1474 | | - struct ethtool_eeprom *ee, |
---|
1475 | | - u8 *data) |
---|
1476 | | -{ |
---|
1477 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1478 | | - int ret; |
---|
1479 | | - |
---|
1480 | | - if (!efx->phy_op || !efx->phy_op->get_module_eeprom) |
---|
1481 | | - return -EOPNOTSUPP; |
---|
1482 | | - |
---|
1483 | | - mutex_lock(&efx->mac_lock); |
---|
1484 | | - ret = efx->phy_op->get_module_eeprom(efx, ee, data); |
---|
1485 | | - mutex_unlock(&efx->mac_lock); |
---|
1486 | | - |
---|
1487 | | - return ret; |
---|
1488 | | -} |
---|
1489 | | - |
---|
1490 | | -static int efx_ethtool_get_module_info(struct net_device *net_dev, |
---|
1491 | | - struct ethtool_modinfo *modinfo) |
---|
1492 | | -{ |
---|
1493 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1494 | | - int ret; |
---|
1495 | | - |
---|
1496 | | - if (!efx->phy_op || !efx->phy_op->get_module_info) |
---|
1497 | | - return -EOPNOTSUPP; |
---|
1498 | | - |
---|
1499 | | - mutex_lock(&efx->mac_lock); |
---|
1500 | | - ret = efx->phy_op->get_module_info(efx, modinfo); |
---|
1501 | | - mutex_unlock(&efx->mac_lock); |
---|
1502 | | - |
---|
1503 | | - return ret; |
---|
1504 | | -} |
---|
1505 | | - |
---|
1506 | | -static int efx_ethtool_get_fecparam(struct net_device *net_dev, |
---|
1507 | | - struct ethtool_fecparam *fecparam) |
---|
1508 | | -{ |
---|
1509 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1510 | | - int rc; |
---|
1511 | | - |
---|
1512 | | - if (!efx->phy_op || !efx->phy_op->get_fecparam) |
---|
1513 | | - return -EOPNOTSUPP; |
---|
1514 | | - mutex_lock(&efx->mac_lock); |
---|
1515 | | - rc = efx->phy_op->get_fecparam(efx, fecparam); |
---|
1516 | | - mutex_unlock(&efx->mac_lock); |
---|
1517 | | - |
---|
1518 | | - return rc; |
---|
1519 | | -} |
---|
1520 | | - |
---|
1521 | | -static int efx_ethtool_set_fecparam(struct net_device *net_dev, |
---|
1522 | | - struct ethtool_fecparam *fecparam) |
---|
1523 | | -{ |
---|
1524 | | - struct efx_nic *efx = netdev_priv(net_dev); |
---|
1525 | | - int rc; |
---|
1526 | | - |
---|
1527 | | - if (!efx->phy_op || !efx->phy_op->get_fecparam) |
---|
1528 | | - return -EOPNOTSUPP; |
---|
1529 | | - mutex_lock(&efx->mac_lock); |
---|
1530 | | - rc = efx->phy_op->set_fecparam(efx, fecparam); |
---|
1531 | | - mutex_unlock(&efx->mac_lock); |
---|
1532 | | - |
---|
1533 | | - return rc; |
---|
1534 | | -} |
---|
1535 | | - |
---|
1536 | 223 | const struct ethtool_ops efx_ethtool_ops = { |
---|
| 224 | + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
---|
| 225 | + ETHTOOL_COALESCE_USECS_IRQ | |
---|
| 226 | + ETHTOOL_COALESCE_USE_ADAPTIVE_RX, |
---|
1537 | 227 | .get_drvinfo = efx_ethtool_get_drvinfo, |
---|
1538 | 228 | .get_regs_len = efx_ethtool_get_regs_len, |
---|
1539 | 229 | .get_regs = efx_ethtool_get_regs, |
---|
1540 | 230 | .get_msglevel = efx_ethtool_get_msglevel, |
---|
1541 | 231 | .set_msglevel = efx_ethtool_set_msglevel, |
---|
1542 | | - .nway_reset = efx_ethtool_nway_reset, |
---|
1543 | 232 | .get_link = ethtool_op_get_link, |
---|
1544 | 233 | .get_coalesce = efx_ethtool_get_coalesce, |
---|
1545 | 234 | .set_coalesce = efx_ethtool_set_coalesce, |
---|