Commit | Line | Data |
---|---|---|
e6550b3e TG |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright 2013 Cisco Systems, Inc. All rights reserved. | |
f13bbc2f NP |
3 | |
4 | #include <linux/netdevice.h> | |
5 | #include <linux/ethtool.h> | |
fb7516d4 | 6 | #include <linux/net_tstamp.h> |
f13bbc2f NP |
7 | |
8 | #include "enic_res.h" | |
9 | #include "enic.h" | |
10 | #include "enic_dev.h" | |
3762ff8f | 11 | #include "enic_clsf.h" |
4f675eb2 | 12 | #include "vnic_rss.h" |
58feff07 | 13 | #include "vnic_stats.h" |
f13bbc2f NP |
14 | |
15 | struct enic_stat { | |
16 | char name[ETH_GSTRING_LEN]; | |
17 | unsigned int index; | |
18 | }; | |
19 | ||
20 | #define ENIC_TX_STAT(stat) { \ | |
21 | .name = #stat, \ | |
22 | .index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \ | |
23 | } | |
24 | ||
25 | #define ENIC_RX_STAT(stat) { \ | |
26 | .name = #stat, \ | |
27 | .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \ | |
28 | } | |
29 | ||
58feff07 GV |
30 | #define ENIC_GEN_STAT(stat) { \ |
31 | .name = #stat, \ | |
32 | .index = offsetof(struct vnic_gen_stats, stat) / sizeof(u64)\ | |
33 | } | |
34 | ||
bde04d98 NE |
35 | #define ENIC_PER_RQ_STAT(stat) { \ |
36 | .name = "rq[%d]_"#stat, \ | |
37 | .index = offsetof(struct enic_rq_stats, stat) / sizeof(u64) \ | |
38 | } | |
39 | ||
40 | #define ENIC_PER_WQ_STAT(stat) { \ | |
41 | .name = "wq[%d]_"#stat, \ | |
42 | .index = offsetof(struct enic_wq_stats, stat) / sizeof(u64) \ | |
43 | } | |
44 | ||
45 | static const struct enic_stat enic_per_rq_stats[] = { | |
46 | ENIC_PER_RQ_STAT(l4_rss_hash), | |
47 | ENIC_PER_RQ_STAT(l3_rss_hash), | |
48 | ENIC_PER_RQ_STAT(csum_unnecessary_encap), | |
49 | ENIC_PER_RQ_STAT(vlan_stripped), | |
50 | ENIC_PER_RQ_STAT(napi_complete), | |
51 | ENIC_PER_RQ_STAT(napi_repoll), | |
52 | ENIC_PER_RQ_STAT(no_skb), | |
53 | ENIC_PER_RQ_STAT(desc_skip), | |
54 | }; | |
55 | ||
56 | #define NUM_ENIC_PER_RQ_STATS ARRAY_SIZE(enic_per_rq_stats) | |
57 | ||
58 | static const struct enic_stat enic_per_wq_stats[] = { | |
59 | ENIC_PER_WQ_STAT(encap_tso), | |
60 | ENIC_PER_WQ_STAT(encap_csum), | |
61 | ENIC_PER_WQ_STAT(add_vlan), | |
62 | ENIC_PER_WQ_STAT(cq_work), | |
63 | ENIC_PER_WQ_STAT(cq_bytes), | |
64 | ENIC_PER_WQ_STAT(null_pkt), | |
65 | ENIC_PER_WQ_STAT(skb_linear_fail), | |
66 | ENIC_PER_WQ_STAT(desc_full_awake), | |
67 | }; | |
68 | ||
69 | #define NUM_ENIC_PER_WQ_STATS ARRAY_SIZE(enic_per_wq_stats) | |
f13bbc2f NP |
70 | static const struct enic_stat enic_tx_stats[] = { |
71 | ENIC_TX_STAT(tx_frames_ok), | |
72 | ENIC_TX_STAT(tx_unicast_frames_ok), | |
73 | ENIC_TX_STAT(tx_multicast_frames_ok), | |
74 | ENIC_TX_STAT(tx_broadcast_frames_ok), | |
75 | ENIC_TX_STAT(tx_bytes_ok), | |
76 | ENIC_TX_STAT(tx_unicast_bytes_ok), | |
77 | ENIC_TX_STAT(tx_multicast_bytes_ok), | |
78 | ENIC_TX_STAT(tx_broadcast_bytes_ok), | |
79 | ENIC_TX_STAT(tx_drops), | |
80 | ENIC_TX_STAT(tx_errors), | |
81 | ENIC_TX_STAT(tx_tso), | |
82 | }; | |
83 | ||
a59571ad NE |
84 | #define NUM_ENIC_TX_STATS ARRAY_SIZE(enic_tx_stats) |
85 | ||
f13bbc2f NP |
86 | static const struct enic_stat enic_rx_stats[] = { |
87 | ENIC_RX_STAT(rx_frames_ok), | |
88 | ENIC_RX_STAT(rx_frames_total), | |
89 | ENIC_RX_STAT(rx_unicast_frames_ok), | |
90 | ENIC_RX_STAT(rx_multicast_frames_ok), | |
91 | ENIC_RX_STAT(rx_broadcast_frames_ok), | |
92 | ENIC_RX_STAT(rx_bytes_ok), | |
93 | ENIC_RX_STAT(rx_unicast_bytes_ok), | |
94 | ENIC_RX_STAT(rx_multicast_bytes_ok), | |
95 | ENIC_RX_STAT(rx_broadcast_bytes_ok), | |
96 | ENIC_RX_STAT(rx_drop), | |
97 | ENIC_RX_STAT(rx_no_bufs), | |
98 | ENIC_RX_STAT(rx_errors), | |
99 | ENIC_RX_STAT(rx_rss), | |
100 | ENIC_RX_STAT(rx_crc_errors), | |
101 | ENIC_RX_STAT(rx_frames_64), | |
102 | ENIC_RX_STAT(rx_frames_127), | |
103 | ENIC_RX_STAT(rx_frames_255), | |
104 | ENIC_RX_STAT(rx_frames_511), | |
105 | ENIC_RX_STAT(rx_frames_1023), | |
106 | ENIC_RX_STAT(rx_frames_1518), | |
107 | ENIC_RX_STAT(rx_frames_to_max), | |
108 | }; | |
109 | ||
a59571ad NE |
110 | #define NUM_ENIC_RX_STATS ARRAY_SIZE(enic_rx_stats) |
111 | ||
58feff07 GV |
112 | static const struct enic_stat enic_gen_stats[] = { |
113 | ENIC_GEN_STAT(dma_map_error), | |
114 | }; | |
115 | ||
a59571ad | 116 | #define NUM_ENIC_GEN_STATS ARRAY_SIZE(enic_gen_stats) |
f13bbc2f | 117 | |
a20667bf | 118 | static void enic_intr_coal_set_rx(struct enic *enic, u32 timer) |
7c2ce6e6 SS |
119 | { |
120 | int i; | |
121 | int intr; | |
122 | ||
123 | for (i = 0; i < enic->rq_count; i++) { | |
124 | intr = enic_msix_rq_intr(enic, i); | |
125 | vnic_intr_coalescing_timer_set(&enic->intr[intr], timer); | |
126 | } | |
127 | } | |
128 | ||
7659f50c PR |
129 | static int enic_get_ksettings(struct net_device *netdev, |
130 | struct ethtool_link_ksettings *ecmd) | |
f13bbc2f NP |
131 | { |
132 | struct enic *enic = netdev_priv(netdev); | |
7659f50c | 133 | struct ethtool_link_settings *base = &ecmd->base; |
f13bbc2f | 134 | |
7659f50c PR |
135 | ethtool_link_ksettings_add_link_mode(ecmd, supported, |
136 | 10000baseT_Full); | |
137 | ethtool_link_ksettings_add_link_mode(ecmd, supported, FIBRE); | |
138 | ethtool_link_ksettings_add_link_mode(ecmd, advertising, | |
139 | 10000baseT_Full); | |
140 | ethtool_link_ksettings_add_link_mode(ecmd, advertising, FIBRE); | |
141 | base->port = PORT_FIBRE; | |
f13bbc2f NP |
142 | |
143 | if (netif_carrier_ok(netdev)) { | |
7659f50c PR |
144 | base->speed = vnic_dev_port_speed(enic->vdev); |
145 | base->duplex = DUPLEX_FULL; | |
f13bbc2f | 146 | } else { |
7659f50c PR |
147 | base->speed = SPEED_UNKNOWN; |
148 | base->duplex = DUPLEX_UNKNOWN; | |
f13bbc2f NP |
149 | } |
150 | ||
7659f50c | 151 | base->autoneg = AUTONEG_DISABLE; |
f13bbc2f NP |
152 | |
153 | return 0; | |
154 | } | |
155 | ||
156 | static void enic_get_drvinfo(struct net_device *netdev, | |
157 | struct ethtool_drvinfo *drvinfo) | |
158 | { | |
159 | struct enic *enic = netdev_priv(netdev); | |
160 | struct vnic_devcmd_fw_info *fw_info; | |
19b596bd | 161 | int err; |
f13bbc2f | 162 | |
19b596bd | 163 | err = enic_dev_fw_info(enic, &fw_info); |
f947fcaf | 164 | /* return only when dma_alloc_coherent fails in vnic_dev_fw_info |
19b596bd GV |
165 | * For other failures, like devcmd failure, we return previously |
166 | * recorded info. | |
167 | */ | |
168 | if (err == -ENOMEM) | |
169 | return; | |
f13bbc2f | 170 | |
f029c781 WS |
171 | strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); |
172 | strscpy(drvinfo->fw_version, fw_info->fw_version, | |
f13bbc2f | 173 | sizeof(drvinfo->fw_version)); |
f029c781 | 174 | strscpy(drvinfo->bus_info, pci_name(enic->pdev), |
f13bbc2f NP |
175 | sizeof(drvinfo->bus_info)); |
176 | } | |
177 | ||
178 | static void enic_get_strings(struct net_device *netdev, u32 stringset, | |
179 | u8 *data) | |
180 | { | |
bde04d98 | 181 | struct enic *enic = netdev_priv(netdev); |
f13bbc2f | 182 | unsigned int i; |
bde04d98 | 183 | unsigned int j; |
f13bbc2f NP |
184 | |
185 | switch (stringset) { | |
186 | case ETH_SS_STATS: | |
a59571ad | 187 | for (i = 0; i < NUM_ENIC_TX_STATS; i++) { |
f13bbc2f NP |
188 | memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN); |
189 | data += ETH_GSTRING_LEN; | |
190 | } | |
a59571ad | 191 | for (i = 0; i < NUM_ENIC_RX_STATS; i++) { |
f13bbc2f NP |
192 | memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); |
193 | data += ETH_GSTRING_LEN; | |
194 | } | |
a59571ad | 195 | for (i = 0; i < NUM_ENIC_GEN_STATS; i++) { |
58feff07 GV |
196 | memcpy(data, enic_gen_stats[i].name, ETH_GSTRING_LEN); |
197 | data += ETH_GSTRING_LEN; | |
198 | } | |
bde04d98 NE |
199 | for (i = 0; i < enic->rq_count; i++) { |
200 | for (j = 0; j < NUM_ENIC_PER_RQ_STATS; j++) { | |
201 | snprintf(data, ETH_GSTRING_LEN, | |
202 | enic_per_rq_stats[j].name, i); | |
203 | data += ETH_GSTRING_LEN; | |
204 | } | |
205 | } | |
206 | for (i = 0; i < enic->wq_count; i++) { | |
207 | for (j = 0; j < NUM_ENIC_PER_WQ_STATS; j++) { | |
208 | snprintf(data, ETH_GSTRING_LEN, | |
209 | enic_per_wq_stats[j].name, i); | |
210 | data += ETH_GSTRING_LEN; | |
211 | } | |
212 | } | |
f13bbc2f NP |
213 | break; |
214 | } | |
215 | } | |
216 | ||
ed519b74 | 217 | static void enic_get_ringparam(struct net_device *netdev, |
74624944 HC |
218 | struct ethtool_ringparam *ring, |
219 | struct kernel_ethtool_ringparam *kernel_ring, | |
220 | struct netlink_ext_ack *extack) | |
ed519b74 PK |
221 | { |
222 | struct enic *enic = netdev_priv(netdev); | |
223 | struct vnic_enet_config *c = &enic->config; | |
224 | ||
225 | ring->rx_max_pending = ENIC_MAX_RQ_DESCS; | |
226 | ring->rx_pending = c->rq_desc_count; | |
227 | ring->tx_max_pending = ENIC_MAX_WQ_DESCS; | |
228 | ring->tx_pending = c->wq_desc_count; | |
229 | } | |
230 | ||
231 | static int enic_set_ringparam(struct net_device *netdev, | |
74624944 HC |
232 | struct ethtool_ringparam *ring, |
233 | struct kernel_ethtool_ringparam *kernel_ring, | |
234 | struct netlink_ext_ack *extack) | |
ed519b74 PK |
235 | { |
236 | struct enic *enic = netdev_priv(netdev); | |
237 | struct vnic_enet_config *c = &enic->config; | |
238 | int running = netif_running(netdev); | |
239 | unsigned int rx_pending; | |
240 | unsigned int tx_pending; | |
241 | int err = 0; | |
242 | ||
243 | if (ring->rx_mini_max_pending || ring->rx_mini_pending) { | |
244 | netdev_info(netdev, | |
245 | "modifying mini ring params is not supported"); | |
246 | return -EINVAL; | |
247 | } | |
248 | if (ring->rx_jumbo_max_pending || ring->rx_jumbo_pending) { | |
249 | netdev_info(netdev, | |
250 | "modifying jumbo ring params is not supported"); | |
251 | return -EINVAL; | |
252 | } | |
253 | rx_pending = c->rq_desc_count; | |
254 | tx_pending = c->wq_desc_count; | |
255 | if (ring->rx_pending > ENIC_MAX_RQ_DESCS || | |
256 | ring->rx_pending < ENIC_MIN_RQ_DESCS) { | |
257 | netdev_info(netdev, "rx pending (%u) not in range [%u,%u]", | |
258 | ring->rx_pending, ENIC_MIN_RQ_DESCS, | |
259 | ENIC_MAX_RQ_DESCS); | |
260 | return -EINVAL; | |
261 | } | |
262 | if (ring->tx_pending > ENIC_MAX_WQ_DESCS || | |
263 | ring->tx_pending < ENIC_MIN_WQ_DESCS) { | |
264 | netdev_info(netdev, "tx pending (%u) not in range [%u,%u]", | |
265 | ring->tx_pending, ENIC_MIN_WQ_DESCS, | |
266 | ENIC_MAX_WQ_DESCS); | |
267 | return -EINVAL; | |
268 | } | |
269 | if (running) | |
270 | dev_close(netdev); | |
271 | c->rq_desc_count = | |
272 | ring->rx_pending & 0xffffffe0; /* must be aligned to groups of 32 */ | |
273 | c->wq_desc_count = | |
274 | ring->tx_pending & 0xffffffe0; /* must be aligned to groups of 32 */ | |
275 | enic_free_vnic_resources(enic); | |
276 | err = enic_alloc_vnic_resources(enic); | |
277 | if (err) { | |
278 | netdev_err(netdev, | |
279 | "Failed to alloc vNIC resources, aborting\n"); | |
280 | enic_free_vnic_resources(enic); | |
281 | goto err_out; | |
282 | } | |
283 | enic_init_vnic_resources(enic); | |
284 | if (running) { | |
00f54e68 | 285 | err = dev_open(netdev, NULL); |
ed519b74 PK |
286 | if (err) |
287 | goto err_out; | |
288 | } | |
289 | return 0; | |
290 | err_out: | |
291 | c->rq_desc_count = rx_pending; | |
292 | c->wq_desc_count = tx_pending; | |
293 | return err; | |
294 | } | |
295 | ||
f13bbc2f NP |
296 | static int enic_get_sset_count(struct net_device *netdev, int sset) |
297 | { | |
bde04d98 NE |
298 | struct enic *enic = netdev_priv(netdev); |
299 | unsigned int n_per_rq_stats; | |
300 | unsigned int n_per_wq_stats; | |
301 | unsigned int n_stats; | |
302 | ||
f13bbc2f NP |
303 | switch (sset) { |
304 | case ETH_SS_STATS: | |
bde04d98 NE |
305 | n_per_rq_stats = NUM_ENIC_PER_RQ_STATS * enic->rq_count; |
306 | n_per_wq_stats = NUM_ENIC_PER_WQ_STATS * enic->wq_count; | |
307 | n_stats = NUM_ENIC_TX_STATS + NUM_ENIC_RX_STATS + | |
308 | NUM_ENIC_GEN_STATS + | |
309 | n_per_rq_stats + n_per_wq_stats; | |
310 | return n_stats; | |
f13bbc2f NP |
311 | default: |
312 | return -EOPNOTSUPP; | |
313 | } | |
314 | } | |
315 | ||
316 | static void enic_get_ethtool_stats(struct net_device *netdev, | |
317 | struct ethtool_stats *stats, u64 *data) | |
318 | { | |
319 | struct enic *enic = netdev_priv(netdev); | |
320 | struct vnic_stats *vstats; | |
321 | unsigned int i; | |
bde04d98 | 322 | unsigned int j; |
19b596bd GV |
323 | int err; |
324 | ||
325 | err = enic_dev_stats_dump(enic, &vstats); | |
f947fcaf | 326 | /* return only when dma_alloc_coherent fails in vnic_dev_stats_dump |
19b596bd GV |
327 | * For other failures, like devcmd failure, we return previously |
328 | * recorded stats. | |
329 | */ | |
330 | if (err == -ENOMEM) | |
331 | return; | |
f13bbc2f | 332 | |
a59571ad | 333 | for (i = 0; i < NUM_ENIC_TX_STATS; i++) |
f13bbc2f | 334 | *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index]; |
a59571ad | 335 | for (i = 0; i < NUM_ENIC_RX_STATS; i++) |
f13bbc2f | 336 | *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index]; |
a59571ad | 337 | for (i = 0; i < NUM_ENIC_GEN_STATS; i++) |
58feff07 | 338 | *(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index]; |
bde04d98 NE |
339 | for (i = 0; i < enic->rq_count; i++) { |
340 | struct enic_rq_stats *rqstats = &enic->rq_stats[i]; | |
341 | int index; | |
342 | ||
343 | for (j = 0; j < NUM_ENIC_PER_RQ_STATS; j++) { | |
344 | index = enic_per_rq_stats[j].index; | |
345 | *(data++) = ((u64 *)rqstats)[index]; | |
346 | } | |
347 | } | |
348 | for (i = 0; i < enic->wq_count; i++) { | |
349 | struct enic_wq_stats *wqstats = &enic->wq_stats[i]; | |
350 | int index; | |
351 | ||
352 | for (j = 0; j < NUM_ENIC_PER_WQ_STATS; j++) { | |
353 | index = enic_per_wq_stats[j].index; | |
354 | *(data++) = ((u64 *)wqstats)[index]; | |
355 | } | |
356 | } | |
f13bbc2f NP |
357 | } |
358 | ||
359 | static u32 enic_get_msglevel(struct net_device *netdev) | |
360 | { | |
361 | struct enic *enic = netdev_priv(netdev); | |
362 | return enic->msg_enable; | |
363 | } | |
364 | ||
365 | static void enic_set_msglevel(struct net_device *netdev, u32 value) | |
366 | { | |
367 | struct enic *enic = netdev_priv(netdev); | |
368 | enic->msg_enable = value; | |
369 | } | |
370 | ||
371 | static int enic_get_coalesce(struct net_device *netdev, | |
f3ccfda1 YM |
372 | struct ethtool_coalesce *ecmd, |
373 | struct kernel_ethtool_coalesce *kernel_coal, | |
374 | struct netlink_ext_ack *extack) | |
f13bbc2f NP |
375 | { |
376 | struct enic *enic = netdev_priv(netdev); | |
7c2ce6e6 | 377 | struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; |
f13bbc2f | 378 | |
d9382bda GV |
379 | if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) |
380 | ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; | |
f13bbc2f | 381 | ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; |
7c2ce6e6 SS |
382 | if (rxcoal->use_adaptive_rx_coalesce) |
383 | ecmd->use_adaptive_rx_coalesce = 1; | |
384 | ecmd->rx_coalesce_usecs_low = rxcoal->small_pkt_range_start; | |
385 | ecmd->rx_coalesce_usecs_high = rxcoal->range_end; | |
f13bbc2f NP |
386 | |
387 | return 0; | |
388 | } | |
389 | ||
d9382bda GV |
390 | static int enic_coalesce_valid(struct enic *enic, |
391 | struct ethtool_coalesce *ec) | |
392 | { | |
393 | u32 coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); | |
394 | u32 rx_coalesce_usecs_high = min_t(u32, coalesce_usecs_max, | |
395 | ec->rx_coalesce_usecs_high); | |
396 | u32 rx_coalesce_usecs_low = min_t(u32, coalesce_usecs_max, | |
397 | ec->rx_coalesce_usecs_low); | |
398 | ||
d9382bda GV |
399 | if ((vnic_dev_get_intr_mode(enic->vdev) != VNIC_DEV_INTR_MODE_MSIX) && |
400 | ec->tx_coalesce_usecs) | |
401 | return -EINVAL; | |
402 | ||
403 | if ((ec->tx_coalesce_usecs > coalesce_usecs_max) || | |
404 | (ec->rx_coalesce_usecs > coalesce_usecs_max) || | |
405 | (ec->rx_coalesce_usecs_low > coalesce_usecs_max) || | |
406 | (ec->rx_coalesce_usecs_high > coalesce_usecs_max)) | |
407 | netdev_info(enic->netdev, "ethtool_set_coalesce: adaptor supports max coalesce value of %d. Setting max value.\n", | |
408 | coalesce_usecs_max); | |
409 | ||
410 | if (ec->rx_coalesce_usecs_high && | |
411 | (rx_coalesce_usecs_high < | |
412 | rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) | |
413 | return -EINVAL; | |
414 | ||
415 | return 0; | |
416 | } | |
417 | ||
f13bbc2f | 418 | static int enic_set_coalesce(struct net_device *netdev, |
f3ccfda1 YM |
419 | struct ethtool_coalesce *ecmd, |
420 | struct kernel_ethtool_coalesce *kernel_coal, | |
421 | struct netlink_ext_ack *extack) | |
f13bbc2f NP |
422 | { |
423 | struct enic *enic = netdev_priv(netdev); | |
424 | u32 tx_coalesce_usecs; | |
425 | u32 rx_coalesce_usecs; | |
7c2ce6e6 SS |
426 | u32 rx_coalesce_usecs_low; |
427 | u32 rx_coalesce_usecs_high; | |
428 | u32 coalesce_usecs_max; | |
f13bbc2f | 429 | unsigned int i, intr; |
d9382bda | 430 | int ret; |
7c2ce6e6 | 431 | struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; |
f13bbc2f | 432 | |
d9382bda GV |
433 | ret = enic_coalesce_valid(enic, ecmd); |
434 | if (ret) | |
435 | return ret; | |
7c2ce6e6 | 436 | coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); |
f13bbc2f | 437 | tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, |
7c2ce6e6 | 438 | coalesce_usecs_max); |
f13bbc2f | 439 | rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs, |
7c2ce6e6 SS |
440 | coalesce_usecs_max); |
441 | ||
442 | rx_coalesce_usecs_low = min_t(u32, ecmd->rx_coalesce_usecs_low, | |
443 | coalesce_usecs_max); | |
444 | rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high, | |
445 | coalesce_usecs_max); | |
f13bbc2f | 446 | |
d9382bda | 447 | if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) { |
f13bbc2f NP |
448 | for (i = 0; i < enic->wq_count; i++) { |
449 | intr = enic_msix_wq_intr(enic, i); | |
450 | vnic_intr_coalescing_timer_set(&enic->intr[intr], | |
d9382bda | 451 | tx_coalesce_usecs); |
f13bbc2f | 452 | } |
d9382bda GV |
453 | enic->tx_coalesce_usecs = tx_coalesce_usecs; |
454 | } | |
455 | rxcoal->use_adaptive_rx_coalesce = !!ecmd->use_adaptive_rx_coalesce; | |
456 | if (!rxcoal->use_adaptive_rx_coalesce) | |
457 | enic_intr_coal_set_rx(enic, rx_coalesce_usecs); | |
458 | if (ecmd->rx_coalesce_usecs_high) { | |
459 | rxcoal->range_end = rx_coalesce_usecs_high; | |
460 | rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; | |
461 | rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + | |
462 | ENIC_AIC_LARGE_PKT_DIFF; | |
f13bbc2f NP |
463 | } |
464 | ||
f13bbc2f NP |
465 | enic->rx_coalesce_usecs = rx_coalesce_usecs; |
466 | ||
467 | return 0; | |
468 | } | |
469 | ||
3762ff8f GV |
470 | static int enic_grxclsrlall(struct enic *enic, struct ethtool_rxnfc *cmd, |
471 | u32 *rule_locs) | |
472 | { | |
473 | int j, ret = 0, cnt = 0; | |
474 | ||
475 | cmd->data = enic->rfs_h.max - enic->rfs_h.free; | |
476 | for (j = 0; j < (1 << ENIC_RFS_FLW_BITSHIFT); j++) { | |
477 | struct hlist_head *hhead; | |
478 | struct hlist_node *tmp; | |
479 | struct enic_rfs_fltr_node *n; | |
480 | ||
481 | hhead = &enic->rfs_h.ht_head[j]; | |
482 | hlist_for_each_entry_safe(n, tmp, hhead, node) { | |
483 | if (cnt == cmd->rule_cnt) | |
484 | return -EMSGSIZE; | |
485 | rule_locs[cnt] = n->fltr_id; | |
486 | cnt++; | |
487 | } | |
488 | } | |
489 | cmd->rule_cnt = cnt; | |
490 | ||
491 | return ret; | |
492 | } | |
493 | ||
494 | static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd) | |
495 | { | |
496 | struct ethtool_rx_flow_spec *fsp = | |
497 | (struct ethtool_rx_flow_spec *)&cmd->fs; | |
498 | struct enic_rfs_fltr_node *n; | |
499 | ||
500 | n = htbl_fltr_search(enic, (u16)fsp->location); | |
501 | if (!n) | |
502 | return -EINVAL; | |
06635a35 | 503 | switch (n->keys.basic.ip_proto) { |
3762ff8f GV |
504 | case IPPROTO_TCP: |
505 | fsp->flow_type = TCP_V4_FLOW; | |
506 | break; | |
507 | case IPPROTO_UDP: | |
508 | fsp->flow_type = UDP_V4_FLOW; | |
509 | break; | |
510 | default: | |
511 | return -EINVAL; | |
3762ff8f GV |
512 | } |
513 | ||
c3f83241 | 514 | fsp->h_u.tcp_ip4_spec.ip4src = flow_get_u32_src(&n->keys); |
3762ff8f GV |
515 | fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0; |
516 | ||
c3f83241 | 517 | fsp->h_u.tcp_ip4_spec.ip4dst = flow_get_u32_dst(&n->keys); |
3762ff8f GV |
518 | fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0; |
519 | ||
59346afe | 520 | fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.src; |
3762ff8f GV |
521 | fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0; |
522 | ||
59346afe | 523 | fsp->h_u.tcp_ip4_spec.pdst = n->keys.ports.dst; |
3762ff8f GV |
524 | fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0; |
525 | ||
526 | fsp->ring_cookie = n->rq_id; | |
527 | ||
528 | return 0; | |
529 | } | |
530 | ||
48398b6e GV |
531 | static int enic_get_rx_flow_hash(struct enic *enic, struct ethtool_rxnfc *cmd) |
532 | { | |
4016a7f1 | 533 | u8 rss_hash_type = 0; |
48398b6e GV |
534 | cmd->data = 0; |
535 | ||
4016a7f1 GV |
536 | spin_lock_bh(&enic->devcmd_lock); |
537 | (void)vnic_dev_capable_rss_hash_type(enic->vdev, &rss_hash_type); | |
538 | spin_unlock_bh(&enic->devcmd_lock); | |
48398b6e GV |
539 | switch (cmd->flow_type) { |
540 | case TCP_V6_FLOW: | |
541 | case TCP_V4_FLOW: | |
4016a7f1 GV |
542 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3 | |
543 | RXH_IP_SRC | RXH_IP_DST; | |
544 | break; | |
48398b6e | 545 | case UDP_V6_FLOW: |
4016a7f1 GV |
546 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; |
547 | if (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP_IPV6) | |
548 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | |
549 | break; | |
48398b6e | 550 | case UDP_V4_FLOW: |
4016a7f1 GV |
551 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; |
552 | if (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP_IPV4) | |
48398b6e | 553 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
4016a7f1 | 554 | break; |
48398b6e GV |
555 | case SCTP_V4_FLOW: |
556 | case AH_ESP_V4_FLOW: | |
557 | case AH_V4_FLOW: | |
558 | case ESP_V4_FLOW: | |
559 | case SCTP_V6_FLOW: | |
560 | case AH_ESP_V6_FLOW: | |
561 | case AH_V6_FLOW: | |
562 | case ESP_V6_FLOW: | |
563 | case IPV4_FLOW: | |
564 | case IPV6_FLOW: | |
565 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; | |
566 | break; | |
567 | default: | |
568 | return -EINVAL; | |
569 | } | |
570 | ||
571 | return 0; | |
572 | } | |
573 | ||
3762ff8f GV |
574 | static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, |
575 | u32 *rule_locs) | |
576 | { | |
577 | struct enic *enic = netdev_priv(dev); | |
578 | int ret = 0; | |
579 | ||
580 | switch (cmd->cmd) { | |
581 | case ETHTOOL_GRXRINGS: | |
582 | cmd->data = enic->rq_count; | |
583 | break; | |
584 | case ETHTOOL_GRXCLSRLCNT: | |
585 | spin_lock_bh(&enic->rfs_h.lock); | |
586 | cmd->rule_cnt = enic->rfs_h.max - enic->rfs_h.free; | |
587 | cmd->data = enic->rfs_h.max; | |
588 | spin_unlock_bh(&enic->rfs_h.lock); | |
589 | break; | |
590 | case ETHTOOL_GRXCLSRLALL: | |
591 | spin_lock_bh(&enic->rfs_h.lock); | |
592 | ret = enic_grxclsrlall(enic, cmd, rule_locs); | |
593 | spin_unlock_bh(&enic->rfs_h.lock); | |
594 | break; | |
595 | case ETHTOOL_GRXCLSRULE: | |
596 | spin_lock_bh(&enic->rfs_h.lock); | |
597 | ret = enic_grxclsrule(enic, cmd); | |
598 | spin_unlock_bh(&enic->rfs_h.lock); | |
599 | break; | |
48398b6e GV |
600 | case ETHTOOL_GRXFH: |
601 | ret = enic_get_rx_flow_hash(enic, cmd); | |
602 | break; | |
3762ff8f GV |
603 | default: |
604 | ret = -EOPNOTSUPP; | |
605 | break; | |
606 | } | |
607 | ||
608 | return ret; | |
609 | } | |
610 | ||
d4ad30b1 GV |
611 | static int enic_get_tunable(struct net_device *dev, |
612 | const struct ethtool_tunable *tuna, void *data) | |
613 | { | |
614 | struct enic *enic = netdev_priv(dev); | |
615 | int ret = 0; | |
616 | ||
617 | switch (tuna->id) { | |
618 | case ETHTOOL_RX_COPYBREAK: | |
619 | *(u32 *)data = enic->rx_copybreak; | |
620 | break; | |
621 | default: | |
622 | ret = -EINVAL; | |
623 | break; | |
624 | } | |
625 | ||
626 | return ret; | |
627 | } | |
628 | ||
629 | static int enic_set_tunable(struct net_device *dev, | |
630 | const struct ethtool_tunable *tuna, | |
631 | const void *data) | |
632 | { | |
633 | struct enic *enic = netdev_priv(dev); | |
634 | int ret = 0; | |
635 | ||
636 | switch (tuna->id) { | |
637 | case ETHTOOL_RX_COPYBREAK: | |
638 | enic->rx_copybreak = *(u32 *)data; | |
639 | break; | |
640 | default: | |
641 | ret = -EINVAL; | |
642 | break; | |
643 | } | |
644 | ||
645 | return ret; | |
646 | } | |
647 | ||
4f675eb2 GV |
648 | static u32 enic_get_rxfh_key_size(struct net_device *netdev) |
649 | { | |
650 | return ENIC_RSS_LEN; | |
651 | } | |
652 | ||
fb6e30a7 AZ |
653 | static int enic_get_rxfh(struct net_device *netdev, |
654 | struct ethtool_rxfh_param *rxfh) | |
4f675eb2 GV |
655 | { |
656 | struct enic *enic = netdev_priv(netdev); | |
657 | ||
fb6e30a7 AZ |
658 | if (rxfh->key) |
659 | memcpy(rxfh->key, enic->rss_key, ENIC_RSS_LEN); | |
4f675eb2 | 660 | |
fb6e30a7 | 661 | rxfh->hfunc = ETH_RSS_HASH_TOP; |
4f675eb2 GV |
662 | |
663 | return 0; | |
664 | } | |
665 | ||
fb6e30a7 AZ |
666 | static int enic_set_rxfh(struct net_device *netdev, |
667 | struct ethtool_rxfh_param *rxfh, | |
668 | struct netlink_ext_ack *extack) | |
4f675eb2 GV |
669 | { |
670 | struct enic *enic = netdev_priv(netdev); | |
671 | ||
fb6e30a7 AZ |
672 | if (rxfh->indir || |
673 | (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && | |
674 | rxfh->hfunc != ETH_RSS_HASH_TOP)) | |
4f675eb2 GV |
675 | return -EINVAL; |
676 | ||
fb6e30a7 AZ |
677 | if (rxfh->key) |
678 | memcpy(enic->rss_key, rxfh->key, ENIC_RSS_LEN); | |
4f675eb2 GV |
679 | |
680 | return __enic_set_rsskey(enic); | |
681 | } | |
682 | ||
fb7516d4 | 683 | static int enic_get_ts_info(struct net_device *netdev, |
2111375b | 684 | struct kernel_ethtool_ts_info *info) |
fb7516d4 | 685 | { |
e4e0145a | 686 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE; |
fb7516d4 GV |
687 | |
688 | return 0; | |
689 | } | |
690 | ||
bf7bb7b4 JK |
691 | static void enic_get_channels(struct net_device *netdev, |
692 | struct ethtool_channels *channels) | |
693 | { | |
694 | struct enic *enic = netdev_priv(netdev); | |
695 | ||
696 | switch (vnic_dev_get_intr_mode(enic->vdev)) { | |
697 | case VNIC_DEV_INTR_MODE_MSIX: | |
698 | channels->max_rx = ENIC_RQ_MAX; | |
699 | channels->max_tx = ENIC_WQ_MAX; | |
700 | channels->rx_count = enic->rq_count; | |
701 | channels->tx_count = enic->wq_count; | |
702 | break; | |
703 | case VNIC_DEV_INTR_MODE_MSI: | |
704 | case VNIC_DEV_INTR_MODE_INTX: | |
705 | channels->max_combined = 1; | |
706 | channels->combined_count = 1; | |
707 | break; | |
708 | default: | |
709 | break; | |
710 | } | |
711 | } | |
712 | ||
f13bbc2f | 713 | static const struct ethtool_ops enic_ethtool_ops = { |
c885bff6 JK |
714 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
715 | ETHTOOL_COALESCE_USE_ADAPTIVE_RX | | |
716 | ETHTOOL_COALESCE_RX_USECS_LOW | | |
717 | ETHTOOL_COALESCE_RX_USECS_HIGH, | |
f13bbc2f NP |
718 | .get_drvinfo = enic_get_drvinfo, |
719 | .get_msglevel = enic_get_msglevel, | |
720 | .set_msglevel = enic_set_msglevel, | |
721 | .get_link = ethtool_op_get_link, | |
722 | .get_strings = enic_get_strings, | |
ed519b74 PK |
723 | .get_ringparam = enic_get_ringparam, |
724 | .set_ringparam = enic_set_ringparam, | |
f13bbc2f NP |
725 | .get_sset_count = enic_get_sset_count, |
726 | .get_ethtool_stats = enic_get_ethtool_stats, | |
727 | .get_coalesce = enic_get_coalesce, | |
728 | .set_coalesce = enic_set_coalesce, | |
3762ff8f | 729 | .get_rxnfc = enic_get_rxnfc, |
d4ad30b1 GV |
730 | .get_tunable = enic_get_tunable, |
731 | .set_tunable = enic_set_tunable, | |
4f675eb2 GV |
732 | .get_rxfh_key_size = enic_get_rxfh_key_size, |
733 | .get_rxfh = enic_get_rxfh, | |
734 | .set_rxfh = enic_set_rxfh, | |
7659f50c | 735 | .get_link_ksettings = enic_get_ksettings, |
fb7516d4 | 736 | .get_ts_info = enic_get_ts_info, |
bf7bb7b4 | 737 | .get_channels = enic_get_channels, |
f13bbc2f NP |
738 | }; |
739 | ||
740 | void enic_set_ethtool_ops(struct net_device *netdev) | |
741 | { | |
7ad24ea4 | 742 | netdev->ethtool_ops = &enic_ethtool_ops; |
f13bbc2f | 743 | } |