1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2003 - 2009 NetXen, Inc. |
4 | * Copyright (C) 2009 - QLogic Corporation. |
5 | * All rights reserved. |
6 | */ |
7 | |
8 | #include <linux/types.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/pci.h> |
11 | #include <asm/io.h> |
12 | #include <linux/netdevice.h> |
13 | #include <linux/ethtool.h> |
14 | |
15 | #include "netxen_nic.h" |
16 | #include "netxen_nic_hw.h" |
17 | |
18 | struct netxen_nic_stats { |
19 | char stat_string[ETH_GSTRING_LEN]; |
20 | int sizeof_stat; |
21 | int stat_offset; |
22 | }; |
23 | |
24 | #define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \ |
25 | offsetof(struct netxen_adapter, m) |
26 | |
27 | #define NETXEN_NIC_PORT_WINDOW 0x10000 |
28 | #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF |
29 | |
30 | static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { |
31 | {"xmit_called" , NETXEN_NIC_STAT(stats.xmitcalled)}, |
32 | {"xmit_finished" , NETXEN_NIC_STAT(stats.xmitfinished)}, |
33 | {"rx_dropped" , NETXEN_NIC_STAT(stats.rxdropped)}, |
34 | {"tx_dropped" , NETXEN_NIC_STAT(stats.txdropped)}, |
35 | {"csummed" , NETXEN_NIC_STAT(stats.csummed)}, |
36 | {"rx_pkts" , NETXEN_NIC_STAT(stats.rx_pkts)}, |
37 | {"lro_pkts" , NETXEN_NIC_STAT(stats.lro_pkts)}, |
38 | {"rx_bytes" , NETXEN_NIC_STAT(stats.rxbytes)}, |
39 | {"tx_bytes" , NETXEN_NIC_STAT(stats.txbytes)}, |
40 | }; |
41 | |
42 | #define NETXEN_NIC_STATS_LEN ARRAY_SIZE(netxen_nic_gstrings_stats) |
43 | |
44 | static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = { |
45 | "Register_Test_on_offline" , |
46 | "Link_Test_on_offline" |
47 | }; |
48 | |
49 | #define NETXEN_NIC_TEST_LEN ARRAY_SIZE(netxen_nic_gstrings_test) |
50 | |
51 | #define NETXEN_NIC_REGS_COUNT 30 |
52 | #define NETXEN_NIC_REGS_LEN (NETXEN_NIC_REGS_COUNT * sizeof(__le32)) |
53 | #define NETXEN_MAX_EEPROM_LEN 1024 |
54 | |
55 | static int netxen_nic_get_eeprom_len(struct net_device *dev) |
56 | { |
57 | return NETXEN_FLASH_TOTAL_SIZE; |
58 | } |
59 | |
60 | static void |
61 | netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) |
62 | { |
63 | struct netxen_adapter *adapter = netdev_priv(dev); |
64 | u32 fw_major = 0; |
65 | u32 fw_minor = 0; |
66 | u32 fw_build = 0; |
67 | |
68 | strscpy(drvinfo->driver, netxen_nic_driver_name, |
69 | sizeof(drvinfo->driver)); |
70 | strscpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, |
71 | sizeof(drvinfo->version)); |
72 | fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); |
73 | fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); |
74 | fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); |
75 | snprintf(buf: drvinfo->fw_version, size: sizeof(drvinfo->fw_version), |
76 | fmt: "%d.%d.%d" , fw_major, fw_minor, fw_build); |
77 | |
78 | strscpy(drvinfo->bus_info, pci_name(adapter->pdev), |
79 | sizeof(drvinfo->bus_info)); |
80 | } |
81 | |
82 | static int |
83 | netxen_nic_get_link_ksettings(struct net_device *dev, |
84 | struct ethtool_link_ksettings *cmd) |
85 | { |
86 | struct netxen_adapter *adapter = netdev_priv(dev); |
87 | int check_sfp_module = 0; |
88 | u32 supported, advertising; |
89 | |
90 | /* read which mode */ |
91 | if (adapter->ahw.port_type == NETXEN_NIC_GBE) { |
92 | supported = (SUPPORTED_10baseT_Half | |
93 | SUPPORTED_10baseT_Full | |
94 | SUPPORTED_100baseT_Half | |
95 | SUPPORTED_100baseT_Full | |
96 | SUPPORTED_1000baseT_Half | |
97 | SUPPORTED_1000baseT_Full); |
98 | |
99 | advertising = (ADVERTISED_100baseT_Half | |
100 | ADVERTISED_100baseT_Full | |
101 | ADVERTISED_1000baseT_Half | |
102 | ADVERTISED_1000baseT_Full); |
103 | |
104 | cmd->base.port = PORT_TP; |
105 | |
106 | cmd->base.speed = adapter->link_speed; |
107 | cmd->base.duplex = adapter->link_duplex; |
108 | cmd->base.autoneg = adapter->link_autoneg; |
109 | |
110 | } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { |
111 | u32 val; |
112 | |
113 | val = NXRD32(adapter, NETXEN_PORT_MODE_ADDR); |
114 | if (val == NETXEN_PORT_MODE_802_3_AP) { |
115 | supported = SUPPORTED_1000baseT_Full; |
116 | advertising = ADVERTISED_1000baseT_Full; |
117 | } else { |
118 | supported = SUPPORTED_10000baseT_Full; |
119 | advertising = ADVERTISED_10000baseT_Full; |
120 | } |
121 | |
122 | if (netif_running(dev) && adapter->has_link_events) { |
123 | cmd->base.speed = adapter->link_speed; |
124 | cmd->base.autoneg = adapter->link_autoneg; |
125 | cmd->base.duplex = adapter->link_duplex; |
126 | goto skip; |
127 | } |
128 | |
129 | cmd->base.port = PORT_TP; |
130 | |
131 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { |
132 | u16 pcifn = adapter->ahw.pci_func; |
133 | |
134 | val = NXRD32(adapter, P3_LINK_SPEED_REG(pcifn)); |
135 | cmd->base.speed = P3_LINK_SPEED_MHZ * |
136 | P3_LINK_SPEED_VAL(pcifn, val); |
137 | } else |
138 | cmd->base.speed = SPEED_10000; |
139 | |
140 | cmd->base.duplex = DUPLEX_FULL; |
141 | cmd->base.autoneg = AUTONEG_DISABLE; |
142 | } else |
143 | return -EIO; |
144 | |
145 | skip: |
146 | cmd->base.phy_address = adapter->physical_port; |
147 | |
148 | switch (adapter->ahw.board_type) { |
149 | case NETXEN_BRDTYPE_P2_SB35_4G: |
150 | case NETXEN_BRDTYPE_P2_SB31_2G: |
151 | case NETXEN_BRDTYPE_P3_REF_QG: |
152 | case NETXEN_BRDTYPE_P3_4_GB: |
153 | case NETXEN_BRDTYPE_P3_4_GB_MM: |
154 | supported |= SUPPORTED_Autoneg; |
155 | advertising |= ADVERTISED_Autoneg; |
156 | fallthrough; |
157 | case NETXEN_BRDTYPE_P2_SB31_10G_CX4: |
158 | case NETXEN_BRDTYPE_P3_10G_CX4: |
159 | case NETXEN_BRDTYPE_P3_10G_CX4_LP: |
160 | case NETXEN_BRDTYPE_P3_10000_BASE_T: |
161 | supported |= SUPPORTED_TP; |
162 | advertising |= ADVERTISED_TP; |
163 | cmd->base.port = PORT_TP; |
164 | cmd->base.autoneg = (adapter->ahw.board_type == |
165 | NETXEN_BRDTYPE_P2_SB31_10G_CX4) ? |
166 | (AUTONEG_DISABLE) : (adapter->link_autoneg); |
167 | break; |
168 | case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ: |
169 | case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ: |
170 | case NETXEN_BRDTYPE_P3_IMEZ: |
171 | case NETXEN_BRDTYPE_P3_XG_LOM: |
172 | case NETXEN_BRDTYPE_P3_HMEZ: |
173 | supported |= SUPPORTED_MII; |
174 | advertising |= ADVERTISED_MII; |
175 | cmd->base.port = PORT_MII; |
176 | cmd->base.autoneg = AUTONEG_DISABLE; |
177 | break; |
178 | case NETXEN_BRDTYPE_P3_10G_SFP_PLUS: |
179 | case NETXEN_BRDTYPE_P3_10G_SFP_CT: |
180 | case NETXEN_BRDTYPE_P3_10G_SFP_QT: |
181 | advertising |= ADVERTISED_TP; |
182 | supported |= SUPPORTED_TP; |
183 | check_sfp_module = netif_running(dev) && |
184 | adapter->has_link_events; |
185 | fallthrough; |
186 | case NETXEN_BRDTYPE_P2_SB31_10G: |
187 | case NETXEN_BRDTYPE_P3_10G_XFP: |
188 | supported |= SUPPORTED_FIBRE; |
189 | advertising |= ADVERTISED_FIBRE; |
190 | cmd->base.port = PORT_FIBRE; |
191 | cmd->base.autoneg = AUTONEG_DISABLE; |
192 | break; |
193 | case NETXEN_BRDTYPE_P3_10G_TP: |
194 | if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { |
195 | cmd->base.autoneg = AUTONEG_DISABLE; |
196 | supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); |
197 | advertising |= |
198 | (ADVERTISED_FIBRE | ADVERTISED_TP); |
199 | cmd->base.port = PORT_FIBRE; |
200 | check_sfp_module = netif_running(dev) && |
201 | adapter->has_link_events; |
202 | } else { |
203 | supported |= (SUPPORTED_TP | SUPPORTED_Autoneg); |
204 | advertising |= |
205 | (ADVERTISED_TP | ADVERTISED_Autoneg); |
206 | cmd->base.port = PORT_TP; |
207 | } |
208 | break; |
209 | default: |
210 | printk(KERN_ERR "netxen-nic: Unsupported board model %d\n" , |
211 | adapter->ahw.board_type); |
212 | return -EIO; |
213 | } |
214 | |
215 | if (check_sfp_module) { |
216 | switch (adapter->module_type) { |
217 | case LINKEVENT_MODULE_OPTICAL_UNKNOWN: |
218 | case LINKEVENT_MODULE_OPTICAL_SRLR: |
219 | case LINKEVENT_MODULE_OPTICAL_LRM: |
220 | case LINKEVENT_MODULE_OPTICAL_SFP_1G: |
221 | cmd->base.port = PORT_FIBRE; |
222 | break; |
223 | case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE: |
224 | case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN: |
225 | case LINKEVENT_MODULE_TWINAX: |
226 | cmd->base.port = PORT_TP; |
227 | break; |
228 | default: |
229 | cmd->base.port = -1; |
230 | } |
231 | } |
232 | |
233 | if (!netif_running(dev) || !adapter->ahw.linkup) { |
234 | cmd->base.duplex = DUPLEX_UNKNOWN; |
235 | cmd->base.speed = SPEED_UNKNOWN; |
236 | } |
237 | |
238 | ethtool_convert_legacy_u32_to_link_mode(dst: cmd->link_modes.supported, |
239 | legacy_u32: supported); |
240 | ethtool_convert_legacy_u32_to_link_mode(dst: cmd->link_modes.advertising, |
241 | legacy_u32: advertising); |
242 | |
243 | return 0; |
244 | } |
245 | |
246 | static int |
247 | netxen_nic_set_link_ksettings(struct net_device *dev, |
248 | const struct ethtool_link_ksettings *cmd) |
249 | { |
250 | struct netxen_adapter *adapter = netdev_priv(dev); |
251 | u32 speed = cmd->base.speed; |
252 | int ret; |
253 | |
254 | if (adapter->ahw.port_type != NETXEN_NIC_GBE) |
255 | return -EOPNOTSUPP; |
256 | |
257 | if (!(adapter->capabilities & NX_FW_CAPABILITY_GBE_LINK_CFG)) |
258 | return -EOPNOTSUPP; |
259 | |
260 | ret = nx_fw_cmd_set_gbe_port(adapter, speed, duplex: cmd->base.duplex, |
261 | autoneg: cmd->base.autoneg); |
262 | if (ret == NX_RCODE_NOT_SUPPORTED) |
263 | return -EOPNOTSUPP; |
264 | else if (ret) |
265 | return -EIO; |
266 | |
267 | adapter->link_speed = speed; |
268 | adapter->link_duplex = cmd->base.duplex; |
269 | adapter->link_autoneg = cmd->base.autoneg; |
270 | |
271 | if (!netif_running(dev)) |
272 | return 0; |
273 | |
274 | dev->netdev_ops->ndo_stop(dev); |
275 | return dev->netdev_ops->ndo_open(dev); |
276 | } |
277 | |
278 | static int netxen_nic_get_regs_len(struct net_device *dev) |
279 | { |
280 | return NETXEN_NIC_REGS_LEN; |
281 | } |
282 | |
283 | static void |
284 | netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) |
285 | { |
286 | struct netxen_adapter *adapter = netdev_priv(dev); |
287 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; |
288 | struct nx_host_sds_ring *sds_ring; |
289 | u32 *regs_buff = p; |
290 | int ring, i = 0; |
291 | int port = adapter->physical_port; |
292 | |
293 | memset(p, 0, NETXEN_NIC_REGS_LEN); |
294 | |
295 | regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | |
296 | (adapter->pdev)->device; |
297 | |
298 | if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) |
299 | return; |
300 | |
301 | regs_buff[i++] = NXRD32(adapter, CRB_CMDPEG_STATE); |
302 | regs_buff[i++] = NXRD32(adapter, CRB_RCVPEG_STATE); |
303 | regs_buff[i++] = NXRD32(adapter, CRB_FW_CAPABILITIES_1); |
304 | regs_buff[i++] = NXRDIO(adapter, adapter->crb_int_state_reg); |
305 | regs_buff[i++] = NXRD32(adapter, NX_CRB_DEV_REF_COUNT); |
306 | regs_buff[i++] = NXRD32(adapter, NX_CRB_DEV_STATE); |
307 | regs_buff[i++] = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER); |
308 | regs_buff[i++] = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1); |
309 | regs_buff[i++] = NXRD32(adapter, NETXEN_PEG_HALT_STATUS2); |
310 | |
311 | regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_0+0x3c); |
312 | regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_1+0x3c); |
313 | regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_2+0x3c); |
314 | regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_3+0x3c); |
315 | |
316 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { |
317 | |
318 | regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_4+0x3c); |
319 | i += 2; |
320 | |
321 | regs_buff[i++] = NXRD32(adapter, CRB_XG_STATE_P3); |
322 | regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer)); |
323 | |
324 | } else { |
325 | i++; |
326 | |
327 | regs_buff[i++] = NXRD32(adapter, |
328 | NETXEN_NIU_XGE_CONFIG_0+(0x10000*port)); |
329 | regs_buff[i++] = NXRD32(adapter, |
330 | NETXEN_NIU_XGE_CONFIG_1+(0x10000*port)); |
331 | |
332 | regs_buff[i++] = NXRD32(adapter, CRB_XG_STATE); |
333 | regs_buff[i++] = NXRDIO(adapter, |
334 | adapter->tx_ring->crb_cmd_consumer); |
335 | } |
336 | |
337 | regs_buff[i++] = NXRDIO(adapter, adapter->tx_ring->crb_cmd_producer); |
338 | |
339 | regs_buff[i++] = NXRDIO(adapter, |
340 | recv_ctx->rds_rings[0].crb_rcv_producer); |
341 | regs_buff[i++] = NXRDIO(adapter, |
342 | recv_ctx->rds_rings[1].crb_rcv_producer); |
343 | |
344 | regs_buff[i++] = adapter->max_sds_rings; |
345 | |
346 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
347 | sds_ring = &(recv_ctx->sds_rings[ring]); |
348 | regs_buff[i++] = NXRDIO(adapter, |
349 | sds_ring->crb_sts_consumer); |
350 | } |
351 | } |
352 | |
353 | static u32 netxen_nic_test_link(struct net_device *dev) |
354 | { |
355 | struct netxen_adapter *adapter = netdev_priv(dev); |
356 | u32 val, port; |
357 | |
358 | port = adapter->physical_port; |
359 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { |
360 | val = NXRD32(adapter, CRB_XG_STATE_P3); |
361 | val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); |
362 | return (val == XG_LINK_UP_P3) ? 0 : 1; |
363 | } else { |
364 | val = NXRD32(adapter, CRB_XG_STATE); |
365 | val = (val >> port*8) & 0xff; |
366 | return (val == XG_LINK_UP) ? 0 : 1; |
367 | } |
368 | } |
369 | |
370 | static int |
371 | netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, |
372 | u8 *bytes) |
373 | { |
374 | struct netxen_adapter *adapter = netdev_priv(dev); |
375 | int offset; |
376 | int ret; |
377 | |
378 | if (eeprom->len == 0) |
379 | return -EINVAL; |
380 | |
381 | eeprom->magic = (adapter->pdev)->vendor | |
382 | ((adapter->pdev)->device << 16); |
383 | offset = eeprom->offset; |
384 | |
385 | ret = netxen_rom_fast_read_words(adapter, addr: offset, bytes, |
386 | size: eeprom->len); |
387 | if (ret < 0) |
388 | return ret; |
389 | |
390 | return 0; |
391 | } |
392 | |
393 | static void |
394 | netxen_nic_get_ringparam(struct net_device *dev, |
395 | struct ethtool_ringparam *ring, |
396 | struct kernel_ethtool_ringparam *kernel_ring, |
397 | struct netlink_ext_ack *extack) |
398 | { |
399 | struct netxen_adapter *adapter = netdev_priv(dev); |
400 | |
401 | ring->rx_pending = adapter->num_rxd; |
402 | ring->rx_jumbo_pending = adapter->num_jumbo_rxd; |
403 | ring->rx_jumbo_pending += adapter->num_lro_rxd; |
404 | ring->tx_pending = adapter->num_txd; |
405 | |
406 | if (adapter->ahw.port_type == NETXEN_NIC_GBE) { |
407 | ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G; |
408 | ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G; |
409 | } else { |
410 | ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G; |
411 | ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G; |
412 | } |
413 | |
414 | ring->tx_max_pending = MAX_CMD_DESCRIPTORS; |
415 | } |
416 | |
417 | static u32 |
418 | netxen_validate_ringparam(u32 val, u32 min, u32 max, char *r_name) |
419 | { |
420 | u32 num_desc; |
421 | num_desc = max(val, min); |
422 | num_desc = min(num_desc, max); |
423 | num_desc = roundup_pow_of_two(num_desc); |
424 | |
425 | if (val != num_desc) { |
426 | printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n" , |
427 | netxen_nic_driver_name, r_name, num_desc, val); |
428 | } |
429 | |
430 | return num_desc; |
431 | } |
432 | |
433 | static int |
434 | netxen_nic_set_ringparam(struct net_device *dev, |
435 | struct ethtool_ringparam *ring, |
436 | struct kernel_ethtool_ringparam *kernel_ring, |
437 | struct netlink_ext_ack *extack) |
438 | { |
439 | struct netxen_adapter *adapter = netdev_priv(dev); |
440 | u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G; |
441 | u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; |
442 | u16 num_rxd, num_jumbo_rxd, num_txd; |
443 | |
444 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) |
445 | return -EOPNOTSUPP; |
446 | |
447 | if (ring->rx_mini_pending) |
448 | return -EOPNOTSUPP; |
449 | |
450 | if (adapter->ahw.port_type == NETXEN_NIC_GBE) { |
451 | max_rcv_desc = MAX_RCV_DESCRIPTORS_1G; |
452 | max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; |
453 | } |
454 | |
455 | num_rxd = netxen_validate_ringparam(val: ring->rx_pending, |
456 | MIN_RCV_DESCRIPTORS, max: max_rcv_desc, r_name: "rx" ); |
457 | |
458 | num_jumbo_rxd = netxen_validate_ringparam(val: ring->rx_jumbo_pending, |
459 | MIN_JUMBO_DESCRIPTORS, max: max_jumbo_desc, r_name: "rx jumbo" ); |
460 | |
461 | num_txd = netxen_validate_ringparam(val: ring->tx_pending, |
462 | MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, r_name: "tx" ); |
463 | |
464 | if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd && |
465 | num_jumbo_rxd == adapter->num_jumbo_rxd) |
466 | return 0; |
467 | |
468 | adapter->num_rxd = num_rxd; |
469 | adapter->num_jumbo_rxd = num_jumbo_rxd; |
470 | adapter->num_txd = num_txd; |
471 | |
472 | return netxen_nic_reset_context(adapter); |
473 | } |
474 | |
475 | static void |
476 | netxen_nic_get_pauseparam(struct net_device *dev, |
477 | struct ethtool_pauseparam *pause) |
478 | { |
479 | struct netxen_adapter *adapter = netdev_priv(dev); |
480 | __u32 val; |
481 | int port = adapter->physical_port; |
482 | |
483 | pause->autoneg = 0; |
484 | |
485 | if (adapter->ahw.port_type == NETXEN_NIC_GBE) { |
486 | if ((port < 0) || (port >= NETXEN_NIU_MAX_GBE_PORTS)) |
487 | return; |
488 | /* get flow control settings */ |
489 | val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port)); |
490 | pause->rx_pause = netxen_gb_get_rx_flowctl(val); |
491 | val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL); |
492 | switch (port) { |
493 | case 0: |
494 | pause->tx_pause = !(netxen_gb_get_gb0_mask(val)); |
495 | break; |
496 | case 1: |
497 | pause->tx_pause = !(netxen_gb_get_gb1_mask(val)); |
498 | break; |
499 | case 2: |
500 | pause->tx_pause = !(netxen_gb_get_gb2_mask(val)); |
501 | break; |
502 | case 3: |
503 | default: |
504 | pause->tx_pause = !(netxen_gb_get_gb3_mask(val)); |
505 | break; |
506 | } |
507 | } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { |
508 | if ((port < 0) || (port >= NETXEN_NIU_MAX_XG_PORTS)) |
509 | return; |
510 | pause->rx_pause = 1; |
511 | val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL); |
512 | if (port == 0) |
513 | pause->tx_pause = !(netxen_xg_get_xg0_mask(val)); |
514 | else |
515 | pause->tx_pause = !(netxen_xg_get_xg1_mask(val)); |
516 | } else { |
517 | printk(KERN_ERR"%s: Unknown board type: %x\n" , |
518 | netxen_nic_driver_name, adapter->ahw.port_type); |
519 | } |
520 | } |
521 | |
522 | static int |
523 | netxen_nic_set_pauseparam(struct net_device *dev, |
524 | struct ethtool_pauseparam *pause) |
525 | { |
526 | struct netxen_adapter *adapter = netdev_priv(dev); |
527 | __u32 val; |
528 | int port = adapter->physical_port; |
529 | |
530 | /* not supported */ |
531 | if (pause->autoneg) |
532 | return -EINVAL; |
533 | |
534 | /* read mode */ |
535 | if (adapter->ahw.port_type == NETXEN_NIC_GBE) { |
536 | if ((port < 0) || (port >= NETXEN_NIU_MAX_GBE_PORTS)) |
537 | return -EIO; |
538 | /* set flow control */ |
539 | val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port)); |
540 | |
541 | if (pause->rx_pause) |
542 | netxen_gb_rx_flowctl(val); |
543 | else |
544 | netxen_gb_unset_rx_flowctl(val); |
545 | |
546 | NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), |
547 | val); |
548 | /* set autoneg */ |
549 | val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL); |
550 | switch (port) { |
551 | case 0: |
552 | if (pause->tx_pause) |
553 | netxen_gb_unset_gb0_mask(val); |
554 | else |
555 | netxen_gb_set_gb0_mask(val); |
556 | break; |
557 | case 1: |
558 | if (pause->tx_pause) |
559 | netxen_gb_unset_gb1_mask(val); |
560 | else |
561 | netxen_gb_set_gb1_mask(val); |
562 | break; |
563 | case 2: |
564 | if (pause->tx_pause) |
565 | netxen_gb_unset_gb2_mask(val); |
566 | else |
567 | netxen_gb_set_gb2_mask(val); |
568 | break; |
569 | case 3: |
570 | default: |
571 | if (pause->tx_pause) |
572 | netxen_gb_unset_gb3_mask(val); |
573 | else |
574 | netxen_gb_set_gb3_mask(val); |
575 | break; |
576 | } |
577 | NXWR32(adapter, NETXEN_NIU_GB_PAUSE_CTL, val); |
578 | } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { |
579 | if ((port < 0) || (port >= NETXEN_NIU_MAX_XG_PORTS)) |
580 | return -EIO; |
581 | val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL); |
582 | if (port == 0) { |
583 | if (pause->tx_pause) |
584 | netxen_xg_unset_xg0_mask(val); |
585 | else |
586 | netxen_xg_set_xg0_mask(val); |
587 | } else { |
588 | if (pause->tx_pause) |
589 | netxen_xg_unset_xg1_mask(val); |
590 | else |
591 | netxen_xg_set_xg1_mask(val); |
592 | } |
593 | NXWR32(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); |
594 | } else { |
595 | printk(KERN_ERR "%s: Unknown board type: %x\n" , |
596 | netxen_nic_driver_name, |
597 | adapter->ahw.port_type); |
598 | } |
599 | return 0; |
600 | } |
601 | |
602 | static int netxen_nic_reg_test(struct net_device *dev) |
603 | { |
604 | struct netxen_adapter *adapter = netdev_priv(dev); |
605 | u32 data_read, data_written; |
606 | |
607 | data_read = NXRD32(adapter, NETXEN_PCIX_PH_REG(0)); |
608 | if ((data_read & 0xffff) != adapter->pdev->vendor) |
609 | return 1; |
610 | |
611 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) |
612 | return 0; |
613 | |
614 | data_written = (u32)0xa5a5a5a5; |
615 | |
616 | NXWR32(adapter, CRB_SCRATCHPAD_TEST, data_written); |
617 | data_read = NXRD32(adapter, CRB_SCRATCHPAD_TEST); |
618 | if (data_written != data_read) |
619 | return 1; |
620 | |
621 | return 0; |
622 | } |
623 | |
624 | static int netxen_get_sset_count(struct net_device *dev, int sset) |
625 | { |
626 | switch (sset) { |
627 | case ETH_SS_TEST: |
628 | return NETXEN_NIC_TEST_LEN; |
629 | case ETH_SS_STATS: |
630 | return NETXEN_NIC_STATS_LEN; |
631 | default: |
632 | return -EOPNOTSUPP; |
633 | } |
634 | } |
635 | |
636 | static void |
637 | netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, |
638 | u64 *data) |
639 | { |
640 | memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN); |
641 | if ((data[0] = netxen_nic_reg_test(dev))) |
642 | eth_test->flags |= ETH_TEST_FL_FAILED; |
643 | /* link test */ |
644 | if ((data[1] = (u64) netxen_nic_test_link(dev))) |
645 | eth_test->flags |= ETH_TEST_FL_FAILED; |
646 | } |
647 | |
648 | static void |
649 | netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
650 | { |
651 | int index; |
652 | |
653 | switch (stringset) { |
654 | case ETH_SS_TEST: |
655 | memcpy(data, *netxen_nic_gstrings_test, |
656 | NETXEN_NIC_TEST_LEN * ETH_GSTRING_LEN); |
657 | break; |
658 | case ETH_SS_STATS: |
659 | for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) { |
660 | memcpy(data + index * ETH_GSTRING_LEN, |
661 | netxen_nic_gstrings_stats[index].stat_string, |
662 | ETH_GSTRING_LEN); |
663 | } |
664 | break; |
665 | } |
666 | } |
667 | |
668 | static void |
669 | netxen_nic_get_ethtool_stats(struct net_device *dev, |
670 | struct ethtool_stats *stats, u64 *data) |
671 | { |
672 | struct netxen_adapter *adapter = netdev_priv(dev); |
673 | int index; |
674 | |
675 | for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) { |
676 | char *p = |
677 | (char *)adapter + |
678 | netxen_nic_gstrings_stats[index].stat_offset; |
679 | data[index] = |
680 | (netxen_nic_gstrings_stats[index].sizeof_stat == |
681 | sizeof(u64)) ? *(u64 *) p : *(u32 *) p; |
682 | } |
683 | } |
684 | |
685 | static void |
686 | netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
687 | { |
688 | struct netxen_adapter *adapter = netdev_priv(dev); |
689 | u32 wol_cfg = 0; |
690 | |
691 | wol->supported = 0; |
692 | wol->wolopts = 0; |
693 | |
694 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) |
695 | return; |
696 | |
697 | wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); |
698 | if (wol_cfg & (1UL << adapter->portnum)) |
699 | wol->supported |= WAKE_MAGIC; |
700 | |
701 | wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); |
702 | if (wol_cfg & (1UL << adapter->portnum)) |
703 | wol->wolopts |= WAKE_MAGIC; |
704 | } |
705 | |
706 | static int |
707 | netxen_nic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
708 | { |
709 | struct netxen_adapter *adapter = netdev_priv(dev); |
710 | u32 wol_cfg = 0; |
711 | |
712 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) |
713 | return -EOPNOTSUPP; |
714 | |
715 | if (wol->wolopts & ~WAKE_MAGIC) |
716 | return -EOPNOTSUPP; |
717 | |
718 | wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); |
719 | if (!(wol_cfg & (1 << adapter->portnum))) |
720 | return -EOPNOTSUPP; |
721 | |
722 | wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); |
723 | if (wol->wolopts & WAKE_MAGIC) |
724 | wol_cfg |= 1UL << adapter->portnum; |
725 | else |
726 | wol_cfg &= ~(1UL << adapter->portnum); |
727 | NXWR32(adapter, NETXEN_WOL_CONFIG, wol_cfg); |
728 | |
729 | return 0; |
730 | } |
731 | |
732 | /* |
733 | * Set the coalescing parameters. Currently only normal is supported. |
734 | * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the |
735 | * firmware coalescing to default. |
736 | */ |
737 | static int netxen_set_intr_coalesce(struct net_device *netdev, |
738 | struct ethtool_coalesce *ethcoal, |
739 | struct kernel_ethtool_coalesce *kernel_coal, |
740 | struct netlink_ext_ack *extack) |
741 | { |
742 | struct netxen_adapter *adapter = netdev_priv(dev: netdev); |
743 | |
744 | if (!NX_IS_REVISION_P3(adapter->ahw.revision_id)) |
745 | return -EINVAL; |
746 | |
747 | if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) |
748 | return -EINVAL; |
749 | |
750 | /* |
751 | * Return Error if unsupported values or |
752 | * unsupported parameters are set. |
753 | */ |
754 | if (ethcoal->rx_coalesce_usecs > 0xffff || |
755 | ethcoal->rx_max_coalesced_frames > 0xffff || |
756 | ethcoal->tx_coalesce_usecs > 0xffff || |
757 | ethcoal->tx_max_coalesced_frames > 0xffff) |
758 | return -EINVAL; |
759 | |
760 | if (!ethcoal->rx_coalesce_usecs || |
761 | !ethcoal->rx_max_coalesced_frames) { |
762 | adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT; |
763 | adapter->coal.normal.data.rx_time_us = |
764 | NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US; |
765 | adapter->coal.normal.data.rx_packets = |
766 | NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS; |
767 | } else { |
768 | adapter->coal.flags = 0; |
769 | adapter->coal.normal.data.rx_time_us = |
770 | ethcoal->rx_coalesce_usecs; |
771 | adapter->coal.normal.data.rx_packets = |
772 | ethcoal->rx_max_coalesced_frames; |
773 | } |
774 | adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs; |
775 | adapter->coal.normal.data.tx_packets = |
776 | ethcoal->tx_max_coalesced_frames; |
777 | |
778 | netxen_config_intr_coalesce(adapter); |
779 | |
780 | return 0; |
781 | } |
782 | |
783 | static int netxen_get_intr_coalesce(struct net_device *netdev, |
784 | struct ethtool_coalesce *ethcoal, |
785 | struct kernel_ethtool_coalesce *kernel_coal, |
786 | struct netlink_ext_ack *extack) |
787 | { |
788 | struct netxen_adapter *adapter = netdev_priv(dev: netdev); |
789 | |
790 | if (!NX_IS_REVISION_P3(adapter->ahw.revision_id)) |
791 | return -EINVAL; |
792 | |
793 | if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) |
794 | return -EINVAL; |
795 | |
796 | ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us; |
797 | ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us; |
798 | ethcoal->rx_max_coalesced_frames = |
799 | adapter->coal.normal.data.rx_packets; |
800 | ethcoal->tx_max_coalesced_frames = |
801 | adapter->coal.normal.data.tx_packets; |
802 | |
803 | return 0; |
804 | } |
805 | |
806 | static int |
807 | netxen_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) |
808 | { |
809 | struct netxen_adapter *adapter = netdev_priv(dev: netdev); |
810 | struct netxen_minidump *mdump = &adapter->mdump; |
811 | if (adapter->fw_mdump_rdy) |
812 | dump->len = mdump->md_dump_size; |
813 | else |
814 | dump->len = 0; |
815 | |
816 | if (!mdump->md_enabled) |
817 | dump->flag = ETH_FW_DUMP_DISABLE; |
818 | else |
819 | dump->flag = mdump->md_capture_mask; |
820 | |
821 | dump->version = adapter->fw_version; |
822 | return 0; |
823 | } |
824 | |
825 | /* Fw dump levels */ |
826 | static const u32 FW_DUMP_LEVELS[] = { 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff }; |
827 | |
828 | static int |
829 | netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val) |
830 | { |
831 | int i; |
832 | struct netxen_adapter *adapter = netdev_priv(dev: netdev); |
833 | struct netxen_minidump *mdump = &adapter->mdump; |
834 | |
835 | switch (val->flag) { |
836 | case NX_FORCE_FW_DUMP_KEY: |
837 | if (!mdump->md_enabled) { |
838 | netdev_info(dev: netdev, format: "FW dump not enabled\n" ); |
839 | return 0; |
840 | } |
841 | if (adapter->fw_mdump_rdy) { |
842 | netdev_info(dev: netdev, format: "Previous dump not cleared, not forcing dump\n" ); |
843 | return 0; |
844 | } |
845 | netdev_info(dev: netdev, format: "Forcing a fw dump\n" ); |
846 | nx_dev_request_reset(adapter); |
847 | break; |
848 | case NX_DISABLE_FW_DUMP: |
849 | if (mdump->md_enabled) { |
850 | netdev_info(dev: netdev, format: "Disabling FW Dump\n" ); |
851 | mdump->md_enabled = 0; |
852 | } |
853 | break; |
854 | case NX_ENABLE_FW_DUMP: |
855 | if (!mdump->md_enabled) { |
856 | netdev_info(dev: netdev, format: "Enabling FW dump\n" ); |
857 | mdump->md_enabled = 1; |
858 | } |
859 | break; |
860 | case NX_FORCE_FW_RESET: |
861 | netdev_info(dev: netdev, format: "Forcing FW reset\n" ); |
862 | nx_dev_request_reset(adapter); |
863 | adapter->flags &= ~NETXEN_FW_RESET_OWNER; |
864 | break; |
865 | default: |
866 | for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) { |
867 | if (val->flag == FW_DUMP_LEVELS[i]) { |
868 | mdump->md_capture_mask = val->flag; |
869 | netdev_info(dev: netdev, |
870 | format: "Driver mask changed to: 0x%x\n" , |
871 | mdump->md_capture_mask); |
872 | return 0; |
873 | } |
874 | } |
875 | netdev_info(dev: netdev, |
876 | format: "Invalid dump level: 0x%x\n" , val->flag); |
877 | return -EINVAL; |
878 | } |
879 | |
880 | return 0; |
881 | } |
882 | |
883 | static int |
884 | netxen_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, |
885 | void *buffer) |
886 | { |
887 | int i, copy_sz; |
888 | u32 *hdr_ptr, *data; |
889 | struct netxen_adapter *adapter = netdev_priv(dev: netdev); |
890 | struct netxen_minidump *mdump = &adapter->mdump; |
891 | |
892 | |
893 | if (!adapter->fw_mdump_rdy) { |
894 | netdev_info(dev: netdev, format: "Dump not available\n" ); |
895 | return -EINVAL; |
896 | } |
897 | /* Copy template header first */ |
898 | copy_sz = mdump->md_template_size; |
899 | hdr_ptr = (u32 *) mdump->md_template; |
900 | data = buffer; |
901 | for (i = 0; i < copy_sz/sizeof(u32); i++) |
902 | *data++ = cpu_to_le32(*hdr_ptr++); |
903 | |
904 | /* Copy captured dump data */ |
905 | memcpy(buffer + copy_sz, |
906 | mdump->md_capture_buff + mdump->md_template_size, |
907 | mdump->md_capture_size); |
908 | dump->len = copy_sz + mdump->md_capture_size; |
909 | dump->flag = mdump->md_capture_mask; |
910 | |
911 | /* Free dump area once data has been captured */ |
912 | vfree(addr: mdump->md_capture_buff); |
913 | mdump->md_capture_buff = NULL; |
914 | adapter->fw_mdump_rdy = 0; |
915 | netdev_info(dev: netdev, format: "extracted the fw dump Successfully\n" ); |
916 | return 0; |
917 | } |
918 | |
919 | const struct ethtool_ops netxen_nic_ethtool_ops = { |
920 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
921 | ETHTOOL_COALESCE_MAX_FRAMES, |
922 | .get_drvinfo = netxen_nic_get_drvinfo, |
923 | .get_regs_len = netxen_nic_get_regs_len, |
924 | .get_regs = netxen_nic_get_regs, |
925 | .get_link = ethtool_op_get_link, |
926 | .get_eeprom_len = netxen_nic_get_eeprom_len, |
927 | .get_eeprom = netxen_nic_get_eeprom, |
928 | .get_ringparam = netxen_nic_get_ringparam, |
929 | .set_ringparam = netxen_nic_set_ringparam, |
930 | .get_pauseparam = netxen_nic_get_pauseparam, |
931 | .set_pauseparam = netxen_nic_set_pauseparam, |
932 | .get_wol = netxen_nic_get_wol, |
933 | .set_wol = netxen_nic_set_wol, |
934 | .self_test = netxen_nic_diag_test, |
935 | .get_strings = netxen_nic_get_strings, |
936 | .get_ethtool_stats = netxen_nic_get_ethtool_stats, |
937 | .get_sset_count = netxen_get_sset_count, |
938 | .get_coalesce = netxen_get_intr_coalesce, |
939 | .set_coalesce = netxen_set_intr_coalesce, |
940 | .get_dump_flag = netxen_get_dump_flag, |
941 | .get_dump_data = netxen_get_dump_data, |
942 | .set_dump = netxen_set_dump, |
943 | .get_link_ksettings = netxen_nic_get_link_ksettings, |
944 | .set_link_ksettings = netxen_nic_set_link_ksettings, |
945 | }; |
946 | |