]>
Commit | Line | Data |
---|---|---|
812034f1 HS |
1 | /* |
2 | * Copyright (C) 2013-2015 Chelsio Communications. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * The full GNU General Public License is included in this distribution in | |
14 | * the file called "COPYING". | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/firmware.h> | |
19 | #include <linux/mdio.h> | |
20 | ||
21 | #include "cxgb4.h" | |
22 | #include "t4_regs.h" | |
23 | #include "t4fw_api.h" | |
24 | ||
25 | #define EEPROM_MAGIC 0x38E2F10C | |
26 | ||
27 | static u32 get_msglevel(struct net_device *dev) | |
28 | { | |
29 | return netdev2adap(dev)->msg_enable; | |
30 | } | |
31 | ||
32 | static void set_msglevel(struct net_device *dev, u32 val) | |
33 | { | |
34 | netdev2adap(dev)->msg_enable = val; | |
35 | } | |
36 | ||
37 | static const char stats_strings[][ETH_GSTRING_LEN] = { | |
38 | "TxOctetsOK ", | |
39 | "TxFramesOK ", | |
40 | "TxBroadcastFrames ", | |
41 | "TxMulticastFrames ", | |
42 | "TxUnicastFrames ", | |
43 | "TxErrorFrames ", | |
44 | ||
45 | "TxFrames64 ", | |
46 | "TxFrames65To127 ", | |
47 | "TxFrames128To255 ", | |
48 | "TxFrames256To511 ", | |
49 | "TxFrames512To1023 ", | |
50 | "TxFrames1024To1518 ", | |
51 | "TxFrames1519ToMax ", | |
52 | ||
53 | "TxFramesDropped ", | |
54 | "TxPauseFrames ", | |
55 | "TxPPP0Frames ", | |
56 | "TxPPP1Frames ", | |
57 | "TxPPP2Frames ", | |
58 | "TxPPP3Frames ", | |
59 | "TxPPP4Frames ", | |
60 | "TxPPP5Frames ", | |
61 | "TxPPP6Frames ", | |
62 | "TxPPP7Frames ", | |
63 | ||
64 | "RxOctetsOK ", | |
65 | "RxFramesOK ", | |
66 | "RxBroadcastFrames ", | |
67 | "RxMulticastFrames ", | |
68 | "RxUnicastFrames ", | |
69 | ||
70 | "RxFramesTooLong ", | |
71 | "RxJabberErrors ", | |
72 | "RxFCSErrors ", | |
73 | "RxLengthErrors ", | |
74 | "RxSymbolErrors ", | |
75 | "RxRuntFrames ", | |
76 | ||
77 | "RxFrames64 ", | |
78 | "RxFrames65To127 ", | |
79 | "RxFrames128To255 ", | |
80 | "RxFrames256To511 ", | |
81 | "RxFrames512To1023 ", | |
82 | "RxFrames1024To1518 ", | |
83 | "RxFrames1519ToMax ", | |
84 | ||
85 | "RxPauseFrames ", | |
86 | "RxPPP0Frames ", | |
87 | "RxPPP1Frames ", | |
88 | "RxPPP2Frames ", | |
89 | "RxPPP3Frames ", | |
90 | "RxPPP4Frames ", | |
91 | "RxPPP5Frames ", | |
92 | "RxPPP6Frames ", | |
93 | "RxPPP7Frames ", | |
94 | ||
95 | "RxBG0FramesDropped ", | |
96 | "RxBG1FramesDropped ", | |
97 | "RxBG2FramesDropped ", | |
98 | "RxBG3FramesDropped ", | |
99 | "RxBG0FramesTrunc ", | |
100 | "RxBG1FramesTrunc ", | |
101 | "RxBG2FramesTrunc ", | |
102 | "RxBG3FramesTrunc ", | |
103 | ||
104 | "TSO ", | |
105 | "TxCsumOffload ", | |
106 | "RxCsumGood ", | |
107 | "VLANextractions ", | |
108 | "VLANinsertions ", | |
109 | "GROpackets ", | |
110 | "GROmerged ", | |
a4cfd929 HS |
111 | }; |
112 | ||
113 | static char adapter_stats_strings[][ETH_GSTRING_LEN] = { | |
114 | "db_drop ", | |
115 | "db_full ", | |
116 | "db_empty ", | |
117 | "tcp_ipv4_out_rsts ", | |
118 | "tcp_ipv4_in_segs ", | |
119 | "tcp_ipv4_out_segs ", | |
120 | "tcp_ipv4_retrans_segs ", | |
121 | "tcp_ipv6_out_rsts ", | |
122 | "tcp_ipv6_in_segs ", | |
123 | "tcp_ipv6_out_segs ", | |
124 | "tcp_ipv6_retrans_segs ", | |
125 | "usm_ddp_frames ", | |
126 | "usm_ddp_octets ", | |
127 | "usm_ddp_drops ", | |
128 | "rdma_no_rqe_mod_defer ", | |
129 | "rdma_no_rqe_pkt_defer ", | |
130 | "tp_err_ofld_no_neigh ", | |
131 | "tp_err_ofld_cong_defer ", | |
132 | "write_coal_success ", | |
133 | "write_coal_fail ", | |
812034f1 HS |
134 | }; |
135 | ||
a6222975 HS |
136 | static char channel_stats_strings[][ETH_GSTRING_LEN] = { |
137 | "--------Channel--------- ", | |
138 | "tp_cpl_requests ", | |
139 | "tp_cpl_responses ", | |
140 | "tp_mac_in_errs ", | |
141 | "tp_hdr_in_errs ", | |
142 | "tp_tcp_in_errs ", | |
143 | "tp_tcp6_in_errs ", | |
144 | "tp_tnl_cong_drops ", | |
145 | "tp_tnl_tx_drops ", | |
146 | "tp_ofld_vlan_drops ", | |
147 | "tp_ofld_chan_drops ", | |
148 | "fcoe_octets_ddp ", | |
149 | "fcoe_frames_ddp ", | |
150 | "fcoe_frames_drop ", | |
151 | }; | |
152 | ||
65046e84 HS |
153 | static char loopback_stats_strings[][ETH_GSTRING_LEN] = { |
154 | "-------Loopback----------- ", | |
155 | "octets_ok ", | |
156 | "frames_ok ", | |
157 | "bcast_frames ", | |
158 | "mcast_frames ", | |
159 | "ucast_frames ", | |
160 | "error_frames ", | |
161 | "frames_64 ", | |
162 | "frames_65_to_127 ", | |
163 | "frames_128_to_255 ", | |
164 | "frames_256_to_511 ", | |
165 | "frames_512_to_1023 ", | |
166 | "frames_1024_to_1518 ", | |
167 | "frames_1519_to_max ", | |
168 | "frames_dropped ", | |
169 | "bg0_frames_dropped ", | |
170 | "bg1_frames_dropped ", | |
171 | "bg2_frames_dropped ", | |
172 | "bg3_frames_dropped ", | |
173 | "bg0_frames_trunc ", | |
174 | "bg1_frames_trunc ", | |
175 | "bg2_frames_trunc ", | |
176 | "bg3_frames_trunc ", | |
177 | }; | |
178 | ||
812034f1 HS |
179 | static int get_sset_count(struct net_device *dev, int sset) |
180 | { | |
181 | switch (sset) { | |
182 | case ETH_SS_STATS: | |
a4cfd929 | 183 | return ARRAY_SIZE(stats_strings) + |
a6222975 | 184 | ARRAY_SIZE(adapter_stats_strings) + |
65046e84 HS |
185 | ARRAY_SIZE(channel_stats_strings) + |
186 | ARRAY_SIZE(loopback_stats_strings); | |
812034f1 HS |
187 | default: |
188 | return -EOPNOTSUPP; | |
189 | } | |
190 | } | |
191 | ||
192 | static int get_regs_len(struct net_device *dev) | |
193 | { | |
194 | struct adapter *adap = netdev2adap(dev); | |
195 | ||
196 | return t4_get_regs_len(adap); | |
197 | } | |
198 | ||
199 | static int get_eeprom_len(struct net_device *dev) | |
200 | { | |
201 | return EEPROMSIZE; | |
202 | } | |
203 | ||
204 | static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | |
205 | { | |
206 | struct adapter *adapter = netdev2adap(dev); | |
207 | u32 exprom_vers; | |
208 | ||
209 | strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); | |
210 | strlcpy(info->version, cxgb4_driver_version, | |
211 | sizeof(info->version)); | |
212 | strlcpy(info->bus_info, pci_name(adapter->pdev), | |
213 | sizeof(info->bus_info)); | |
214 | ||
215 | if (adapter->params.fw_vers) | |
216 | snprintf(info->fw_version, sizeof(info->fw_version), | |
217 | "%u.%u.%u.%u, TP %u.%u.%u.%u", | |
218 | FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), | |
219 | FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), | |
220 | FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), | |
221 | FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers), | |
222 | FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), | |
223 | FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), | |
224 | FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), | |
225 | FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); | |
226 | ||
227 | if (!t4_get_exprom_version(adapter, &exprom_vers)) | |
228 | snprintf(info->erom_version, sizeof(info->erom_version), | |
229 | "%u.%u.%u.%u", | |
230 | FW_HDR_FW_VER_MAJOR_G(exprom_vers), | |
231 | FW_HDR_FW_VER_MINOR_G(exprom_vers), | |
232 | FW_HDR_FW_VER_MICRO_G(exprom_vers), | |
233 | FW_HDR_FW_VER_BUILD_G(exprom_vers)); | |
234 | } | |
235 | ||
236 | static void get_strings(struct net_device *dev, u32 stringset, u8 *data) | |
237 | { | |
a4cfd929 | 238 | if (stringset == ETH_SS_STATS) { |
812034f1 | 239 | memcpy(data, stats_strings, sizeof(stats_strings)); |
a4cfd929 HS |
240 | data += sizeof(stats_strings); |
241 | memcpy(data, adapter_stats_strings, | |
242 | sizeof(adapter_stats_strings)); | |
a6222975 HS |
243 | data += sizeof(adapter_stats_strings); |
244 | memcpy(data, channel_stats_strings, | |
245 | sizeof(channel_stats_strings)); | |
65046e84 HS |
246 | data += sizeof(channel_stats_strings); |
247 | memcpy(data, loopback_stats_strings, | |
248 | sizeof(loopback_stats_strings)); | |
a4cfd929 | 249 | } |
812034f1 HS |
250 | } |
251 | ||
252 | /* port stats maintained per queue of the port. They should be in the same | |
253 | * order as in stats_strings above. | |
254 | */ | |
255 | struct queue_port_stats { | |
256 | u64 tso; | |
257 | u64 tx_csum; | |
258 | u64 rx_csum; | |
259 | u64 vlan_ex; | |
260 | u64 vlan_ins; | |
261 | u64 gro_pkts; | |
262 | u64 gro_merged; | |
263 | }; | |
264 | ||
a4cfd929 HS |
265 | struct adapter_stats { |
266 | u64 db_drop; | |
267 | u64 db_full; | |
268 | u64 db_empty; | |
269 | u64 tcp_v4_out_rsts; | |
270 | u64 tcp_v4_in_segs; | |
271 | u64 tcp_v4_out_segs; | |
272 | u64 tcp_v4_retrans_segs; | |
273 | u64 tcp_v6_out_rsts; | |
274 | u64 tcp_v6_in_segs; | |
275 | u64 tcp_v6_out_segs; | |
276 | u64 tcp_v6_retrans_segs; | |
277 | u64 frames; | |
278 | u64 octets; | |
279 | u64 drops; | |
280 | u64 rqe_dfr_mod; | |
281 | u64 rqe_dfr_pkt; | |
282 | u64 ofld_no_neigh; | |
283 | u64 ofld_cong_defer; | |
284 | u64 wc_success; | |
285 | u64 wc_fail; | |
286 | }; | |
287 | ||
a6222975 HS |
288 | struct channel_stats { |
289 | u64 cpl_req; | |
290 | u64 cpl_rsp; | |
291 | u64 mac_in_errs; | |
292 | u64 hdr_in_errs; | |
293 | u64 tcp_in_errs; | |
294 | u64 tcp6_in_errs; | |
295 | u64 tnl_cong_drops; | |
296 | u64 tnl_tx_drops; | |
297 | u64 ofld_vlan_drops; | |
298 | u64 ofld_chan_drops; | |
299 | u64 octets_ddp; | |
300 | u64 frames_ddp; | |
301 | u64 frames_drop; | |
302 | }; | |
303 | ||
812034f1 HS |
304 | static void collect_sge_port_stats(const struct adapter *adap, |
305 | const struct port_info *p, | |
306 | struct queue_port_stats *s) | |
307 | { | |
308 | int i; | |
309 | const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; | |
310 | const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; | |
311 | ||
312 | memset(s, 0, sizeof(*s)); | |
313 | for (i = 0; i < p->nqsets; i++, rx++, tx++) { | |
314 | s->tso += tx->tso; | |
315 | s->tx_csum += tx->tx_cso; | |
316 | s->rx_csum += rx->stats.rx_cso; | |
317 | s->vlan_ex += rx->stats.vlan_ex; | |
318 | s->vlan_ins += tx->vlan_ins; | |
319 | s->gro_pkts += rx->stats.lro_pkts; | |
320 | s->gro_merged += rx->stats.lro_merged; | |
321 | } | |
322 | } | |
323 | ||
a4cfd929 HS |
324 | static void collect_adapter_stats(struct adapter *adap, struct adapter_stats *s) |
325 | { | |
326 | struct tp_tcp_stats v4, v6; | |
327 | struct tp_rdma_stats rdma_stats; | |
328 | struct tp_err_stats err_stats; | |
329 | struct tp_usm_stats usm_stats; | |
330 | u64 val1, val2; | |
331 | ||
332 | memset(s, 0, sizeof(*s)); | |
333 | ||
334 | spin_lock(&adap->stats_lock); | |
335 | t4_tp_get_tcp_stats(adap, &v4, &v6); | |
336 | t4_tp_get_rdma_stats(adap, &rdma_stats); | |
337 | t4_get_usm_stats(adap, &usm_stats); | |
338 | t4_tp_get_err_stats(adap, &err_stats); | |
339 | spin_unlock(&adap->stats_lock); | |
340 | ||
341 | s->db_drop = adap->db_stats.db_drop; | |
342 | s->db_full = adap->db_stats.db_full; | |
343 | s->db_empty = adap->db_stats.db_empty; | |
344 | ||
345 | s->tcp_v4_out_rsts = v4.tcp_out_rsts; | |
346 | s->tcp_v4_in_segs = v4.tcp_in_segs; | |
347 | s->tcp_v4_out_segs = v4.tcp_out_segs; | |
348 | s->tcp_v4_retrans_segs = v4.tcp_retrans_segs; | |
349 | s->tcp_v6_out_rsts = v6.tcp_out_rsts; | |
350 | s->tcp_v6_in_segs = v6.tcp_in_segs; | |
351 | s->tcp_v6_out_segs = v6.tcp_out_segs; | |
352 | s->tcp_v6_retrans_segs = v6.tcp_retrans_segs; | |
353 | ||
354 | if (is_offload(adap)) { | |
355 | s->frames = usm_stats.frames; | |
356 | s->octets = usm_stats.octets; | |
357 | s->drops = usm_stats.drops; | |
358 | s->rqe_dfr_mod = rdma_stats.rqe_dfr_mod; | |
359 | s->rqe_dfr_pkt = rdma_stats.rqe_dfr_pkt; | |
360 | } | |
361 | ||
362 | s->ofld_no_neigh = err_stats.ofld_no_neigh; | |
363 | s->ofld_cong_defer = err_stats.ofld_cong_defer; | |
364 | ||
365 | if (!is_t4(adap->params.chip)) { | |
366 | int v; | |
367 | ||
368 | v = t4_read_reg(adap, SGE_STAT_CFG_A); | |
369 | if (STATSOURCE_T5_G(v) == 7) { | |
370 | val2 = t4_read_reg(adap, SGE_STAT_MATCH_A); | |
371 | val1 = t4_read_reg(adap, SGE_STAT_TOTAL_A); | |
372 | s->wc_success = val1 - val2; | |
373 | s->wc_fail = val2; | |
374 | } | |
375 | } | |
376 | } | |
377 | ||
a6222975 HS |
378 | static void collect_channel_stats(struct adapter *adap, struct channel_stats *s, |
379 | u8 i) | |
380 | { | |
381 | struct tp_cpl_stats cpl_stats; | |
382 | struct tp_err_stats err_stats; | |
383 | struct tp_fcoe_stats fcoe_stats; | |
384 | ||
385 | memset(s, 0, sizeof(*s)); | |
386 | ||
387 | spin_lock(&adap->stats_lock); | |
388 | t4_tp_get_cpl_stats(adap, &cpl_stats); | |
389 | t4_tp_get_err_stats(adap, &err_stats); | |
390 | t4_get_fcoe_stats(adap, i, &fcoe_stats); | |
391 | spin_unlock(&adap->stats_lock); | |
392 | ||
393 | s->cpl_req = cpl_stats.req[i]; | |
394 | s->cpl_rsp = cpl_stats.rsp[i]; | |
395 | s->mac_in_errs = err_stats.mac_in_errs[i]; | |
396 | s->hdr_in_errs = err_stats.hdr_in_errs[i]; | |
397 | s->tcp_in_errs = err_stats.tcp_in_errs[i]; | |
398 | s->tcp6_in_errs = err_stats.tcp6_in_errs[i]; | |
399 | s->tnl_cong_drops = err_stats.tnl_cong_drops[i]; | |
400 | s->tnl_tx_drops = err_stats.tnl_tx_drops[i]; | |
401 | s->ofld_vlan_drops = err_stats.ofld_vlan_drops[i]; | |
402 | s->ofld_chan_drops = err_stats.ofld_chan_drops[i]; | |
403 | s->octets_ddp = fcoe_stats.octets_ddp; | |
404 | s->frames_ddp = fcoe_stats.frames_ddp; | |
405 | s->frames_drop = fcoe_stats.frames_drop; | |
406 | } | |
407 | ||
812034f1 HS |
408 | static void get_stats(struct net_device *dev, struct ethtool_stats *stats, |
409 | u64 *data) | |
410 | { | |
411 | struct port_info *pi = netdev_priv(dev); | |
412 | struct adapter *adapter = pi->adapter; | |
65046e84 HS |
413 | struct lb_port_stats s; |
414 | int i; | |
415 | u64 *p0; | |
812034f1 | 416 | |
a4cfd929 HS |
417 | t4_get_port_stats_offset(adapter, pi->tx_chan, |
418 | (struct port_stats *)data, | |
419 | &pi->stats_base); | |
812034f1 HS |
420 | |
421 | data += sizeof(struct port_stats) / sizeof(u64); | |
422 | collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); | |
423 | data += sizeof(struct queue_port_stats) / sizeof(u64); | |
a4cfd929 | 424 | collect_adapter_stats(adapter, (struct adapter_stats *)data); |
a6222975 HS |
425 | data += sizeof(struct adapter_stats) / sizeof(u64); |
426 | ||
427 | *data++ = (u64)pi->port_id; | |
428 | collect_channel_stats(adapter, (struct channel_stats *)data, | |
429 | pi->port_id); | |
65046e84 HS |
430 | data += sizeof(struct channel_stats) / sizeof(u64); |
431 | ||
432 | *data++ = (u64)pi->port_id; | |
433 | memset(&s, 0, sizeof(s)); | |
434 | t4_get_lb_stats(adapter, pi->port_id, &s); | |
a6222975 | 435 | |
65046e84 HS |
436 | p0 = &s.octets; |
437 | for (i = 0; i < ARRAY_SIZE(loopback_stats_strings) - 1; i++) | |
438 | *data++ = (unsigned long long)*p0++; | |
812034f1 HS |
439 | } |
440 | ||
441 | static void get_regs(struct net_device *dev, struct ethtool_regs *regs, | |
442 | void *buf) | |
443 | { | |
444 | struct adapter *adap = netdev2adap(dev); | |
445 | size_t buf_size; | |
446 | ||
447 | buf_size = t4_get_regs_len(adap); | |
448 | regs->version = mk_adap_vers(adap); | |
449 | t4_get_regs(adap, buf, buf_size); | |
450 | } | |
451 | ||
452 | static int restart_autoneg(struct net_device *dev) | |
453 | { | |
454 | struct port_info *p = netdev_priv(dev); | |
455 | ||
456 | if (!netif_running(dev)) | |
457 | return -EAGAIN; | |
458 | if (p->link_cfg.autoneg != AUTONEG_ENABLE) | |
459 | return -EINVAL; | |
b2612722 | 460 | t4_restart_aneg(p->adapter, p->adapter->pf, p->tx_chan); |
812034f1 HS |
461 | return 0; |
462 | } | |
463 | ||
464 | static int identify_port(struct net_device *dev, | |
465 | enum ethtool_phys_id_state state) | |
466 | { | |
467 | unsigned int val; | |
468 | struct adapter *adap = netdev2adap(dev); | |
469 | ||
470 | if (state == ETHTOOL_ID_ACTIVE) | |
471 | val = 0xffff; | |
472 | else if (state == ETHTOOL_ID_INACTIVE) | |
473 | val = 0; | |
474 | else | |
475 | return -EINVAL; | |
476 | ||
b2612722 | 477 | return t4_identify_port(adap, adap->pf, netdev2pinfo(dev)->viid, val); |
812034f1 HS |
478 | } |
479 | ||
480 | static unsigned int from_fw_linkcaps(enum fw_port_type type, unsigned int caps) | |
481 | { | |
482 | unsigned int v = 0; | |
483 | ||
484 | if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || | |
485 | type == FW_PORT_TYPE_BT_XAUI) { | |
486 | v |= SUPPORTED_TP; | |
487 | if (caps & FW_PORT_CAP_SPEED_100M) | |
488 | v |= SUPPORTED_100baseT_Full; | |
489 | if (caps & FW_PORT_CAP_SPEED_1G) | |
490 | v |= SUPPORTED_1000baseT_Full; | |
491 | if (caps & FW_PORT_CAP_SPEED_10G) | |
492 | v |= SUPPORTED_10000baseT_Full; | |
493 | } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { | |
494 | v |= SUPPORTED_Backplane; | |
495 | if (caps & FW_PORT_CAP_SPEED_1G) | |
496 | v |= SUPPORTED_1000baseKX_Full; | |
497 | if (caps & FW_PORT_CAP_SPEED_10G) | |
498 | v |= SUPPORTED_10000baseKX4_Full; | |
499 | } else if (type == FW_PORT_TYPE_KR) { | |
500 | v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; | |
501 | } else if (type == FW_PORT_TYPE_BP_AP) { | |
502 | v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | | |
503 | SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; | |
504 | } else if (type == FW_PORT_TYPE_BP4_AP) { | |
505 | v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | | |
506 | SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | | |
507 | SUPPORTED_10000baseKX4_Full; | |
508 | } else if (type == FW_PORT_TYPE_FIBER_XFI || | |
509 | type == FW_PORT_TYPE_FIBER_XAUI || | |
510 | type == FW_PORT_TYPE_SFP || | |
511 | type == FW_PORT_TYPE_QSFP_10G || | |
512 | type == FW_PORT_TYPE_QSA) { | |
513 | v |= SUPPORTED_FIBRE; | |
514 | if (caps & FW_PORT_CAP_SPEED_1G) | |
515 | v |= SUPPORTED_1000baseT_Full; | |
516 | if (caps & FW_PORT_CAP_SPEED_10G) | |
517 | v |= SUPPORTED_10000baseT_Full; | |
518 | } else if (type == FW_PORT_TYPE_BP40_BA || | |
519 | type == FW_PORT_TYPE_QSFP) { | |
520 | v |= SUPPORTED_40000baseSR4_Full; | |
521 | v |= SUPPORTED_FIBRE; | |
522 | } | |
523 | ||
524 | if (caps & FW_PORT_CAP_ANEG) | |
525 | v |= SUPPORTED_Autoneg; | |
526 | return v; | |
527 | } | |
528 | ||
529 | static unsigned int to_fw_linkcaps(unsigned int caps) | |
530 | { | |
531 | unsigned int v = 0; | |
532 | ||
533 | if (caps & ADVERTISED_100baseT_Full) | |
534 | v |= FW_PORT_CAP_SPEED_100M; | |
535 | if (caps & ADVERTISED_1000baseT_Full) | |
536 | v |= FW_PORT_CAP_SPEED_1G; | |
537 | if (caps & ADVERTISED_10000baseT_Full) | |
538 | v |= FW_PORT_CAP_SPEED_10G; | |
539 | if (caps & ADVERTISED_40000baseSR4_Full) | |
540 | v |= FW_PORT_CAP_SPEED_40G; | |
541 | return v; | |
542 | } | |
543 | ||
544 | static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
545 | { | |
546 | const struct port_info *p = netdev_priv(dev); | |
547 | ||
548 | if (p->port_type == FW_PORT_TYPE_BT_SGMII || | |
549 | p->port_type == FW_PORT_TYPE_BT_XFI || | |
550 | p->port_type == FW_PORT_TYPE_BT_XAUI) { | |
551 | cmd->port = PORT_TP; | |
552 | } else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || | |
553 | p->port_type == FW_PORT_TYPE_FIBER_XAUI) { | |
554 | cmd->port = PORT_FIBRE; | |
555 | } else if (p->port_type == FW_PORT_TYPE_SFP || | |
556 | p->port_type == FW_PORT_TYPE_QSFP_10G || | |
557 | p->port_type == FW_PORT_TYPE_QSA || | |
558 | p->port_type == FW_PORT_TYPE_QSFP) { | |
559 | if (p->mod_type == FW_PORT_MOD_TYPE_LR || | |
560 | p->mod_type == FW_PORT_MOD_TYPE_SR || | |
561 | p->mod_type == FW_PORT_MOD_TYPE_ER || | |
562 | p->mod_type == FW_PORT_MOD_TYPE_LRM) | |
563 | cmd->port = PORT_FIBRE; | |
564 | else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || | |
565 | p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) | |
566 | cmd->port = PORT_DA; | |
567 | else | |
568 | cmd->port = PORT_OTHER; | |
569 | } else { | |
570 | cmd->port = PORT_OTHER; | |
571 | } | |
572 | ||
573 | if (p->mdio_addr >= 0) { | |
574 | cmd->phy_address = p->mdio_addr; | |
575 | cmd->transceiver = XCVR_EXTERNAL; | |
576 | cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? | |
577 | MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; | |
578 | } else { | |
579 | cmd->phy_address = 0; /* not really, but no better option */ | |
580 | cmd->transceiver = XCVR_INTERNAL; | |
581 | cmd->mdio_support = 0; | |
582 | } | |
583 | ||
584 | cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); | |
585 | cmd->advertising = from_fw_linkcaps(p->port_type, | |
586 | p->link_cfg.advertising); | |
587 | ethtool_cmd_speed_set(cmd, | |
588 | netif_carrier_ok(dev) ? p->link_cfg.speed : 0); | |
589 | cmd->duplex = DUPLEX_FULL; | |
590 | cmd->autoneg = p->link_cfg.autoneg; | |
591 | cmd->maxtxpkt = 0; | |
592 | cmd->maxrxpkt = 0; | |
593 | return 0; | |
594 | } | |
595 | ||
596 | static unsigned int speed_to_caps(int speed) | |
597 | { | |
598 | if (speed == 100) | |
599 | return FW_PORT_CAP_SPEED_100M; | |
600 | if (speed == 1000) | |
601 | return FW_PORT_CAP_SPEED_1G; | |
602 | if (speed == 10000) | |
603 | return FW_PORT_CAP_SPEED_10G; | |
604 | if (speed == 40000) | |
605 | return FW_PORT_CAP_SPEED_40G; | |
606 | return 0; | |
607 | } | |
608 | ||
609 | static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
610 | { | |
611 | unsigned int cap; | |
612 | struct port_info *p = netdev_priv(dev); | |
613 | struct link_config *lc = &p->link_cfg; | |
614 | u32 speed = ethtool_cmd_speed(cmd); | |
615 | ||
616 | if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ | |
617 | return -EINVAL; | |
618 | ||
619 | if (!(lc->supported & FW_PORT_CAP_ANEG)) { | |
620 | /* PHY offers a single speed. See if that's what's | |
621 | * being requested. | |
622 | */ | |
623 | if (cmd->autoneg == AUTONEG_DISABLE && | |
624 | (lc->supported & speed_to_caps(speed))) | |
625 | return 0; | |
626 | return -EINVAL; | |
627 | } | |
628 | ||
629 | if (cmd->autoneg == AUTONEG_DISABLE) { | |
630 | cap = speed_to_caps(speed); | |
631 | ||
632 | if (!(lc->supported & cap) || | |
633 | (speed == 1000) || | |
634 | (speed == 10000) || | |
635 | (speed == 40000)) | |
636 | return -EINVAL; | |
637 | lc->requested_speed = cap; | |
638 | lc->advertising = 0; | |
639 | } else { | |
640 | cap = to_fw_linkcaps(cmd->advertising); | |
641 | if (!(lc->supported & cap)) | |
642 | return -EINVAL; | |
643 | lc->requested_speed = 0; | |
644 | lc->advertising = cap | FW_PORT_CAP_ANEG; | |
645 | } | |
646 | lc->autoneg = cmd->autoneg; | |
647 | ||
648 | if (netif_running(dev)) | |
4036da90 | 649 | return t4_link_l1cfg(p->adapter, p->adapter->pf, p->tx_chan, |
812034f1 HS |
650 | lc); |
651 | return 0; | |
652 | } | |
653 | ||
654 | static void get_pauseparam(struct net_device *dev, | |
655 | struct ethtool_pauseparam *epause) | |
656 | { | |
657 | struct port_info *p = netdev_priv(dev); | |
658 | ||
659 | epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; | |
660 | epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; | |
661 | epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; | |
662 | } | |
663 | ||
664 | static int set_pauseparam(struct net_device *dev, | |
665 | struct ethtool_pauseparam *epause) | |
666 | { | |
667 | struct port_info *p = netdev_priv(dev); | |
668 | struct link_config *lc = &p->link_cfg; | |
669 | ||
670 | if (epause->autoneg == AUTONEG_DISABLE) | |
671 | lc->requested_fc = 0; | |
672 | else if (lc->supported & FW_PORT_CAP_ANEG) | |
673 | lc->requested_fc = PAUSE_AUTONEG; | |
674 | else | |
675 | return -EINVAL; | |
676 | ||
677 | if (epause->rx_pause) | |
678 | lc->requested_fc |= PAUSE_RX; | |
679 | if (epause->tx_pause) | |
680 | lc->requested_fc |= PAUSE_TX; | |
681 | if (netif_running(dev)) | |
4036da90 | 682 | return t4_link_l1cfg(p->adapter, p->adapter->pf, p->tx_chan, |
812034f1 HS |
683 | lc); |
684 | return 0; | |
685 | } | |
686 | ||
687 | static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) | |
688 | { | |
689 | const struct port_info *pi = netdev_priv(dev); | |
690 | const struct sge *s = &pi->adapter->sge; | |
691 | ||
692 | e->rx_max_pending = MAX_RX_BUFFERS; | |
693 | e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; | |
694 | e->rx_jumbo_max_pending = 0; | |
695 | e->tx_max_pending = MAX_TXQ_ENTRIES; | |
696 | ||
697 | e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; | |
698 | e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; | |
699 | e->rx_jumbo_pending = 0; | |
700 | e->tx_pending = s->ethtxq[pi->first_qset].q.size; | |
701 | } | |
702 | ||
703 | static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) | |
704 | { | |
705 | int i; | |
706 | const struct port_info *pi = netdev_priv(dev); | |
707 | struct adapter *adapter = pi->adapter; | |
708 | struct sge *s = &adapter->sge; | |
709 | ||
710 | if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || | |
711 | e->tx_pending > MAX_TXQ_ENTRIES || | |
712 | e->rx_mini_pending > MAX_RSPQ_ENTRIES || | |
713 | e->rx_mini_pending < MIN_RSPQ_ENTRIES || | |
714 | e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) | |
715 | return -EINVAL; | |
716 | ||
717 | if (adapter->flags & FULL_INIT_DONE) | |
718 | return -EBUSY; | |
719 | ||
720 | for (i = 0; i < pi->nqsets; ++i) { | |
721 | s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; | |
722 | s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; | |
723 | s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; | |
724 | } | |
725 | return 0; | |
726 | } | |
727 | ||
728 | /** | |
729 | * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete! | |
730 | * @dev: the network device | |
731 | * @us: the hold-off time in us, or 0 to disable timer | |
732 | * @cnt: the hold-off packet count, or 0 to disable counter | |
733 | * | |
734 | * Set the RX interrupt hold-off parameters for a network device. | |
735 | */ | |
736 | static int set_rx_intr_params(struct net_device *dev, | |
737 | unsigned int us, unsigned int cnt) | |
738 | { | |
739 | int i, err; | |
740 | struct port_info *pi = netdev_priv(dev); | |
741 | struct adapter *adap = pi->adapter; | |
742 | struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; | |
743 | ||
744 | for (i = 0; i < pi->nqsets; i++, q++) { | |
745 | err = cxgb4_set_rspq_intr_params(&q->rspq, us, cnt); | |
746 | if (err) | |
747 | return err; | |
748 | } | |
749 | return 0; | |
750 | } | |
751 | ||
752 | static int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx) | |
753 | { | |
754 | int i; | |
755 | struct port_info *pi = netdev_priv(dev); | |
756 | struct adapter *adap = pi->adapter; | |
757 | struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; | |
758 | ||
759 | for (i = 0; i < pi->nqsets; i++, q++) | |
760 | q->rspq.adaptive_rx = adaptive_rx; | |
761 | ||
762 | return 0; | |
763 | } | |
764 | ||
765 | static int get_adaptive_rx_setting(struct net_device *dev) | |
766 | { | |
767 | struct port_info *pi = netdev_priv(dev); | |
768 | struct adapter *adap = pi->adapter; | |
769 | struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; | |
770 | ||
771 | return q->rspq.adaptive_rx; | |
772 | } | |
773 | ||
774 | static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) | |
775 | { | |
776 | set_adaptive_rx_setting(dev, c->use_adaptive_rx_coalesce); | |
777 | return set_rx_intr_params(dev, c->rx_coalesce_usecs, | |
778 | c->rx_max_coalesced_frames); | |
779 | } | |
780 | ||
781 | static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) | |
782 | { | |
783 | const struct port_info *pi = netdev_priv(dev); | |
784 | const struct adapter *adap = pi->adapter; | |
785 | const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; | |
786 | ||
787 | c->rx_coalesce_usecs = qtimer_val(adap, rq); | |
1ecc7b7a | 788 | c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN_F) ? |
812034f1 HS |
789 | adap->sge.counter_val[rq->pktcnt_idx] : 0; |
790 | c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); | |
791 | return 0; | |
792 | } | |
793 | ||
794 | /** | |
795 | * eeprom_ptov - translate a physical EEPROM address to virtual | |
796 | * @phys_addr: the physical EEPROM address | |
797 | * @fn: the PCI function number | |
798 | * @sz: size of function-specific area | |
799 | * | |
800 | * Translate a physical EEPROM address to virtual. The first 1K is | |
801 | * accessed through virtual addresses starting at 31K, the rest is | |
802 | * accessed through virtual addresses starting at 0. | |
803 | * | |
804 | * The mapping is as follows: | |
805 | * [0..1K) -> [31K..32K) | |
806 | * [1K..1K+A) -> [31K-A..31K) | |
807 | * [1K+A..ES) -> [0..ES-A-1K) | |
808 | * | |
809 | * where A = @fn * @sz, and ES = EEPROM size. | |
810 | */ | |
811 | static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) | |
812 | { | |
813 | fn *= sz; | |
814 | if (phys_addr < 1024) | |
815 | return phys_addr + (31 << 10); | |
816 | if (phys_addr < 1024 + fn) | |
817 | return 31744 - fn + phys_addr - 1024; | |
818 | if (phys_addr < EEPROMSIZE) | |
819 | return phys_addr - 1024 - fn; | |
820 | return -EINVAL; | |
821 | } | |
822 | ||
823 | /* The next two routines implement eeprom read/write from physical addresses. | |
824 | */ | |
825 | static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) | |
826 | { | |
b2612722 | 827 | int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE); |
812034f1 HS |
828 | |
829 | if (vaddr >= 0) | |
830 | vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); | |
831 | return vaddr < 0 ? vaddr : 0; | |
832 | } | |
833 | ||
834 | static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) | |
835 | { | |
b2612722 | 836 | int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE); |
812034f1 HS |
837 | |
838 | if (vaddr >= 0) | |
839 | vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); | |
840 | return vaddr < 0 ? vaddr : 0; | |
841 | } | |
842 | ||
843 | #define EEPROM_MAGIC 0x38E2F10C | |
844 | ||
845 | static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, | |
846 | u8 *data) | |
847 | { | |
848 | int i, err = 0; | |
849 | struct adapter *adapter = netdev2adap(dev); | |
850 | u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); | |
851 | ||
852 | if (!buf) | |
853 | return -ENOMEM; | |
854 | ||
855 | e->magic = EEPROM_MAGIC; | |
856 | for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) | |
857 | err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); | |
858 | ||
859 | if (!err) | |
860 | memcpy(data, buf + e->offset, e->len); | |
861 | kfree(buf); | |
862 | return err; | |
863 | } | |
864 | ||
865 | static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | |
866 | u8 *data) | |
867 | { | |
868 | u8 *buf; | |
869 | int err = 0; | |
870 | u32 aligned_offset, aligned_len, *p; | |
871 | struct adapter *adapter = netdev2adap(dev); | |
872 | ||
873 | if (eeprom->magic != EEPROM_MAGIC) | |
874 | return -EINVAL; | |
875 | ||
876 | aligned_offset = eeprom->offset & ~3; | |
877 | aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; | |
878 | ||
b2612722 HS |
879 | if (adapter->pf > 0) { |
880 | u32 start = 1024 + adapter->pf * EEPROMPFSIZE; | |
812034f1 HS |
881 | |
882 | if (aligned_offset < start || | |
883 | aligned_offset + aligned_len > start + EEPROMPFSIZE) | |
884 | return -EPERM; | |
885 | } | |
886 | ||
887 | if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { | |
888 | /* RMW possibly needed for first or last words. | |
889 | */ | |
890 | buf = kmalloc(aligned_len, GFP_KERNEL); | |
891 | if (!buf) | |
892 | return -ENOMEM; | |
893 | err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); | |
894 | if (!err && aligned_len > 4) | |
895 | err = eeprom_rd_phys(adapter, | |
896 | aligned_offset + aligned_len - 4, | |
897 | (u32 *)&buf[aligned_len - 4]); | |
898 | if (err) | |
899 | goto out; | |
900 | memcpy(buf + (eeprom->offset & 3), data, eeprom->len); | |
901 | } else { | |
902 | buf = data; | |
903 | } | |
904 | ||
905 | err = t4_seeprom_wp(adapter, false); | |
906 | if (err) | |
907 | goto out; | |
908 | ||
909 | for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { | |
910 | err = eeprom_wr_phys(adapter, aligned_offset, *p); | |
911 | aligned_offset += 4; | |
912 | } | |
913 | ||
914 | if (!err) | |
915 | err = t4_seeprom_wp(adapter, true); | |
916 | out: | |
917 | if (buf != data) | |
918 | kfree(buf); | |
919 | return err; | |
920 | } | |
921 | ||
922 | static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) | |
923 | { | |
924 | int ret; | |
925 | const struct firmware *fw; | |
926 | struct adapter *adap = netdev2adap(netdev); | |
927 | unsigned int mbox = PCIE_FW_MASTER_M + 1; | |
402b7645 HS |
928 | u32 pcie_fw; |
929 | unsigned int master; | |
930 | u8 master_vld = 0; | |
931 | ||
932 | pcie_fw = t4_read_reg(adap, PCIE_FW_A); | |
933 | master = PCIE_FW_MASTER_G(pcie_fw); | |
934 | if (pcie_fw & PCIE_FW_MASTER_VLD_F) | |
935 | master_vld = 1; | |
936 | /* if csiostor is the master return */ | |
937 | if (master_vld && (master != adap->pf)) { | |
938 | dev_warn(adap->pdev_dev, | |
939 | "cxgb4 driver needs to be loaded as MASTER to support FW flash\n"); | |
940 | return -EOPNOTSUPP; | |
941 | } | |
812034f1 HS |
942 | |
943 | ef->data[sizeof(ef->data) - 1] = '\0'; | |
944 | ret = request_firmware(&fw, ef->data, adap->pdev_dev); | |
945 | if (ret < 0) | |
946 | return ret; | |
947 | ||
948 | /* If the adapter has been fully initialized then we'll go ahead and | |
949 | * try to get the firmware's cooperation in upgrading to the new | |
950 | * firmware image otherwise we'll try to do the entire job from the | |
951 | * host ... and we always "force" the operation in this path. | |
952 | */ | |
953 | if (adap->flags & FULL_INIT_DONE) | |
954 | mbox = adap->mbox; | |
955 | ||
956 | ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1); | |
957 | release_firmware(fw); | |
958 | if (!ret) | |
959 | dev_info(adap->pdev_dev, | |
960 | "loaded firmware %s, reload cxgb4 driver\n", ef->data); | |
961 | return ret; | |
962 | } | |
963 | ||
812034f1 HS |
964 | static u32 get_rss_table_size(struct net_device *dev) |
965 | { | |
966 | const struct port_info *pi = netdev_priv(dev); | |
967 | ||
968 | return pi->rss_size; | |
969 | } | |
970 | ||
971 | static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc) | |
972 | { | |
973 | const struct port_info *pi = netdev_priv(dev); | |
974 | unsigned int n = pi->rss_size; | |
975 | ||
976 | if (hfunc) | |
977 | *hfunc = ETH_RSS_HASH_TOP; | |
978 | if (!p) | |
979 | return 0; | |
980 | while (n--) | |
981 | p[n] = pi->rss[n]; | |
982 | return 0; | |
983 | } | |
984 | ||
985 | static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key, | |
986 | const u8 hfunc) | |
987 | { | |
988 | unsigned int i; | |
989 | struct port_info *pi = netdev_priv(dev); | |
990 | ||
991 | /* We require at least one supported parameter to be changed and no | |
992 | * change in any of the unsupported parameters | |
993 | */ | |
994 | if (key || | |
995 | (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) | |
996 | return -EOPNOTSUPP; | |
997 | if (!p) | |
998 | return 0; | |
999 | ||
1000 | for (i = 0; i < pi->rss_size; i++) | |
1001 | pi->rss[i] = p[i]; | |
1002 | if (pi->adapter->flags & FULL_INIT_DONE) | |
1003 | return cxgb4_write_rss(pi, pi->rss); | |
1004 | return 0; | |
1005 | } | |
1006 | ||
1007 | static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, | |
1008 | u32 *rules) | |
1009 | { | |
1010 | const struct port_info *pi = netdev_priv(dev); | |
1011 | ||
1012 | switch (info->cmd) { | |
1013 | case ETHTOOL_GRXFH: { | |
1014 | unsigned int v = pi->rss_mode; | |
1015 | ||
1016 | info->data = 0; | |
1017 | switch (info->flow_type) { | |
1018 | case TCP_V4_FLOW: | |
1019 | if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) | |
1020 | info->data = RXH_IP_SRC | RXH_IP_DST | | |
1021 | RXH_L4_B_0_1 | RXH_L4_B_2_3; | |
1022 | else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) | |
1023 | info->data = RXH_IP_SRC | RXH_IP_DST; | |
1024 | break; | |
1025 | case UDP_V4_FLOW: | |
1026 | if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) && | |
1027 | (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) | |
1028 | info->data = RXH_IP_SRC | RXH_IP_DST | | |
1029 | RXH_L4_B_0_1 | RXH_L4_B_2_3; | |
1030 | else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) | |
1031 | info->data = RXH_IP_SRC | RXH_IP_DST; | |
1032 | break; | |
1033 | case SCTP_V4_FLOW: | |
1034 | case AH_ESP_V4_FLOW: | |
1035 | case IPV4_FLOW: | |
1036 | if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) | |
1037 | info->data = RXH_IP_SRC | RXH_IP_DST; | |
1038 | break; | |
1039 | case TCP_V6_FLOW: | |
1040 | if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) | |
1041 | info->data = RXH_IP_SRC | RXH_IP_DST | | |
1042 | RXH_L4_B_0_1 | RXH_L4_B_2_3; | |
1043 | else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) | |
1044 | info->data = RXH_IP_SRC | RXH_IP_DST; | |
1045 | break; | |
1046 | case UDP_V6_FLOW: | |
1047 | if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) && | |
1048 | (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) | |
1049 | info->data = RXH_IP_SRC | RXH_IP_DST | | |
1050 | RXH_L4_B_0_1 | RXH_L4_B_2_3; | |
1051 | else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) | |
1052 | info->data = RXH_IP_SRC | RXH_IP_DST; | |
1053 | break; | |
1054 | case SCTP_V6_FLOW: | |
1055 | case AH_ESP_V6_FLOW: | |
1056 | case IPV6_FLOW: | |
1057 | if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) | |
1058 | info->data = RXH_IP_SRC | RXH_IP_DST; | |
1059 | break; | |
1060 | } | |
1061 | return 0; | |
1062 | } | |
1063 | case ETHTOOL_GRXRINGS: | |
1064 | info->data = pi->nqsets; | |
1065 | return 0; | |
1066 | } | |
1067 | return -EOPNOTSUPP; | |
1068 | } | |
1069 | ||
1070 | static const struct ethtool_ops cxgb_ethtool_ops = { | |
1071 | .get_settings = get_settings, | |
1072 | .set_settings = set_settings, | |
1073 | .get_drvinfo = get_drvinfo, | |
1074 | .get_msglevel = get_msglevel, | |
1075 | .set_msglevel = set_msglevel, | |
1076 | .get_ringparam = get_sge_param, | |
1077 | .set_ringparam = set_sge_param, | |
1078 | .get_coalesce = get_coalesce, | |
1079 | .set_coalesce = set_coalesce, | |
1080 | .get_eeprom_len = get_eeprom_len, | |
1081 | .get_eeprom = get_eeprom, | |
1082 | .set_eeprom = set_eeprom, | |
1083 | .get_pauseparam = get_pauseparam, | |
1084 | .set_pauseparam = set_pauseparam, | |
1085 | .get_link = ethtool_op_get_link, | |
1086 | .get_strings = get_strings, | |
1087 | .set_phys_id = identify_port, | |
1088 | .nway_reset = restart_autoneg, | |
1089 | .get_sset_count = get_sset_count, | |
1090 | .get_ethtool_stats = get_stats, | |
1091 | .get_regs_len = get_regs_len, | |
1092 | .get_regs = get_regs, | |
812034f1 HS |
1093 | .get_rxnfc = get_rxnfc, |
1094 | .get_rxfh_indir_size = get_rss_table_size, | |
1095 | .get_rxfh = get_rss_table, | |
1096 | .set_rxfh = set_rss_table, | |
1097 | .flash_device = set_flash, | |
1098 | }; | |
1099 | ||
1100 | void cxgb4_set_ethtool_ops(struct net_device *netdev) | |
1101 | { | |
1102 | netdev->ethtool_ops = &cxgb_ethtool_ops; | |
1103 | } |