blob: dd4430aae7fa4aa5f09b03c5bb86d96395c7ebf9 [file] [log] [blame]
Greg Rosefbb7ddf2013-12-21 06:12:56 +00001/*******************************************************************************
2 *
3 * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
Mitch Williams00e5ec42016-01-15 14:33:10 -08004 * Copyright(c) 2013 - 2016 Intel Corporation.
Greg Rosefbb7ddf2013-12-21 06:12:56 +00005 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
Jesse Brandeburgb8316072014-04-05 07:46:11 +000015 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
Greg Rosefbb7ddf2013-12-21 06:12:56 +000018 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
20 *
21 * Contact Information:
22 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 ******************************************************************************/
26
27/* ethtool support for i40evf */
28#include "i40evf.h"
29
30#include <linux/uaccess.h>
31
Greg Rosefbb7ddf2013-12-21 06:12:56 +000032struct i40evf_stats {
33 char stat_string[ETH_GSTRING_LEN];
34 int stat_offset;
35};
36
37#define I40EVF_STAT(_name, _stat) { \
38 .stat_string = _name, \
39 .stat_offset = offsetof(struct i40evf_adapter, _stat) \
40}
41
42/* All stats are u64, so we don't need to track the size of the field. */
43static const struct i40evf_stats i40evf_gstrings_stats[] = {
44 I40EVF_STAT("rx_bytes", current_stats.rx_bytes),
45 I40EVF_STAT("rx_unicast", current_stats.rx_unicast),
46 I40EVF_STAT("rx_multicast", current_stats.rx_multicast),
47 I40EVF_STAT("rx_broadcast", current_stats.rx_broadcast),
48 I40EVF_STAT("rx_discards", current_stats.rx_discards),
Greg Rosefbb7ddf2013-12-21 06:12:56 +000049 I40EVF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol),
50 I40EVF_STAT("tx_bytes", current_stats.tx_bytes),
51 I40EVF_STAT("tx_unicast", current_stats.tx_unicast),
52 I40EVF_STAT("tx_multicast", current_stats.tx_multicast),
53 I40EVF_STAT("tx_broadcast", current_stats.tx_broadcast),
54 I40EVF_STAT("tx_discards", current_stats.tx_discards),
55 I40EVF_STAT("tx_errors", current_stats.tx_errors),
56};
57
58#define I40EVF_GLOBAL_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats)
Mitch Williamsc7b8d972014-04-04 04:43:08 +000059#define I40EVF_QUEUE_STATS_LEN(_dev) \
Mitch Williams75a64432014-11-11 20:02:42 +000060 (((struct i40evf_adapter *)\
Mitch Williamscc052922014-10-25 03:24:34 +000061 netdev_priv(_dev))->num_active_queues \
Mitch Williamsc7b8d972014-04-04 04:43:08 +000062 * 2 * (sizeof(struct i40e_queue_stats) / sizeof(u64)))
63#define I40EVF_STATS_LEN(_dev) \
64 (I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev))
Greg Rosefbb7ddf2013-12-21 06:12:56 +000065
Mitch Williams00e5ec42016-01-15 14:33:10 -080066static const char i40evf_priv_flags_strings[][ETH_GSTRING_LEN] = {
67 "packet-split",
68};
69
70#define I40EVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40evf_priv_flags_strings)
71
Greg Rosefbb7ddf2013-12-21 06:12:56 +000072/**
73 * i40evf_get_settings - Get Link Speed and Duplex settings
74 * @netdev: network interface device structure
75 * @ecmd: ethtool command
76 *
77 * Reports speed/duplex settings. Because this is a VF, we don't know what
78 * kind of link we really have, so we fake it.
79 **/
80static int i40evf_get_settings(struct net_device *netdev,
81 struct ethtool_cmd *ecmd)
82{
83 /* In the future the VF will be able to query the PF for
84 * some information - for now use a dummy value
85 */
Mitch Williams107f3012014-04-04 04:43:09 +000086 ecmd->supported = 0;
Greg Rosefbb7ddf2013-12-21 06:12:56 +000087 ecmd->autoneg = AUTONEG_DISABLE;
88 ecmd->transceiver = XCVR_DUMMY1;
89 ecmd->port = PORT_NONE;
90
91 return 0;
92}
93
94/**
95 * i40evf_get_sset_count - Get length of string set
96 * @netdev: network interface device structure
97 * @sset: id of string set
98 *
99 * Reports size of string table. This driver only supports
100 * strings for statistics.
101 **/
102static int i40evf_get_sset_count(struct net_device *netdev, int sset)
103{
104 if (sset == ETH_SS_STATS)
Mitch Williamsc7b8d972014-04-04 04:43:08 +0000105 return I40EVF_STATS_LEN(netdev);
Mitch Williams00e5ec42016-01-15 14:33:10 -0800106 else if (sset == ETH_SS_PRIV_FLAGS)
107 return I40EVF_PRIV_FLAGS_STR_LEN;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000108 else
Mitch Williamsc7b8d972014-04-04 04:43:08 +0000109 return -EINVAL;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000110}
111
112/**
113 * i40evf_get_ethtool_stats - report device statistics
114 * @netdev: network interface device structure
115 * @stats: ethtool statistics structure
116 * @data: pointer to data buffer
117 *
118 * All statistics are added to the data buffer as an array of u64.
119 **/
120static void i40evf_get_ethtool_stats(struct net_device *netdev,
121 struct ethtool_stats *stats, u64 *data)
122{
123 struct i40evf_adapter *adapter = netdev_priv(netdev);
124 int i, j;
125 char *p;
126
127 for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) {
128 p = (char *)adapter + i40evf_gstrings_stats[i].stat_offset;
129 data[i] = *(u64 *)p;
130 }
Mitch Williamscc052922014-10-25 03:24:34 +0000131 for (j = 0; j < adapter->num_active_queues; j++) {
Mitch Williams0dd438d2015-10-26 19:44:40 -0400132 data[i++] = adapter->tx_rings[j].stats.packets;
133 data[i++] = adapter->tx_rings[j].stats.bytes;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000134 }
Mitch Williamscc052922014-10-25 03:24:34 +0000135 for (j = 0; j < adapter->num_active_queues; j++) {
Mitch Williams0dd438d2015-10-26 19:44:40 -0400136 data[i++] = adapter->rx_rings[j].stats.packets;
137 data[i++] = adapter->rx_rings[j].stats.bytes;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000138 }
139}
140
141/**
142 * i40evf_get_strings - Get string set
143 * @netdev: network interface device structure
144 * @sset: id of string set
145 * @data: buffer for string data
146 *
147 * Builds stats string table.
148 **/
149static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
150{
151 struct i40evf_adapter *adapter = netdev_priv(netdev);
152 u8 *p = data;
153 int i;
154
155 if (sset == ETH_SS_STATS) {
156 for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) {
157 memcpy(p, i40evf_gstrings_stats[i].stat_string,
158 ETH_GSTRING_LEN);
159 p += ETH_GSTRING_LEN;
160 }
Mitch Williamscc052922014-10-25 03:24:34 +0000161 for (i = 0; i < adapter->num_active_queues; i++) {
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000162 snprintf(p, ETH_GSTRING_LEN, "tx-%u.packets", i);
163 p += ETH_GSTRING_LEN;
164 snprintf(p, ETH_GSTRING_LEN, "tx-%u.bytes", i);
165 p += ETH_GSTRING_LEN;
166 }
Mitch Williamscc052922014-10-25 03:24:34 +0000167 for (i = 0; i < adapter->num_active_queues; i++) {
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000168 snprintf(p, ETH_GSTRING_LEN, "rx-%u.packets", i);
169 p += ETH_GSTRING_LEN;
170 snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i);
171 p += ETH_GSTRING_LEN;
172 }
Mitch Williams00e5ec42016-01-15 14:33:10 -0800173 } else if (sset == ETH_SS_PRIV_FLAGS) {
174 for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) {
175 memcpy(data, i40evf_priv_flags_strings[i],
176 ETH_GSTRING_LEN);
177 data += ETH_GSTRING_LEN;
178 }
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000179 }
180}
181
182/**
183 * i40evf_get_msglevel - Get debug message level
184 * @netdev: network interface device structure
185 *
186 * Returns current debug message level.
187 **/
188static u32 i40evf_get_msglevel(struct net_device *netdev)
189{
190 struct i40evf_adapter *adapter = netdev_priv(netdev);
Mitch Williams75a64432014-11-11 20:02:42 +0000191
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000192 return adapter->msg_enable;
193}
194
195/**
Ashish Shah0e888982015-02-06 08:52:10 +0000196 * i40evf_set_msglevel - Set debug message level
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000197 * @netdev: network interface device structure
198 * @data: message level
199 *
200 * Set current debug message level. Higher values cause the driver to
201 * be noisier.
202 **/
203static void i40evf_set_msglevel(struct net_device *netdev, u32 data)
204{
205 struct i40evf_adapter *adapter = netdev_priv(netdev);
Mitch Williams75a64432014-11-11 20:02:42 +0000206
Ashish Shah0e888982015-02-06 08:52:10 +0000207 if (I40E_DEBUG_USER & data)
208 adapter->hw.debug_mask = data;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000209 adapter->msg_enable = data;
210}
211
212/**
Jesse Brandeburgb39c1e22014-08-01 13:27:08 -0700213 * i40evf_get_drvinfo - Get driver info
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000214 * @netdev: network interface device structure
215 * @drvinfo: ethool driver info structure
216 *
217 * Returns information about the driver and device for display to the user.
218 **/
219static void i40evf_get_drvinfo(struct net_device *netdev,
220 struct ethtool_drvinfo *drvinfo)
221{
222 struct i40evf_adapter *adapter = netdev_priv(netdev);
223
224 strlcpy(drvinfo->driver, i40evf_driver_name, 32);
225 strlcpy(drvinfo->version, i40evf_driver_version, 32);
Mitch Williamscc470a82015-03-27 00:12:11 -0700226 strlcpy(drvinfo->fw_version, "N/A", 4);
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000227 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
Mitch Williams00e5ec42016-01-15 14:33:10 -0800228 drvinfo->n_priv_flags = I40EVF_PRIV_FLAGS_STR_LEN;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000229}
230
231/**
232 * i40evf_get_ringparam - Get ring parameters
233 * @netdev: network interface device structure
234 * @ring: ethtool ringparam structure
235 *
236 * Returns current ring parameters. TX and RX rings are reported separately,
237 * but the number of rings is not reported.
238 **/
239static void i40evf_get_ringparam(struct net_device *netdev,
Mitch Williams75a64432014-11-11 20:02:42 +0000240 struct ethtool_ringparam *ring)
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000241{
242 struct i40evf_adapter *adapter = netdev_priv(netdev);
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000243
244 ring->rx_max_pending = I40EVF_MAX_RXD;
245 ring->tx_max_pending = I40EVF_MAX_TXD;
Mitch Williamsd732a182014-04-24 06:41:37 +0000246 ring->rx_pending = adapter->rx_desc_count;
247 ring->tx_pending = adapter->tx_desc_count;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000248}
249
250/**
251 * i40evf_set_ringparam - Set ring parameters
252 * @netdev: network interface device structure
253 * @ring: ethtool ringparam structure
254 *
255 * Sets ring parameters. TX and RX rings are controlled separately, but the
256 * number of rings is not specified, so all rings get the same settings.
257 **/
258static int i40evf_set_ringparam(struct net_device *netdev,
259 struct ethtool_ringparam *ring)
260{
261 struct i40evf_adapter *adapter = netdev_priv(netdev);
262 u32 new_rx_count, new_tx_count;
263
264 if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
265 return -EINVAL;
266
267 new_tx_count = clamp_t(u32, ring->tx_pending,
268 I40EVF_MIN_TXD,
269 I40EVF_MAX_TXD);
270 new_tx_count = ALIGN(new_tx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE);
271
272 new_rx_count = clamp_t(u32, ring->rx_pending,
273 I40EVF_MIN_RXD,
274 I40EVF_MAX_RXD);
275 new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE);
276
277 /* if nothing to do return success */
Mitch Williamsd732a182014-04-24 06:41:37 +0000278 if ((new_tx_count == adapter->tx_desc_count) &&
279 (new_rx_count == adapter->rx_desc_count))
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000280 return 0;
281
Mitch Williamsd732a182014-04-24 06:41:37 +0000282 adapter->tx_desc_count = new_tx_count;
283 adapter->rx_desc_count = new_rx_count;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000284
Mitch Williams67c818a2015-06-19 08:56:30 -0700285 if (netif_running(netdev)) {
286 adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
287 schedule_work(&adapter->reset_task);
288 }
Mitch Williamsd732a182014-04-24 06:41:37 +0000289
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000290 return 0;
291}
292
293/**
294 * i40evf_get_coalesce - Get interrupt coalescing settings
295 * @netdev: network interface device structure
296 * @ec: ethtool coalesce structure
297 *
298 * Returns current coalescing settings. This is referred to elsewhere in the
299 * driver as Interrupt Throttle Rate, as this is how the hardware describes
300 * this functionality.
301 **/
302static int i40evf_get_coalesce(struct net_device *netdev,
Mitch Williams75a64432014-11-11 20:02:42 +0000303 struct ethtool_coalesce *ec)
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000304{
305 struct i40evf_adapter *adapter = netdev_priv(netdev);
306 struct i40e_vsi *vsi = &adapter->vsi;
307
308 ec->tx_max_coalesced_frames = vsi->work_limit;
309 ec->rx_max_coalesced_frames = vsi->work_limit;
310
311 if (ITR_IS_DYNAMIC(vsi->rx_itr_setting))
Mitch Williams32f5f542014-04-04 04:43:10 +0000312 ec->use_adaptive_rx_coalesce = 1;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000313
314 if (ITR_IS_DYNAMIC(vsi->tx_itr_setting))
Mitch Williams32f5f542014-04-04 04:43:10 +0000315 ec->use_adaptive_tx_coalesce = 1;
316
317 ec->rx_coalesce_usecs = vsi->rx_itr_setting & ~I40E_ITR_DYNAMIC;
318 ec->tx_coalesce_usecs = vsi->tx_itr_setting & ~I40E_ITR_DYNAMIC;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000319
320 return 0;
321}
322
323/**
324 * i40evf_set_coalesce - Set interrupt coalescing settings
325 * @netdev: network interface device structure
326 * @ec: ethtool coalesce structure
327 *
328 * Change current coalescing settings.
329 **/
330static int i40evf_set_coalesce(struct net_device *netdev,
Mitch Williams75a64432014-11-11 20:02:42 +0000331 struct ethtool_coalesce *ec)
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000332{
333 struct i40evf_adapter *adapter = netdev_priv(netdev);
334 struct i40e_hw *hw = &adapter->hw;
335 struct i40e_vsi *vsi = &adapter->vsi;
336 struct i40e_q_vector *q_vector;
337 int i;
338
Mitch Williams32f5f542014-04-04 04:43:10 +0000339 if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
340 vsi->work_limit = ec->tx_max_coalesced_frames_irq;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000341
Mitch Williams32f5f542014-04-04 04:43:10 +0000342 if ((ec->rx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
343 (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1)))
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000344 vsi->rx_itr_setting = ec->rx_coalesce_usecs;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000345
Mitch Williams32f5f542014-04-04 04:43:10 +0000346 else
347 return -EINVAL;
348
349 if ((ec->tx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
350 (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1)))
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000351 vsi->tx_itr_setting = ec->tx_coalesce_usecs;
Mitch Williams32f5f542014-04-04 04:43:10 +0000352 else if (ec->use_adaptive_tx_coalesce)
353 vsi->tx_itr_setting = (I40E_ITR_DYNAMIC |
354 ITR_REG_TO_USEC(I40E_ITR_RX_DEF));
355 else
356 return -EINVAL;
357
358 if (ec->use_adaptive_rx_coalesce)
359 vsi->rx_itr_setting |= I40E_ITR_DYNAMIC;
360 else
361 vsi->rx_itr_setting &= ~I40E_ITR_DYNAMIC;
362
363 if (ec->use_adaptive_tx_coalesce)
364 vsi->tx_itr_setting |= I40E_ITR_DYNAMIC;
365 else
366 vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000367
368 for (i = 0; i < adapter->num_msix_vectors - NONQ_VECS; i++) {
Mitch Williams7d96ba12015-10-26 19:44:39 -0400369 q_vector = &adapter->q_vectors[i];
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000370 q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
371 wr32(hw, I40E_VFINT_ITRN1(0, i), q_vector->rx.itr);
372 q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
373 wr32(hw, I40E_VFINT_ITRN1(1, i), q_vector->tx.itr);
374 i40e_flush(hw);
375 }
376
377 return 0;
378}
379
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000380/**
381 * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type
382 * @adapter: board private structure
383 * @cmd: ethtool rxnfc command
384 *
385 * Returns Success if the flow is supported, else Invalid Input.
386 **/
387static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter,
388 struct ethtool_rxnfc *cmd)
389{
390 struct i40e_hw *hw = &adapter->hw;
391 u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) |
392 ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32);
393
394 /* We always hash on IP src and dest addresses */
395 cmd->data = RXH_IP_SRC | RXH_IP_DST;
396
397 switch (cmd->flow_type) {
398 case TCP_V4_FLOW:
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400399 if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP))
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000400 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
401 break;
402 case UDP_V4_FLOW:
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400403 if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP))
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000404 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
405 break;
406
407 case SCTP_V4_FLOW:
408 case AH_ESP_V4_FLOW:
409 case AH_V4_FLOW:
410 case ESP_V4_FLOW:
411 case IPV4_FLOW:
412 break;
413
414 case TCP_V6_FLOW:
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400415 if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP))
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000416 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
417 break;
418 case UDP_V6_FLOW:
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400419 if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP))
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000420 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
421 break;
422
423 case SCTP_V6_FLOW:
424 case AH_ESP_V6_FLOW:
425 case AH_V6_FLOW:
426 case ESP_V6_FLOW:
427 case IPV6_FLOW:
428 break;
429 default:
430 cmd->data = 0;
431 return -EINVAL;
432 }
433
434 return 0;
435}
436
437/**
438 * i40evf_get_rxnfc - command to get RX flow classification rules
439 * @netdev: network interface device structure
440 * @cmd: ethtool rxnfc command
441 *
442 * Returns Success if the command is supported.
443 **/
444static int i40evf_get_rxnfc(struct net_device *netdev,
445 struct ethtool_rxnfc *cmd,
446 u32 *rule_locs)
447{
448 struct i40evf_adapter *adapter = netdev_priv(netdev);
449 int ret = -EOPNOTSUPP;
450
451 switch (cmd->cmd) {
452 case ETHTOOL_GRXRINGS:
Mitch Williamscc052922014-10-25 03:24:34 +0000453 cmd->data = adapter->num_active_queues;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000454 ret = 0;
455 break;
456 case ETHTOOL_GRXFH:
457 ret = i40evf_get_rss_hash_opts(adapter, cmd);
458 break;
459 default:
460 break;
461 }
462
463 return ret;
464}
465
466/**
467 * i40evf_set_rss_hash_opt - Enable/Disable flow types for RSS hash
468 * @adapter: board private structure
469 * @cmd: ethtool rxnfc command
470 *
471 * Returns Success if the flow input set is supported.
472 **/
473static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter,
474 struct ethtool_rxnfc *nfc)
475{
476 struct i40e_hw *hw = &adapter->hw;
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800477 u32 flags = adapter->vf_res->vf_offload_flags;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000478
479 u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) |
480 ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32);
481
482 /* RSS does not support anything other than hashing
483 * to queues on src and dst IPs and ports
484 */
485 if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
486 RXH_L4_B_0_1 | RXH_L4_B_2_3))
487 return -EINVAL;
488
489 /* We need at least the IP SRC and DEST fields for hashing */
490 if (!(nfc->data & RXH_IP_SRC) ||
491 !(nfc->data & RXH_IP_DST))
492 return -EINVAL;
493
494 switch (nfc->flow_type) {
495 case TCP_V4_FLOW:
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800496 if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
497 if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
498 hena |=
499 BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
500
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400501 hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800502 } else {
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000503 return -EINVAL;
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800504 }
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000505 break;
506 case TCP_V6_FLOW:
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800507 if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
508 if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
509 hena |=
510 BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK);
511
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400512 hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800513 } else {
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000514 return -EINVAL;
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800515 }
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000516 break;
517 case UDP_V4_FLOW:
Anjali Singhai Jain6e35c042015-12-09 15:50:24 -0800518 if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800519 if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
520 hena |=
521 BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
522 BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP);
523
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400524 hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
525 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
Anjali Singhai Jain6e35c042015-12-09 15:50:24 -0800526 } else {
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000527 return -EINVAL;
528 }
529 break;
530 case UDP_V6_FLOW:
Anjali Singhai Jain6e35c042015-12-09 15:50:24 -0800531 if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
Anjali Singhai Jain3d0da5b2015-12-22 14:25:05 -0800532 if (flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
533 hena |=
534 BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
535 BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP);
536
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400537 hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
538 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
Anjali Singhai Jain6e35c042015-12-09 15:50:24 -0800539 } else {
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000540 return -EINVAL;
541 }
542 break;
543 case AH_ESP_V4_FLOW:
544 case AH_V4_FLOW:
545 case ESP_V4_FLOW:
546 case SCTP_V4_FLOW:
547 if ((nfc->data & RXH_L4_B_0_1) ||
548 (nfc->data & RXH_L4_B_2_3))
549 return -EINVAL;
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400550 hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000551 break;
552 case AH_ESP_V6_FLOW:
553 case AH_V6_FLOW:
554 case ESP_V6_FLOW:
555 case SCTP_V6_FLOW:
556 if ((nfc->data & RXH_L4_B_0_1) ||
557 (nfc->data & RXH_L4_B_2_3))
558 return -EINVAL;
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400559 hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000560 break;
561 case IPV4_FLOW:
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400562 hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
563 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000564 break;
565 case IPV6_FLOW:
Jesse Brandeburg41a1d042015-06-04 16:24:02 -0400566 hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
567 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000568 break;
569 default:
570 return -EINVAL;
571 }
572
573 wr32(hw, I40E_VFQF_HENA(0), (u32)hena);
574 wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
575 i40e_flush(hw);
576
577 return 0;
578}
579
580/**
581 * i40evf_set_rxnfc - command to set RX flow classification rules
582 * @netdev: network interface device structure
583 * @cmd: ethtool rxnfc command
584 *
585 * Returns Success if the command is supported.
586 **/
587static int i40evf_set_rxnfc(struct net_device *netdev,
588 struct ethtool_rxnfc *cmd)
589{
590 struct i40evf_adapter *adapter = netdev_priv(netdev);
591 int ret = -EOPNOTSUPP;
592
593 switch (cmd->cmd) {
594 case ETHTOOL_SRXFH:
595 ret = i40evf_set_rss_hash_opt(adapter, cmd);
596 break;
597 default:
598 break;
599 }
600
601 return ret;
602}
603
604/**
605 * i40evf_get_channels: get the number of channels supported by the device
606 * @netdev: network interface device structure
607 * @ch: channel information structure
608 *
609 * For the purposes of our device, we only use combined channels, i.e. a tx/rx
610 * queue pair. Report one extra channel to match our "other" MSI-X vector.
611 **/
612static void i40evf_get_channels(struct net_device *netdev,
613 struct ethtool_channels *ch)
614{
615 struct i40evf_adapter *adapter = netdev_priv(netdev);
616
617 /* Report maximum channels */
Mitch Williamscc052922014-10-25 03:24:34 +0000618 ch->max_combined = adapter->num_active_queues;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000619
620 ch->max_other = NONQ_VECS;
621 ch->other_count = NONQ_VECS;
622
Mitch Williamscc052922014-10-25 03:24:34 +0000623 ch->combined_count = adapter->num_active_queues;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000624}
625
626/**
627 * i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size
628 * @netdev: network interface device structure
629 *
630 * Returns the table size.
631 **/
632static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev)
633{
634 return (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4;
635}
636
637/**
Ben Hutchingsfe62d002014-05-15 01:25:27 +0100638 * i40evf_get_rxfh - get the rx flow hash indirection table
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000639 * @netdev: network interface device structure
640 * @indir: indirection table
Mitch Williams2cda3f32014-11-11 20:02:31 +0000641 * @key: hash key
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000642 *
643 * Reads the indirection table directly from the hardware. Always returns 0.
644 **/
Eyal Perry892311f2014-12-02 18:12:10 +0200645static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
646 u8 *hfunc)
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000647{
648 struct i40evf_adapter *adapter = netdev_priv(netdev);
Helin Zhang90b02b42015-10-26 19:44:33 -0400649 struct i40e_vsi *vsi = &adapter->vsi;
650 u8 *seed = NULL, *lut;
651 int ret;
652 u16 i;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000653
Eyal Perry892311f2014-12-02 18:12:10 +0200654 if (hfunc)
655 *hfunc = ETH_RSS_HASH_TOP;
656 if (!indir)
657 return 0;
658
Helin Zhang90b02b42015-10-26 19:44:33 -0400659 seed = key;
660
661 lut = kzalloc(I40EVF_HLUT_ARRAY_SIZE, GFP_KERNEL);
662 if (!lut)
663 return -ENOMEM;
664
665 ret = i40evf_get_rss(vsi, seed, lut, I40EVF_HLUT_ARRAY_SIZE);
666 if (ret)
667 goto out;
668
669 /* Each 32 bits pointed by 'indir' is stored with a lut entry */
670 for (i = 0; i < I40EVF_HLUT_ARRAY_SIZE; i++)
671 indir[i] = (u32)lut[i];
672
673out:
674 kfree(lut);
675
676 return ret;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000677}
678
679/**
Ben Hutchingsfe62d002014-05-15 01:25:27 +0100680 * i40evf_set_rxfh - set the rx flow hash indirection table
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000681 * @netdev: network interface device structure
682 * @indir: indirection table
Mitch Williams2cda3f32014-11-11 20:02:31 +0000683 * @key: hash key
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000684 *
685 * Returns -EINVAL if the table specifies an inavlid queue id, otherwise
686 * returns 0 after programming the table.
687 **/
Ben Hutchingsfe62d002014-05-15 01:25:27 +0100688static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
Eyal Perry892311f2014-12-02 18:12:10 +0200689 const u8 *key, const u8 hfunc)
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000690{
691 struct i40evf_adapter *adapter = netdev_priv(netdev);
Helin Zhang2c86ac32015-10-27 16:15:06 -0400692 struct i40e_vsi *vsi = &adapter->vsi;
Helin Zhang66f9af852015-10-26 19:44:34 -0400693 u8 *seed = NULL;
Helin Zhang2c86ac32015-10-27 16:15:06 -0400694 u16 i;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000695
Eyal Perry892311f2014-12-02 18:12:10 +0200696 /* We do not allow change in unsupported parameters */
697 if (key ||
698 (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
699 return -EOPNOTSUPP;
700 if (!indir)
701 return 0;
702
Helin Zhang2c86ac32015-10-27 16:15:06 -0400703 if (key) {
Helin Zhang66f9af852015-10-26 19:44:34 -0400704 if (!vsi->rss_hkey_user) {
705 vsi->rss_hkey_user = kzalloc(I40EVF_HKEY_ARRAY_SIZE,
706 GFP_KERNEL);
707 if (!vsi->rss_hkey_user)
708 return -ENOMEM;
709 }
710 memcpy(vsi->rss_hkey_user, key, I40EVF_HKEY_ARRAY_SIZE);
711 seed = vsi->rss_hkey_user;
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000712 }
Helin Zhang66f9af852015-10-26 19:44:34 -0400713 if (!vsi->rss_lut_user) {
714 vsi->rss_lut_user = kzalloc(I40EVF_HLUT_ARRAY_SIZE,
715 GFP_KERNEL);
716 if (!vsi->rss_lut_user)
717 return -ENOMEM;
718 }
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000719
Helin Zhang2c86ac32015-10-27 16:15:06 -0400720 /* Each 32 bits pointed by 'indir' is stored with a lut entry */
721 for (i = 0; i < I40EVF_HLUT_ARRAY_SIZE; i++)
Helin Zhang66f9af852015-10-26 19:44:34 -0400722 vsi->rss_lut_user[i] = (u8)(indir[i]);
Helin Zhang2c86ac32015-10-27 16:15:06 -0400723
Helin Zhang66f9af852015-10-26 19:44:34 -0400724 return i40evf_config_rss(vsi, seed, vsi->rss_lut_user,
725 I40EVF_HLUT_ARRAY_SIZE);
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000726}
727
Mitch Williams00e5ec42016-01-15 14:33:10 -0800728/**
729 * i40evf_get_priv_flags - report device private flags
730 * @dev: network interface device structure
731 *
732 * The get string set count and the string set should be matched for each
733 * flag returned. Add new strings for each flag to the i40e_priv_flags_strings
734 * array.
735 *
736 * Returns a u32 bitmap of flags.
737 **/
738static u32 i40evf_get_priv_flags(struct net_device *dev)
739{
740 struct i40evf_adapter *adapter = netdev_priv(dev);
741 u32 ret_flags = 0;
742
743 ret_flags |= adapter->flags & I40EVF_FLAG_RX_PS_ENABLED ?
744 I40EVF_PRIV_FLAGS_PS : 0;
745
746 return ret_flags;
747}
748
749/**
750 * i40evf_set_priv_flags - set private flags
751 * @dev: network interface device structure
752 * @flags: bit flags to be set
753 **/
754static int i40evf_set_priv_flags(struct net_device *dev, u32 flags)
755{
756 struct i40evf_adapter *adapter = netdev_priv(dev);
757 bool reset_required = false;
758
759 if ((flags & I40EVF_PRIV_FLAGS_PS) &&
760 !(adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
761 adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
762 reset_required = true;
763 } else if (!(flags & I40EVF_PRIV_FLAGS_PS) &&
764 (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
765 adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
766 reset_required = true;
767 }
768
769 /* if needed, issue reset to cause things to take effect */
770 if (reset_required)
771 i40evf_schedule_reset(adapter);
772
773 return 0;
774}
775
Mitch Williamsf0c53c72014-04-04 04:43:11 +0000776static const struct ethtool_ops i40evf_ethtool_ops = {
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000777 .get_settings = i40evf_get_settings,
778 .get_drvinfo = i40evf_get_drvinfo,
779 .get_link = ethtool_op_get_link,
780 .get_ringparam = i40evf_get_ringparam,
781 .set_ringparam = i40evf_set_ringparam,
782 .get_strings = i40evf_get_strings,
783 .get_ethtool_stats = i40evf_get_ethtool_stats,
784 .get_sset_count = i40evf_get_sset_count,
Mitch Williams00e5ec42016-01-15 14:33:10 -0800785 .get_priv_flags = i40evf_get_priv_flags,
786 .set_priv_flags = i40evf_set_priv_flags,
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000787 .get_msglevel = i40evf_get_msglevel,
788 .set_msglevel = i40evf_set_msglevel,
789 .get_coalesce = i40evf_get_coalesce,
790 .set_coalesce = i40evf_set_coalesce,
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000791 .get_rxnfc = i40evf_get_rxnfc,
792 .set_rxnfc = i40evf_set_rxnfc,
793 .get_rxfh_indir_size = i40evf_get_rxfh_indir_size,
Ben Hutchingsfe62d002014-05-15 01:25:27 +0100794 .get_rxfh = i40evf_get_rxfh,
795 .set_rxfh = i40evf_set_rxfh,
Mitch A Williams4e9dc312014-04-01 04:43:49 +0000796 .get_channels = i40evf_get_channels,
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000797};
798
799/**
800 * i40evf_set_ethtool_ops - Initialize ethtool ops struct
801 * @netdev: network interface device structure
802 *
803 * Sets ethtool ops struct in our netdev so that ethtool can call
804 * our functions.
805 **/
806void i40evf_set_ethtool_ops(struct net_device *netdev)
807{
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +0000808 netdev->ethtool_ops = &i40evf_ethtool_ops;
Greg Rosefbb7ddf2013-12-21 06:12:56 +0000809}