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