blob: 7b0c90efb365e27c7c35fec7068348e37f0d3974 [file] [log] [blame]
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001/*
Sritej Velaga40839129f2010-12-02 20:41:56 +00002 * QLogic qlcnic NIC Driver
Jitendra Kalsaria577ae392013-02-04 12:33:07 +00003 * Copyright (c) 2009-2013 QLogic Corporation
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004 *
Sritej Velaga40839129f2010-12-02 20:41:56 +00005 * See LICENSE.qlcnic for copyright and licensing details.
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00006 */
7
8#include <linux/types.h>
9#include <linux/delay.h>
10#include <linux/pci.h>
11#include <linux/io.h>
12#include <linux/netdevice.h>
13#include <linux/ethtool.h>
14
15#include "qlcnic.h"
16
17struct qlcnic_stats {
18 char stat_string[ETH_GSTRING_LEN];
19 int sizeof_stat;
20 int stat_offset;
21};
22
23#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
24#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
Sony Chacko7e38d042013-01-01 03:20:28 +000025static const u32 qlcnic_fw_dump_level[] = {
26 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
27};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000028
29static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
Sony Chacko7e38d042013-01-01 03:20:28 +000030 {"xmit_called", QLC_SIZEOF(stats.xmitcalled),
31 QLC_OFF(stats.xmitcalled)},
32 {"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
33 QLC_OFF(stats.xmitfinished)},
34 {"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
35 {"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
36 {"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
37 {"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
38 {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
39 {"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
40 {"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
41 {"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
42 {"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
43 {"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
44 {"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000045 {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
Sony Chacko7e38d042013-01-01 03:20:28 +000046 QLC_OFF(stats.skb_alloc_failure)},
47 {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +000048 {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
49 QLC_OFF(stats.rx_dma_map_error)},
50 {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
51 QLC_OFF(stats.tx_dma_map_error)},
Sony Chacko7e38d042013-01-01 03:20:28 +000052 {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
53 QLC_OFF(stats.mac_filter_limit_overrun)},
54 {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
55 QLC_OFF(stats.spurious_intr)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000056
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000057};
58
amit salecha3666e0b2010-10-18 01:47:48 +000059static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
60 "rx unicast frames",
61 "rx multicast frames",
62 "rx broadcast frames",
63 "rx dropped frames",
64 "rx errors",
65 "rx local frames",
66 "rx numbytes",
67 "tx unicast frames",
68 "tx multicast frames",
69 "tx broadcast frames",
70 "tx dropped frames",
71 "tx errors",
72 "tx local frames",
73 "tx numbytes",
74};
75
Sony Chacko7e38d042013-01-01 03:20:28 +000076static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
77 "ctx_tx_bytes",
78 "ctx_tx_pkts",
79 "ctx_tx_errors",
80 "ctx_tx_dropped_pkts",
81 "ctx_tx_num_buffers",
82};
83
84static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
Jitendra Kalsaria54a89972012-04-26 10:31:30 +000085 "mac_tx_frames",
86 "mac_tx_bytes",
87 "mac_tx_mcast_pkts",
88 "mac_tx_bcast_pkts",
89 "mac_tx_pause_cnt",
90 "mac_tx_ctrl_pkt",
91 "mac_tx_lt_64b_pkts",
92 "mac_tx_lt_127b_pkts",
93 "mac_tx_lt_255b_pkts",
94 "mac_tx_lt_511b_pkts",
95 "mac_tx_lt_1023b_pkts",
96 "mac_tx_lt_1518b_pkts",
97 "mac_tx_gt_1518b_pkts",
98 "mac_rx_frames",
99 "mac_rx_bytes",
100 "mac_rx_mcast_pkts",
101 "mac_rx_bcast_pkts",
102 "mac_rx_pause_cnt",
103 "mac_rx_ctrl_pkt",
104 "mac_rx_lt_64b_pkts",
105 "mac_rx_lt_127b_pkts",
106 "mac_rx_lt_255b_pkts",
107 "mac_rx_lt_511b_pkts",
108 "mac_rx_lt_1023b_pkts",
109 "mac_rx_lt_1518b_pkts",
110 "mac_rx_gt_1518b_pkts",
111 "mac_rx_length_error",
112 "mac_rx_length_small",
113 "mac_rx_length_large",
114 "mac_rx_jabber",
115 "mac_rx_dropped",
Sony Chacko7e38d042013-01-01 03:20:28 +0000116 "mac_crc_error",
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000117 "mac_align_error",
Shahed Shaikh52290742013-04-24 12:42:41 +0000118 "eswitch_frames",
119 "eswitch_bytes",
120 "eswitch_multicast_frames",
121 "eswitch_broadcast_frames",
122 "eswitch_unicast_frames",
123 "eswitch_error_free_frames",
124 "eswitch_error_free_bytes",
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000125};
126
Sony Chacko7e38d042013-01-01 03:20:28 +0000127#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400128
129static const char qlcnic_tx_ring_stats_strings[][ETH_GSTRING_LEN] = {
130 "xmit_on",
131 "xmit_off",
132 "xmit_called",
133 "xmit_finished",
134};
135
Sony Chacko7e38d042013-01-01 03:20:28 +0000136static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
137 "ctx_rx_bytes",
138 "ctx_rx_pkts",
139 "ctx_lro_pkt_cnt",
140 "ctx_ip_csum_error",
141 "ctx_rx_pkts_wo_ctx",
Shahed Shaikh8c046412013-05-09 09:25:10 +0000142 "ctx_rx_pkts_drop_wo_sds_on_card",
143 "ctx_rx_pkts_drop_wo_sds_on_host",
Sony Chacko7e38d042013-01-01 03:20:28 +0000144 "ctx_rx_osized_pkts",
145 "ctx_rx_pkts_dropped_wo_rds",
146 "ctx_rx_unexpected_mcast_pkts",
147 "ctx_invalid_mac_address",
Shahed Shaikh8c046412013-05-09 09:25:10 +0000148 "ctx_rx_rds_ring_prim_attempted",
Sony Chacko7e38d042013-01-01 03:20:28 +0000149 "ctx_rx_rds_ring_prim_success",
150 "ctx_num_lro_flows_added",
151 "ctx_num_lro_flows_removed",
152 "ctx_num_lro_flows_active",
153 "ctx_pkts_dropped_unknown",
154};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000155
156static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
157 "Register_Test_on_offline",
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000158 "Link_Test_on_offline",
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000159 "Interrupt_Test_offline",
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000160 "Internal_Loopback_offline",
Shahed Shaikh2e3ea7e2013-08-02 23:15:58 -0400161 "External_Loopback_offline",
Sony Chacko7e38d042013-01-01 03:20:28 +0000162 "EEPROM_Test_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000163};
164
165#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
166
Sony Chacko7e38d042013-01-01 03:20:28 +0000167static inline int qlcnic_82xx_statistics(void)
168{
Shahed Shaikh10758222013-03-08 09:53:51 +0000169 return ARRAY_SIZE(qlcnic_device_gstrings_stats) +
170 ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
Sony Chacko7e38d042013-01-01 03:20:28 +0000171}
172
173static inline int qlcnic_83xx_statistics(void)
174{
175 return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
176 ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
177 ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
178}
179
180static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)
181{
182 if (qlcnic_82xx_check(adapter))
183 return qlcnic_82xx_statistics();
184 else if (qlcnic_83xx_check(adapter))
185 return qlcnic_83xx_statistics();
186 else
187 return -1;
188}
189
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000190#define QLCNIC_RING_REGS_COUNT 20
191#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
192#define QLCNIC_MAX_EEPROM_LEN 1024
193
194static const u32 diag_registers[] = {
Shahed Shaikh2c6196d2013-01-01 03:20:29 +0000195 QLCNIC_CMDPEG_STATE,
196 QLCNIC_RCVPEG_STATE,
197 QLCNIC_FW_CAPABILITIES,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000198 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000199 QLCNIC_CRB_DEV_STATE,
200 QLCNIC_CRB_DRV_STATE,
201 QLCNIC_CRB_DRV_SCRATCH,
202 QLCNIC_CRB_DEV_PARTITION_INFO,
203 QLCNIC_CRB_DRV_IDC_VER,
204 QLCNIC_PEG_ALIVE_COUNTER,
205 QLCNIC_PEG_HALT_STATUS1,
206 QLCNIC_PEG_HALT_STATUS2,
Sony Chacko7e38d042013-01-01 03:20:28 +0000207 -1
208};
209
Shahed Shaikh2c6196d2013-01-01 03:20:29 +0000210
Sony Chacko7e38d042013-01-01 03:20:28 +0000211static const u32 ext_diag_registers[] = {
212 CRB_XG_STATE_P3P,
213 ISR_INT_STATE_REG,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000214 QLCNIC_CRB_PEG_NET_0+0x3c,
215 QLCNIC_CRB_PEG_NET_1+0x3c,
216 QLCNIC_CRB_PEG_NET_2+0x3c,
217 QLCNIC_CRB_PEG_NET_4+0x3c,
218 -1
219};
220
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000221#define QLCNIC_MGMT_API_VERSION 2
Sony Chacko7e38d042013-01-01 03:20:28 +0000222#define QLCNIC_ETHTOOL_REGS_VER 3
223
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000224static int qlcnic_get_regs_len(struct net_device *dev)
225{
Sony Chacko7e38d042013-01-01 03:20:28 +0000226 struct qlcnic_adapter *adapter = netdev_priv(dev);
227 u32 len;
228
229 if (qlcnic_83xx_check(adapter))
230 len = qlcnic_83xx_get_regs_len(adapter);
231 else
232 len = sizeof(ext_diag_registers) + sizeof(diag_registers);
233
234 return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000235}
236
237static int qlcnic_get_eeprom_len(struct net_device *dev)
238{
239 return QLCNIC_FLASH_TOTAL_SIZE;
240}
241
242static void
243qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
244{
245 struct qlcnic_adapter *adapter = netdev_priv(dev);
246 u32 fw_major, fw_minor, fw_build;
Sony Chacko7e38d042013-01-01 03:20:28 +0000247 fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
248 fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
249 fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
Rick Jones68aad782011-11-07 13:29:27 +0000250 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
251 "%d.%d.%d", fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000252
Rick Jones68aad782011-11-07 13:29:27 +0000253 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
254 sizeof(drvinfo->bus_info));
255 strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
256 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
257 sizeof(drvinfo->version));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000258}
259
260static int
261qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
262{
263 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhanib9386622013-05-09 09:25:12 +0000264
265 if (qlcnic_82xx_check(adapter))
266 return qlcnic_82xx_get_settings(adapter, ecmd);
267 else if (qlcnic_83xx_check(adapter))
268 return qlcnic_83xx_get_settings(adapter, ecmd);
269
270 return -EIO;
271}
272
273int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
274 struct ethtool_cmd *ecmd)
275{
Sony Chacko7e38d042013-01-01 03:20:28 +0000276 struct qlcnic_hardware_context *ahw = adapter->ahw;
277 u32 speed, reg;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400278 int check_sfp_module = 0, err = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000279 u16 pcifn = ahw->pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000280
281 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000282 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000283 ecmd->supported = (SUPPORTED_10baseT_Half |
284 SUPPORTED_10baseT_Full |
285 SUPPORTED_100baseT_Half |
286 SUPPORTED_100baseT_Full |
287 SUPPORTED_1000baseT_Half |
288 SUPPORTED_1000baseT_Full);
289
290 ecmd->advertising = (ADVERTISED_100baseT_Half |
291 ADVERTISED_100baseT_Full |
292 ADVERTISED_1000baseT_Half |
293 ADVERTISED_1000baseT_Full);
294
Sony Chacko79788452012-12-04 03:33:53 +0000295 ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
296 ecmd->duplex = adapter->ahw->link_duplex;
297 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000298
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000299 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Sony Chacko7e38d042013-01-01 03:20:28 +0000300 u32 val = 0;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400301 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000302
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000303 if (val == QLCNIC_PORT_MODE_802_3_AP) {
304 ecmd->supported = SUPPORTED_1000baseT_Full;
305 ecmd->advertising = ADVERTISED_1000baseT_Full;
306 } else {
307 ecmd->supported = SUPPORTED_10000baseT_Full;
308 ecmd->advertising = ADVERTISED_10000baseT_Full;
309 }
310
Himanshu Madhanib9386622013-05-09 09:25:12 +0000311 if (netif_running(adapter->netdev) && ahw->has_link_events) {
Rajesh Borundiabeb3d3a2013-08-02 23:15:59 -0400312 if (ahw->linkup) {
313 reg = QLCRD32(adapter,
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400314 P3P_LINK_SPEED_REG(pcifn), &err);
Rajesh Borundiabeb3d3a2013-08-02 23:15:59 -0400315 speed = P3P_LINK_SPEED_VAL(pcifn, reg);
316 ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
317 }
318
Himanshu Madhanib9386622013-05-09 09:25:12 +0000319 ethtool_cmd_speed_set(ecmd, ahw->link_speed);
320 ecmd->autoneg = ahw->link_autoneg;
321 ecmd->duplex = ahw->link_duplex;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000322 goto skip;
323 }
324
Sony Chacko476a4b62012-02-03 13:45:42 +0000325 ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
326 ecmd->duplex = DUPLEX_UNKNOWN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000327 ecmd->autoneg = AUTONEG_DISABLE;
328 } else
329 return -EIO;
330
331skip:
Sony Chacko79788452012-12-04 03:33:53 +0000332 ecmd->phy_address = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000333 ecmd->transceiver = XCVR_EXTERNAL;
334
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000335 switch (adapter->ahw->board_type) {
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000336 case QLCNIC_BRDTYPE_P3P_REF_QG:
337 case QLCNIC_BRDTYPE_P3P_4_GB:
338 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000339
340 ecmd->supported |= SUPPORTED_Autoneg;
341 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000342 case QLCNIC_BRDTYPE_P3P_10G_CX4:
343 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
344 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000345 ecmd->supported |= SUPPORTED_TP;
346 ecmd->advertising |= ADVERTISED_TP;
347 ecmd->port = PORT_TP;
Sony Chacko79788452012-12-04 03:33:53 +0000348 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000349 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000350 case QLCNIC_BRDTYPE_P3P_IMEZ:
351 case QLCNIC_BRDTYPE_P3P_XG_LOM:
352 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000353 ecmd->supported |= SUPPORTED_MII;
354 ecmd->advertising |= ADVERTISED_MII;
355 ecmd->port = PORT_MII;
356 ecmd->autoneg = AUTONEG_DISABLE;
357 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000358 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
359 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
360 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000361 ecmd->advertising |= ADVERTISED_TP;
362 ecmd->supported |= SUPPORTED_TP;
Himanshu Madhanib9386622013-05-09 09:25:12 +0000363 check_sfp_module = netif_running(adapter->netdev) &&
364 ahw->has_link_events;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000365 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000366 ecmd->supported |= SUPPORTED_FIBRE;
367 ecmd->advertising |= ADVERTISED_FIBRE;
368 ecmd->port = PORT_FIBRE;
369 ecmd->autoneg = AUTONEG_DISABLE;
370 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000371 case QLCNIC_BRDTYPE_P3P_10G_TP:
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000372 if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000373 ecmd->autoneg = AUTONEG_DISABLE;
374 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
375 ecmd->advertising |=
376 (ADVERTISED_FIBRE | ADVERTISED_TP);
377 ecmd->port = PORT_FIBRE;
Himanshu Madhanib9386622013-05-09 09:25:12 +0000378 check_sfp_module = netif_running(adapter->netdev) &&
379 ahw->has_link_events;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000380 } else {
381 ecmd->autoneg = AUTONEG_ENABLE;
382 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
383 ecmd->advertising |=
384 (ADVERTISED_TP | ADVERTISED_Autoneg);
385 ecmd->port = PORT_TP;
386 }
387 break;
388 default:
389 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000390 adapter->ahw->board_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000391 return -EIO;
392 }
393
394 if (check_sfp_module) {
Sony Chacko79788452012-12-04 03:33:53 +0000395 switch (adapter->ahw->module_type) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000396 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
397 case LINKEVENT_MODULE_OPTICAL_SRLR:
398 case LINKEVENT_MODULE_OPTICAL_LRM:
399 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
400 ecmd->port = PORT_FIBRE;
401 break;
402 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
403 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
404 case LINKEVENT_MODULE_TWINAX:
405 ecmd->port = PORT_TP;
406 break;
407 default:
408 ecmd->port = PORT_OTHER;
409 }
410 }
411
412 return 0;
413}
414
Sony Chacko7e38d042013-01-01 03:20:28 +0000415static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,
416 struct ethtool_cmd *ecmd)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000417{
Sony Chacko7e38d042013-01-01 03:20:28 +0000418 u32 ret = 0, config = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000419 /* read which mode */
Sony Chacko7e610ca2011-04-28 11:48:19 +0000420 if (ecmd->duplex)
421 config |= 0x1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000422
Sony Chacko7e610ca2011-04-28 11:48:19 +0000423 if (ecmd->autoneg)
424 config |= 0x2;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000425
Sony Chacko7e610ca2011-04-28 11:48:19 +0000426 switch (ethtool_cmd_speed(ecmd)) {
427 case SPEED_10:
428 config |= (0 << 8);
429 break;
430 case SPEED_100:
431 config |= (1 << 8);
432 break;
433 case SPEED_1000:
434 config |= (10 << 8);
435 break;
436 default:
437 return -EIO;
438 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000439
Sony Chacko7e610ca2011-04-28 11:48:19 +0000440 ret = qlcnic_fw_cmd_set_port(adapter, config);
441
442 if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000443 return -EOPNOTSUPP;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000444 else if (ret)
445 return -EIO;
Sony Chacko7e38d042013-01-01 03:20:28 +0000446 return ret;
447}
448
449static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
450{
451 u32 ret = 0;
452 struct qlcnic_adapter *adapter = netdev_priv(dev);
453
454 if (adapter->ahw->port_type != QLCNIC_GBE)
455 return -EOPNOTSUPP;
456
457 if (qlcnic_83xx_check(adapter))
458 ret = qlcnic_83xx_set_settings(adapter, ecmd);
459 else
460 ret = qlcnic_set_port_config(adapter, ecmd);
461
462 if (!ret)
463 return ret;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000464
Sony Chacko79788452012-12-04 03:33:53 +0000465 adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
466 adapter->ahw->link_duplex = ecmd->duplex;
467 adapter->ahw->link_autoneg = ecmd->autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000468
469 if (!netif_running(dev))
470 return 0;
471
472 dev->netdev_ops->ndo_stop(dev);
473 return dev->netdev_ops->ndo_open(dev);
474}
475
Sony Chacko7e38d042013-01-01 03:20:28 +0000476static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
477 u32 *regs_buff)
478{
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400479 int i, j = 0, err = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000480
481 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
482 regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
483 j = 0;
484 while (ext_diag_registers[j] != -1)
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400485 regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++],
486 &err);
Sony Chacko7e38d042013-01-01 03:20:28 +0000487 return i;
488}
489
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000490static void
491qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
492{
493 struct qlcnic_adapter *adapter = netdev_priv(dev);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000494 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000495 struct qlcnic_host_sds_ring *sds_ring;
496 u32 *regs_buff = p;
Sony Chacko7e38d042013-01-01 03:20:28 +0000497 int ring, i = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000498
499 memset(p, 0, qlcnic_get_regs_len(dev));
Sony Chacko7e38d042013-01-01 03:20:28 +0000500
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000501 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000502 (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000503
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000504 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
505 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
506
Sony Chacko7e38d042013-01-01 03:20:28 +0000507 if (qlcnic_82xx_check(adapter))
508 i = qlcnic_82xx_get_registers(adapter, regs_buff);
509 else
510 i = qlcnic_83xx_get_registers(adapter, regs_buff);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000511
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000512 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000513 return;
514
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000515 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
516
517 regs_buff[i++] = 1; /* No. of tx ring */
518 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
519 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
520
521 regs_buff[i++] = 2; /* No. of rx ring */
522 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
523 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
524
525 regs_buff[i++] = adapter->max_sds_rings;
526
527 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
528 sds_ring = &(recv_ctx->sds_rings[ring]);
529 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
530 }
531}
532
533static u32 qlcnic_test_link(struct net_device *dev)
534{
535 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400536 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000537 u32 val;
538
Sony Chacko7e38d042013-01-01 03:20:28 +0000539 if (qlcnic_83xx_check(adapter)) {
540 val = qlcnic_83xx_test_link(adapter);
541 return (val & 1) ? 0 : 1;
542 }
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400543 val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err);
544 if (err == -EIO)
545 return err;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000546 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000547 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000548}
549
550static int
551qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
552 u8 *bytes)
553{
554 struct qlcnic_adapter *adapter = netdev_priv(dev);
555 int offset;
Sony Chacko7e38d042013-01-01 03:20:28 +0000556 int ret = -1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000557
Sony Chacko7e38d042013-01-01 03:20:28 +0000558 if (qlcnic_83xx_check(adapter))
559 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000560 if (eeprom->len == 0)
561 return -EINVAL;
562
563 eeprom->magic = (adapter->pdev)->vendor |
564 ((adapter->pdev)->device << 16);
565 offset = eeprom->offset;
566
Sony Chacko7e38d042013-01-01 03:20:28 +0000567 if (qlcnic_82xx_check(adapter))
568 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
569 eeprom->len);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000570 if (ret < 0)
571 return ret;
572
573 return 0;
574}
575
576static void
577qlcnic_get_ringparam(struct net_device *dev,
578 struct ethtool_ringparam *ring)
579{
580 struct qlcnic_adapter *adapter = netdev_priv(dev);
581
582 ring->rx_pending = adapter->num_rxd;
583 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000584 ring->tx_pending = adapter->num_txd;
585
Sony Chacko90d19002010-10-26 17:53:08 +0000586 ring->rx_max_pending = adapter->max_rxd;
587 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000588 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000589}
590
591static u32
592qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
593{
594 u32 num_desc;
595 num_desc = max(val, min);
596 num_desc = min(num_desc, max);
597 num_desc = roundup_pow_of_two(num_desc);
598
599 if (val != num_desc) {
600 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
601 qlcnic_driver_name, r_name, num_desc, val);
602 }
603
604 return num_desc;
605}
606
607static int
608qlcnic_set_ringparam(struct net_device *dev,
609 struct ethtool_ringparam *ring)
610{
611 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000612 u16 num_rxd, num_jumbo_rxd, num_txd;
613
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000614 if (ring->rx_mini_pending)
615 return -EOPNOTSUPP;
616
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000617 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000618 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000619
620 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000621 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
622 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000623
624 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
625 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
626
627 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
628 num_jumbo_rxd == adapter->num_jumbo_rxd)
629 return 0;
630
631 adapter->num_rxd = num_rxd;
632 adapter->num_jumbo_rxd = num_jumbo_rxd;
633 adapter->num_txd = num_txd;
634
635 return qlcnic_reset_context(adapter);
636}
637
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000638static void qlcnic_get_channels(struct net_device *dev,
639 struct ethtool_channels *channel)
640{
641 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400642 int min;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000643
Sony Chacko79788452012-12-04 03:33:53 +0000644 min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus());
645 channel->max_rx = rounddown_pow_of_two(min);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400646 channel->max_tx = min_t(int, QLCNIC_MAX_TX_RINGS, num_online_cpus());
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000647
648 channel->rx_count = adapter->max_sds_rings;
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400649 channel->tx_count = adapter->max_drv_tx_rings;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000650}
651
652static int qlcnic_set_channels(struct net_device *dev,
653 struct ethtool_channels *channel)
654{
655 struct qlcnic_adapter *adapter = netdev_priv(dev);
656 int err;
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400657 int txq = 0;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000658
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400659 if (channel->other_count || channel->combined_count)
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000660 return -EINVAL;
661
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400662 if (channel->rx_count) {
663 err = qlcnic_validate_max_rss(adapter, channel->rx_count);
664 if (err)
665 return err;
666 }
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000667
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400668 if (channel->tx_count) {
669 err = qlcnic_validate_max_tx_rings(adapter, channel->tx_count);
670 if (err)
671 return err;
672 txq = channel->tx_count;
673 }
674
675 err = qlcnic_set_max_rss(adapter, channel->rx_count, txq);
676 netdev_info(dev, "allocated 0x%x sds rings and 0x%x tx rings\n",
677 adapter->max_sds_rings, adapter->max_drv_tx_rings);
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000678 return err;
679}
680
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000681static void
682qlcnic_get_pauseparam(struct net_device *netdev,
683 struct ethtool_pauseparam *pause)
684{
685 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000686 int port = adapter->ahw->physical_port;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400687 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000688 __u32 val;
689
Sony Chacko7e38d042013-01-01 03:20:28 +0000690 if (qlcnic_83xx_check(adapter)) {
691 qlcnic_83xx_get_pauseparam(adapter, pause);
692 return;
693 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000694 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000695 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
696 return;
697 /* get flow control settings */
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400698 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
699 if (err == -EIO)
700 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000701 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400702 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
703 if (err == -EIO)
704 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000705 switch (port) {
706 case 0:
707 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
708 break;
709 case 1:
710 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
711 break;
712 case 2:
713 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
714 break;
715 case 3:
716 default:
717 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
718 break;
719 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000720 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000721 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
722 return;
723 pause->rx_pause = 1;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400724 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
725 if (err == -EIO)
726 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000727 if (port == 0)
728 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
729 else
730 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
731 } else {
732 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000733 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000734 }
735}
736
737static int
738qlcnic_set_pauseparam(struct net_device *netdev,
739 struct ethtool_pauseparam *pause)
740{
741 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000742 int port = adapter->ahw->physical_port;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400743 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000744 __u32 val;
745
Sony Chacko7e38d042013-01-01 03:20:28 +0000746 if (qlcnic_83xx_check(adapter))
747 return qlcnic_83xx_set_pauseparam(adapter, pause);
748
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000749 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000750 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000751 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
752 return -EIO;
753 /* set flow control */
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400754 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
755 if (err == -EIO)
756 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000757
758 if (pause->rx_pause)
759 qlcnic_gb_rx_flowctl(val);
760 else
761 qlcnic_gb_unset_rx_flowctl(val);
762
763 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
764 val);
Sony Chacko7e38d042013-01-01 03:20:28 +0000765 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000766 /* set autoneg */
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400767 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
768 if (err == -EIO)
769 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000770 switch (port) {
771 case 0:
772 if (pause->tx_pause)
773 qlcnic_gb_unset_gb0_mask(val);
774 else
775 qlcnic_gb_set_gb0_mask(val);
776 break;
777 case 1:
778 if (pause->tx_pause)
779 qlcnic_gb_unset_gb1_mask(val);
780 else
781 qlcnic_gb_set_gb1_mask(val);
782 break;
783 case 2:
784 if (pause->tx_pause)
785 qlcnic_gb_unset_gb2_mask(val);
786 else
787 qlcnic_gb_set_gb2_mask(val);
788 break;
789 case 3:
790 default:
791 if (pause->tx_pause)
792 qlcnic_gb_unset_gb3_mask(val);
793 else
794 qlcnic_gb_set_gb3_mask(val);
795 break;
796 }
797 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000798 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000799 if (!pause->rx_pause || pause->autoneg)
800 return -EOPNOTSUPP;
801
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000802 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
803 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000804
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400805 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
806 if (err == -EIO)
807 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000808 if (port == 0) {
809 if (pause->tx_pause)
810 qlcnic_xg_unset_xg0_mask(val);
811 else
812 qlcnic_xg_set_xg0_mask(val);
813 } else {
814 if (pause->tx_pause)
815 qlcnic_xg_unset_xg1_mask(val);
816 else
817 qlcnic_xg_set_xg1_mask(val);
818 }
819 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
820 } else {
821 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000822 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000823 }
824 return 0;
825}
826
827static int qlcnic_reg_test(struct net_device *dev)
828{
829 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000830 u32 data_read;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400831 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000832
Sony Chacko7e38d042013-01-01 03:20:28 +0000833 if (qlcnic_83xx_check(adapter))
834 return qlcnic_83xx_reg_test(adapter);
835
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400836 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err);
837 if (err == -EIO)
838 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000839 if ((data_read & 0xffff) != adapter->pdev->vendor)
840 return 1;
841
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000842 return 0;
843}
844
Sony Chacko7e38d042013-01-01 03:20:28 +0000845static int qlcnic_eeprom_test(struct net_device *dev)
846{
847 struct qlcnic_adapter *adapter = netdev_priv(dev);
848
849 if (qlcnic_82xx_check(adapter))
850 return 0;
851
852 return qlcnic_83xx_flash_test(adapter);
853}
854
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000855static int qlcnic_get_sset_count(struct net_device *dev, int sset)
856{
Sony Chacko7e38d042013-01-01 03:20:28 +0000857 int len;
858
amit salecha3666e0b2010-10-18 01:47:48 +0000859 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000860 switch (sset) {
861 case ETH_SS_TEST:
862 return QLCNIC_TEST_LEN;
863 case ETH_SS_STATS:
Sony Chacko7e38d042013-01-01 03:20:28 +0000864 len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
865 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
866 qlcnic_83xx_check(adapter))
867 return len;
868 return qlcnic_82xx_statistics();
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000869 default:
870 return -EOPNOTSUPP;
871 }
872}
873
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000874static int qlcnic_irq_test(struct net_device *netdev)
875{
876 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000877 struct qlcnic_hardware_context *ahw = adapter->ahw;
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000878 struct qlcnic_cmd_args cmd;
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000879 int ret, max_sds_rings = adapter->max_sds_rings;
880
881 if (qlcnic_83xx_check(adapter))
882 return qlcnic_83xx_interrupt_test(netdev);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000883
884 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
885 return -EIO;
886
887 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
888 if (ret)
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000889 goto clear_diag_irq;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000890
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000891 ahw->diag_cnt = 0;
Shahed Shaikhb6b43162013-06-22 04:12:00 -0400892 ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
893 if (ret)
894 goto free_diag_res;
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000895
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000896 cmd.req.arg[1] = ahw->pci_func;
897 ret = qlcnic_issue_cmd(adapter, &cmd);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000898 if (ret)
899 goto done;
900
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000901 usleep_range(1000, 12000);
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000902 ret = !ahw->diag_cnt;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000903
904done:
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000905 qlcnic_free_mbx_args(&cmd);
Shahed Shaikhb6b43162013-06-22 04:12:00 -0400906
907free_diag_res:
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000908 qlcnic_diag_free_res(netdev, max_sds_rings);
909
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000910clear_diag_irq:
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000911 adapter->max_sds_rings = max_sds_rings;
912 clear_bit(__QLCNIC_RESETTING, &adapter->state);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400913
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000914 return ret;
915}
916
Rajesh Borundiad1a11052013-04-19 07:01:13 +0000917#define QLCNIC_ILB_PKT_SIZE 64
918#define QLCNIC_NUM_ILB_PKT 16
919#define QLCNIC_ILB_MAX_RCV_LOOP 10
920#define QLCNIC_LB_PKT_POLL_DELAY_MSEC 1
921#define QLCNIC_LB_PKT_POLL_COUNT 20
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000922
923static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
924{
925 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
926
927 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
928
929 memcpy(data, mac, ETH_ALEN);
930 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
931
932 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
933}
934
935int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
936{
937 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
938 qlcnic_create_loopback_buff(buff, mac);
939 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
940}
941
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000942int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000943{
944 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
945 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
946 struct sk_buff *skb;
947 int i, loop, cnt = 0;
948
949 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
Pradeep A. Dalvidae2e9f2012-02-06 11:16:13 +0000950 skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000951 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
952 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
Sony Chacko79788452012-12-04 03:33:53 +0000953 adapter->ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000954 qlcnic_xmit_frame(skb, adapter->netdev);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000955 loop = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000956
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000957 do {
Rajesh Borundiad1a11052013-04-19 07:01:13 +0000958 msleep(QLCNIC_LB_PKT_POLL_DELAY_MSEC);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000959 qlcnic_process_rcv_ring_diag(sds_ring);
Rajesh Borundiad1a11052013-04-19 07:01:13 +0000960 if (loop++ > QLCNIC_LB_PKT_POLL_COUNT)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000961 break;
Sony Chacko79788452012-12-04 03:33:53 +0000962 } while (!adapter->ahw->diag_cnt);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000963
964 dev_kfree_skb_any(skb);
965
Sony Chacko79788452012-12-04 03:33:53 +0000966 if (!adapter->ahw->diag_cnt)
Sony Chacko7e38d042013-01-01 03:20:28 +0000967 dev_warn(&adapter->pdev->dev,
968 "LB Test: packet #%d was not received\n",
969 i + 1);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000970 else
971 cnt++;
972 }
973 if (cnt != i) {
Sony Chacko7e38d042013-01-01 03:20:28 +0000974 dev_err(&adapter->pdev->dev,
975 "LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
976 if (mode != QLCNIC_ILB_MODE)
Manish chopradf3cfbe2011-08-29 12:50:27 +0000977 dev_warn(&adapter->pdev->dev,
Sony Chacko7e38d042013-01-01 03:20:28 +0000978 "WARNING: Please check loopback cable\n");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000979 return -1;
980 }
981 return 0;
982}
983
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000984int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000985{
986 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Himanshu Madhanic2c5e3a2013-08-21 11:24:12 -0400987 int max_drv_tx_rings = adapter->max_drv_tx_rings;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000988 int max_sds_rings = adapter->max_sds_rings;
989 struct qlcnic_host_sds_ring *sds_ring;
Sony Chacko7e38d042013-01-01 03:20:28 +0000990 struct qlcnic_hardware_context *ahw = adapter->ahw;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000991 int loop = 0;
992 int ret;
993
Sony Chacko7e38d042013-01-01 03:20:28 +0000994 if (qlcnic_83xx_check(adapter))
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000995 return qlcnic_83xx_loopback_test(netdev, mode);
996
Sony Chacko7e38d042013-01-01 03:20:28 +0000997 if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
998 dev_info(&adapter->pdev->dev,
999 "Firmware do not support loopback test\n");
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001000 return -EOPNOTSUPP;
1001 }
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001002
Sony Chacko7e38d042013-01-01 03:20:28 +00001003 dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
1004 mode == QLCNIC_ILB_MODE ? "internal" : "external");
1005 if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
1006 dev_warn(&adapter->pdev->dev,
1007 "Loopback test not supported in nonprivileged mode\n");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001008 return 0;
1009 }
1010
1011 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001012 return -EBUSY;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001013
1014 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
1015 if (ret)
1016 goto clear_it;
1017
1018 sds_ring = &adapter->recv_ctx->sds_rings[0];
Amit Kumar Salechae1428d22011-06-29 20:00:50 +00001019 ret = qlcnic_set_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001020 if (ret)
1021 goto free_res;
1022
Sony Chacko7e38d042013-01-01 03:20:28 +00001023 ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001024 do {
1025 msleep(500);
1026 qlcnic_process_rcv_ring_diag(sds_ring);
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001027 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
Jitendra Kalsariab9c11982013-08-02 00:57:39 -04001028 netdev_info(netdev,
1029 "Firmware didn't sent link up event to loopback request\n");
1030 ret = -ETIMEDOUT;
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001031 goto free_res;
Sony Chacko79788452012-12-04 03:33:53 +00001032 } else if (adapter->ahw->diag_cnt) {
1033 ret = adapter->ahw->diag_cnt;
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001034 goto free_res;
1035 }
Sony Chacko7e38d042013-01-01 03:20:28 +00001036 } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001037
Manish chopradf3cfbe2011-08-29 12:50:27 +00001038 ret = qlcnic_do_lb_test(adapter, mode);
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001039
Sony Chacko7e2cf4f2013-01-01 03:20:17 +00001040 qlcnic_clear_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001041
1042 free_res:
1043 qlcnic_diag_free_res(netdev, max_sds_rings);
1044
1045 clear_it:
1046 adapter->max_sds_rings = max_sds_rings;
Himanshu Madhanic2c5e3a2013-08-21 11:24:12 -04001047 adapter->max_drv_tx_rings = max_drv_tx_rings;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001048 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1049 return ret;
1050}
1051
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001052static void
1053qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
1054 u64 *data)
1055{
1056 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001057
Sony Chacko8dec32cc2010-08-17 00:34:24 +00001058 data[0] = qlcnic_reg_test(dev);
1059 if (data[0])
1060 eth_test->flags |= ETH_TEST_FL_FAILED;
1061
1062 data[1] = (u64) qlcnic_test_link(dev);
1063 if (data[1])
1064 eth_test->flags |= ETH_TEST_FL_FAILED;
1065
Sony Chacko13b93ed2011-01-10 00:15:22 +00001066 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001067 data[2] = qlcnic_irq_test(dev);
1068 if (data[2])
1069 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001070
Amit Kumar Salechae1428d22011-06-29 20:00:50 +00001071 data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001072 if (data[3])
1073 eth_test->flags |= ETH_TEST_FL_FAILED;
Sony Chacko7e38d042013-01-01 03:20:28 +00001074
Shahed Shaikh2e3ea7e2013-08-02 23:15:58 -04001075 if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
1076 data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
1077 if (data[4])
1078 eth_test->flags |= ETH_TEST_FL_FAILED;
1079 eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
1080 }
1081
1082 data[5] = qlcnic_eeprom_test(dev);
1083 if (data[5])
Sony Chacko7e38d042013-01-01 03:20:28 +00001084 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001085 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001086}
1087
1088static void
Sony Chacko7e38d042013-01-01 03:20:28 +00001089qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001090{
amit salecha3666e0b2010-10-18 01:47:48 +00001091 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e38d042013-01-01 03:20:28 +00001092 int index, i, num_stats;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001093
1094 switch (stringset) {
1095 case ETH_SS_TEST:
1096 memcpy(data, *qlcnic_gstrings_test,
1097 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
1098 break;
1099 case ETH_SS_STATS:
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001100 num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings);
1101 for (i = 0; i < adapter->max_drv_tx_rings; i++) {
1102 for (index = 0; index < num_stats; index++) {
1103 sprintf(data, "tx_ring_%d %s", i,
1104 qlcnic_tx_ring_stats_strings[index]);
1105 data += ETH_GSTRING_LEN;
1106 }
1107 }
1108
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001109 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
1110 memcpy(data + index * ETH_GSTRING_LEN,
1111 qlcnic_gstrings_stats[index].stat_string,
1112 ETH_GSTRING_LEN);
1113 }
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001114
Sony Chacko7e38d042013-01-01 03:20:28 +00001115 if (qlcnic_83xx_check(adapter)) {
1116 num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
1117 for (i = 0; i < num_stats; i++, index++)
1118 memcpy(data + index * ETH_GSTRING_LEN,
1119 qlcnic_83xx_tx_stats_strings[i],
1120 ETH_GSTRING_LEN);
1121 num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
1122 for (i = 0; i < num_stats; i++, index++)
1123 memcpy(data + index * ETH_GSTRING_LEN,
1124 qlcnic_83xx_mac_stats_strings[i],
1125 ETH_GSTRING_LEN);
1126 num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
1127 for (i = 0; i < num_stats; i++, index++)
1128 memcpy(data + index * ETH_GSTRING_LEN,
1129 qlcnic_83xx_rx_stats_strings[i],
1130 ETH_GSTRING_LEN);
1131 return;
1132 } else {
1133 num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
1134 for (i = 0; i < num_stats; i++, index++)
1135 memcpy(data + index * ETH_GSTRING_LEN,
1136 qlcnic_83xx_mac_stats_strings[i],
1137 ETH_GSTRING_LEN);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001138 }
amit salecha3666e0b2010-10-18 01:47:48 +00001139 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
1140 return;
Sony Chacko7e38d042013-01-01 03:20:28 +00001141 num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
1142 for (i = 0; i < num_stats; index++, i++) {
amit salecha3666e0b2010-10-18 01:47:48 +00001143 memcpy(data + index * ETH_GSTRING_LEN,
1144 qlcnic_device_gstrings_stats[i],
1145 ETH_GSTRING_LEN);
1146 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001147 }
1148}
1149
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001150static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type)
amit salecha3666e0b2010-10-18 01:47:48 +00001151{
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001152 if (type == QLCNIC_MAC_STATS) {
1153 struct qlcnic_mac_statistics *mac_stats =
1154 (struct qlcnic_mac_statistics *)stats;
Sony Chacko7e38d042013-01-01 03:20:28 +00001155 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
1156 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
1157 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
1158 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
1159 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
1160 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
1161 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
1162 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
1163 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
1164 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
1165 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
1166 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
1167 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
1168 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
1169 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
1170 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
1171 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
1172 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
1173 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
1174 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
1175 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
1176 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
1177 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
1178 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
1179 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
1180 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
1181 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
1182 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
1183 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
1184 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
1185 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
1186 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
1187 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001188 } else if (type == QLCNIC_ESW_STATS) {
1189 struct __qlcnic_esw_statistics *esw_stats =
1190 (struct __qlcnic_esw_statistics *)stats;
Sony Chacko7e38d042013-01-01 03:20:28 +00001191 *data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
1192 *data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
1193 *data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
1194 *data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
1195 *data++ = QLCNIC_FILL_STATS(esw_stats->errors);
1196 *data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
1197 *data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001198 }
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001199 return data;
amit salecha3666e0b2010-10-18 01:47:48 +00001200}
1201
Sony Chacko7e38d042013-01-01 03:20:28 +00001202static void qlcnic_get_ethtool_stats(struct net_device *dev,
1203 struct ethtool_stats *stats, u64 *data)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001204{
1205 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001206 struct qlcnic_host_tx_ring *tx_ring;
amit salecha3666e0b2010-10-18 01:47:48 +00001207 struct qlcnic_esw_statistics port_stats;
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001208 struct qlcnic_mac_statistics mac_stats;
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001209 int index, ret, length, size, ring;
Sony Chacko7e38d042013-01-01 03:20:28 +00001210 char *p;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001211
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001212 memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64));
1213 for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) {
1214 if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1215 tx_ring = &adapter->tx_ring[ring];
1216 *data++ = tx_ring->xmit_on;
1217 *data++ = tx_ring->xmit_off;
1218 *data++ = tx_ring->xmit_called;
1219 *data++ = tx_ring->xmit_finished;
1220 }
1221 }
Sony Chacko7e38d042013-01-01 03:20:28 +00001222 memset(data, 0, stats->n_stats * sizeof(u64));
1223 length = QLCNIC_STATS_LEN;
1224 for (index = 0; index < length; index++) {
1225 p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset;
1226 size = qlcnic_gstrings_stats[index].sizeof_stat;
1227 *data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001228 }
amit salecha3666e0b2010-10-18 01:47:48 +00001229
Sony Chacko7e38d042013-01-01 03:20:28 +00001230 if (qlcnic_83xx_check(adapter)) {
1231 if (adapter->ahw->linkup)
1232 qlcnic_83xx_get_stats(adapter, data);
1233 return;
1234 } else {
1235 /* Retrieve MAC statistics from firmware */
1236 memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
1237 qlcnic_get_mac_stats(adapter, &mac_stats);
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001238 data = qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
Sony Chacko7e38d042013-01-01 03:20:28 +00001239 }
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001240
amit salecha3666e0b2010-10-18 01:47:48 +00001241 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
1242 return;
1243
1244 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001245 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001246 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
1247 if (ret)
1248 return;
1249
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001250 data = qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001251 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001252 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
1253 if (ret)
1254 return;
1255
Sony Chacko7e38d042013-01-01 03:20:28 +00001256 qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001257}
1258
stephen hemminger94469f72011-04-06 11:47:23 +00001259static int qlcnic_set_led(struct net_device *dev,
1260 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001261{
1262 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001263 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001264 int err = -EIO, active = 1;
1265
Sony Chacko7e38d042013-01-01 03:20:28 +00001266 if (qlcnic_83xx_check(adapter))
Himanshu Madhanid16951d2013-03-08 09:53:50 +00001267 return qlcnic_83xx_set_led(dev, state);
1268
Sony Chacko79788452012-12-04 03:33:53 +00001269 if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001270 netdev_warn(dev, "LED test not supported for non "
1271 "privilege function\n");
1272 return -EOPNOTSUPP;
1273 }
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001274
stephen hemminger94469f72011-04-06 11:47:23 +00001275 switch (state) {
1276 case ETHTOOL_ID_ACTIVE:
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001277 if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
1278 return -EBUSY;
1279
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001280 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1281 break;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001282
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001283 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1284 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1285 break;
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001286 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001287 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001288
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001289 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
1290 err = 0;
1291 break;
1292 }
stephen hemminger94469f72011-04-06 11:47:23 +00001293
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001294 dev_err(&adapter->pdev->dev,
1295 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +00001296 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001297
stephen hemminger94469f72011-04-06 11:47:23 +00001298 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001299 active = 0;
1300
1301 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1302 break;
1303
1304 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1305 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1306 break;
1307 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
1308 }
1309
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001310 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
1311 dev_err(&adapter->pdev->dev,
1312 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001313
stephen hemminger94469f72011-04-06 11:47:23 +00001314 break;
1315
1316 default:
1317 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001318 }
1319
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001320 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001321 qlcnic_diag_free_res(dev, max_sds_rings);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001322
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001323 if (!active || err)
1324 clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001325
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001326 return err;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001327}
1328
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001329static void
1330qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1331{
1332 struct qlcnic_adapter *adapter = netdev_priv(dev);
1333 u32 wol_cfg;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001334 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001335
Sony Chacko7e38d042013-01-01 03:20:28 +00001336 if (qlcnic_83xx_check(adapter))
1337 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001338 wol->supported = 0;
1339 wol->wolopts = 0;
1340
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001341 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
1342 if (err == -EIO)
1343 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001344 if (wol_cfg & (1UL << adapter->portnum))
1345 wol->supported |= WAKE_MAGIC;
1346
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001347 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001348 if (wol_cfg & (1UL << adapter->portnum))
1349 wol->wolopts |= WAKE_MAGIC;
1350}
1351
1352static int
1353qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1354{
1355 struct qlcnic_adapter *adapter = netdev_priv(dev);
1356 u32 wol_cfg;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001357 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001358
Sony Chacko7e38d042013-01-01 03:20:28 +00001359 if (qlcnic_83xx_check(adapter))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001360 return -EOPNOTSUPP;
Sony Chacko7e38d042013-01-01 03:20:28 +00001361 if (wol->wolopts & ~WAKE_MAGIC)
1362 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001363
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001364 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
1365 if (err == -EIO)
1366 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001367 if (!(wol_cfg & (1 << adapter->portnum)))
1368 return -EOPNOTSUPP;
1369
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001370 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
1371 if (err == -EIO)
1372 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001373 if (wol->wolopts & WAKE_MAGIC)
1374 wol_cfg |= 1UL << adapter->portnum;
1375 else
1376 wol_cfg &= ~(1UL << adapter->portnum);
1377
1378 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1379
1380 return 0;
1381}
1382
1383/*
1384 * Set the coalescing parameters. Currently only normal is supported.
1385 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1386 * firmware coalescing to default.
1387 */
1388static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1389 struct ethtool_coalesce *ethcoal)
1390{
1391 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001392 struct qlcnic_nic_intr_coalesce *coal;
1393 u32 rx_coalesce_usecs, rx_max_frames;
1394 u32 tx_coalesce_usecs, tx_max_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001395
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001396 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001397 return -EINVAL;
1398
1399 /*
1400 * Return Error if unsupported values or
1401 * unsupported parameters are set.
1402 */
1403 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1404 ethcoal->rx_max_coalesced_frames > 0xffff ||
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001405 ethcoal->tx_coalesce_usecs > 0xffff ||
1406 ethcoal->tx_max_coalesced_frames > 0xffff ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001407 ethcoal->rx_coalesce_usecs_irq ||
1408 ethcoal->rx_max_coalesced_frames_irq ||
1409 ethcoal->tx_coalesce_usecs_irq ||
1410 ethcoal->tx_max_coalesced_frames_irq ||
1411 ethcoal->stats_block_coalesce_usecs ||
1412 ethcoal->use_adaptive_rx_coalesce ||
1413 ethcoal->use_adaptive_tx_coalesce ||
1414 ethcoal->pkt_rate_low ||
1415 ethcoal->rx_coalesce_usecs_low ||
1416 ethcoal->rx_max_coalesced_frames_low ||
1417 ethcoal->tx_coalesce_usecs_low ||
1418 ethcoal->tx_max_coalesced_frames_low ||
1419 ethcoal->pkt_rate_high ||
1420 ethcoal->rx_coalesce_usecs_high ||
1421 ethcoal->rx_max_coalesced_frames_high ||
1422 ethcoal->tx_coalesce_usecs_high ||
1423 ethcoal->tx_max_coalesced_frames_high)
1424 return -EINVAL;
1425
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001426 coal = &adapter->ahw->coal;
1427
1428 if (qlcnic_83xx_check(adapter)) {
1429 if (!ethcoal->tx_coalesce_usecs ||
1430 !ethcoal->tx_max_coalesced_frames ||
1431 !ethcoal->rx_coalesce_usecs ||
1432 !ethcoal->rx_max_coalesced_frames) {
1433 coal->flag = QLCNIC_INTR_DEFAULT;
1434 coal->type = QLCNIC_INTR_COAL_TYPE_RX;
1435 coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
1436 coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
1437 coal->tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
1438 coal->tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
1439 } else {
1440 tx_coalesce_usecs = ethcoal->tx_coalesce_usecs;
1441 tx_max_frames = ethcoal->tx_max_coalesced_frames;
1442 rx_coalesce_usecs = ethcoal->rx_coalesce_usecs;
1443 rx_max_frames = ethcoal->rx_max_coalesced_frames;
1444 coal->flag = 0;
1445
1446 if ((coal->rx_time_us == rx_coalesce_usecs) &&
1447 (coal->rx_packets == rx_max_frames)) {
1448 coal->type = QLCNIC_INTR_COAL_TYPE_TX;
1449 coal->tx_time_us = tx_coalesce_usecs;
1450 coal->tx_packets = tx_max_frames;
1451 } else if ((coal->tx_time_us == tx_coalesce_usecs) &&
1452 (coal->tx_packets == tx_max_frames)) {
1453 coal->type = QLCNIC_INTR_COAL_TYPE_RX;
1454 coal->rx_time_us = rx_coalesce_usecs;
1455 coal->rx_packets = rx_max_frames;
1456 } else {
1457 coal->type = QLCNIC_INTR_COAL_TYPE_RX;
1458 coal->rx_time_us = rx_coalesce_usecs;
1459 coal->rx_packets = rx_max_frames;
1460 coal->tx_time_us = tx_coalesce_usecs;
1461 coal->tx_packets = tx_max_frames;
1462 }
1463 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001464 } else {
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001465 if (!ethcoal->rx_coalesce_usecs ||
1466 !ethcoal->rx_max_coalesced_frames) {
1467 coal->flag = QLCNIC_INTR_DEFAULT;
1468 coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
1469 coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
1470 } else {
1471 coal->flag = 0;
1472 coal->rx_time_us = ethcoal->rx_coalesce_usecs;
1473 coal->rx_packets = ethcoal->rx_max_coalesced_frames;
1474 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001475 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001476
1477 qlcnic_config_intr_coalesce(adapter);
1478
1479 return 0;
1480}
1481
1482static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1483 struct ethtool_coalesce *ethcoal)
1484{
1485 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1486
1487 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1488 return -EINVAL;
1489
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001490 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
1491 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001492 ethcoal->tx_coalesce_usecs = adapter->ahw->coal.tx_time_us;
1493 ethcoal->tx_max_coalesced_frames = adapter->ahw->coal.tx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001494
1495 return 0;
1496}
1497
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001498static u32 qlcnic_get_msglevel(struct net_device *netdev)
1499{
1500 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1501
Sony Chacko79788452012-12-04 03:33:53 +00001502 return adapter->ahw->msg_enable;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001503}
1504
1505static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1506{
1507 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1508
Sony Chacko79788452012-12-04 03:33:53 +00001509 adapter->ahw->msg_enable = msglvl;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001510}
1511
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001512static int
1513qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1514{
1515 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1516 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1517
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001518 if (!fw_dump->tmpl_hdr) {
1519 netdev_err(adapter->netdev, "FW Dump not supported\n");
1520 return -ENOTSUPP;
1521 }
1522
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001523 if (fw_dump->clr)
1524 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1525 else
1526 dump->len = 0;
Manish choprabcebe552012-05-15 01:13:39 +00001527
1528 if (!fw_dump->enable)
1529 dump->flag = ETH_FW_DUMP_DISABLE;
1530 else
1531 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1532
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001533 dump->version = adapter->fw_version;
1534 return 0;
1535}
1536
1537static int
1538qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1539 void *buffer)
1540{
1541 int i, copy_sz;
Shahed Shaikh63507592012-11-23 23:56:52 +00001542 u32 *hdr_ptr;
1543 __le32 *data;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001544 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1545 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1546
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001547 if (!fw_dump->tmpl_hdr) {
1548 netdev_err(netdev, "FW Dump not supported\n");
1549 return -ENOTSUPP;
1550 }
1551
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001552 if (!fw_dump->clr) {
1553 netdev_info(netdev, "Dump not available\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001554 return -EINVAL;
1555 }
1556 /* Copy template header first */
1557 copy_sz = fw_dump->tmpl_hdr->size;
1558 hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
Joe Perches43d620c2011-06-16 19:08:06 +00001559 data = buffer;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001560 for (i = 0; i < copy_sz/sizeof(u32); i++)
1561 *data++ = cpu_to_le32(*hdr_ptr++);
1562
1563 /* Copy captured dump data */
1564 memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1565 dump->len = copy_sz + fw_dump->size;
1566 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1567
1568 /* Free dump area once data has been captured */
1569 vfree(fw_dump->data);
1570 fw_dump->data = NULL;
1571 fw_dump->clr = 0;
Manish choprac47884e42012-02-03 13:45:44 +00001572 netdev_info(netdev, "extracted the FW dump Successfully\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001573 return 0;
1574}
1575
1576static int
1577qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1578{
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001579 int i;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001580 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1581 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001582 u32 state;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001583
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001584 switch (val->flag) {
1585 case QLCNIC_FORCE_FW_DUMP_KEY:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001586 if (!fw_dump->tmpl_hdr) {
1587 netdev_err(netdev, "FW dump not supported\n");
1588 return -ENOTSUPP;
1589 }
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001590 if (!fw_dump->enable) {
1591 netdev_info(netdev, "FW dump not enabled\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001592 return 0;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001593 }
1594 if (fw_dump->clr) {
Manish choprac47884e42012-02-03 13:45:44 +00001595 netdev_info(netdev,
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001596 "Previous dump not cleared, not forcing dump\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001597 return 0;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001598 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001599 netdev_info(netdev, "Forcing a FW dump\n");
Sony Chacko7e38d042013-01-01 03:20:28 +00001600 qlcnic_dev_request_reset(adapter, val->flag);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001601 break;
1602 case QLCNIC_DISABLE_FW_DUMP:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001603 if (fw_dump->enable && fw_dump->tmpl_hdr) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001604 netdev_info(netdev, "Disabling FW dump\n");
1605 fw_dump->enable = 0;
1606 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001607 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001608 case QLCNIC_ENABLE_FW_DUMP:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001609 if (!fw_dump->tmpl_hdr) {
1610 netdev_err(netdev, "FW dump not supported\n");
1611 return -ENOTSUPP;
1612 }
1613 if (!fw_dump->enable) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001614 netdev_info(netdev, "Enabling FW dump\n");
1615 fw_dump->enable = 1;
1616 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001617 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001618 case QLCNIC_FORCE_FW_RESET:
1619 netdev_info(netdev, "Forcing a FW reset\n");
Sony Chacko7e38d042013-01-01 03:20:28 +00001620 qlcnic_dev_request_reset(adapter, val->flag);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001621 adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001622 return 0;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001623 case QLCNIC_SET_QUIESCENT:
1624 case QLCNIC_RESET_QUIESCENT:
Shahed Shaikh2deb5352013-07-19 16:56:26 -04001625 state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001626 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
1627 netdev_info(netdev, "Device in FAILED state\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001628 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001629 default:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001630 if (!fw_dump->tmpl_hdr) {
1631 netdev_err(netdev, "FW dump not supported\n");
1632 return -ENOTSUPP;
1633 }
Sony Chacko7e38d042013-01-01 03:20:28 +00001634 for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
1635 if (val->flag == qlcnic_fw_dump_level[i]) {
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001636 fw_dump->tmpl_hdr->drv_cap_mask =
1637 val->flag;
1638 netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1639 fw_dump->tmpl_hdr->drv_cap_mask);
1640 return 0;
1641 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001642 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001643 netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag);
1644 return -EINVAL;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001645 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001646 return 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001647}
1648
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001649const struct ethtool_ops qlcnic_ethtool_ops = {
1650 .get_settings = qlcnic_get_settings,
1651 .set_settings = qlcnic_set_settings,
1652 .get_drvinfo = qlcnic_get_drvinfo,
1653 .get_regs_len = qlcnic_get_regs_len,
1654 .get_regs = qlcnic_get_regs,
1655 .get_link = ethtool_op_get_link,
1656 .get_eeprom_len = qlcnic_get_eeprom_len,
1657 .get_eeprom = qlcnic_get_eeprom,
1658 .get_ringparam = qlcnic_get_ringparam,
1659 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +00001660 .get_channels = qlcnic_get_channels,
1661 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001662 .get_pauseparam = qlcnic_get_pauseparam,
1663 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001664 .get_wol = qlcnic_get_wol,
1665 .set_wol = qlcnic_set_wol,
1666 .self_test = qlcnic_diag_test,
1667 .get_strings = qlcnic_get_strings,
1668 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1669 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001670 .get_coalesce = qlcnic_get_intr_coalesce,
1671 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +00001672 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001673 .set_msglevel = qlcnic_set_msglevel,
1674 .get_msglevel = qlcnic_get_msglevel,
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001675 .get_dump_flag = qlcnic_get_dump_flag,
1676 .get_dump_data = qlcnic_get_dump_data,
1677 .set_dump = qlcnic_set_dump,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001678};
Rajesh Borundiad1a11052013-04-19 07:01:13 +00001679
1680const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = {
1681 .get_settings = qlcnic_get_settings,
1682 .get_drvinfo = qlcnic_get_drvinfo,
1683 .get_regs_len = qlcnic_get_regs_len,
1684 .get_regs = qlcnic_get_regs,
1685 .get_link = ethtool_op_get_link,
1686 .get_eeprom_len = qlcnic_get_eeprom_len,
1687 .get_eeprom = qlcnic_get_eeprom,
1688 .get_ringparam = qlcnic_get_ringparam,
1689 .set_ringparam = qlcnic_set_ringparam,
1690 .get_channels = qlcnic_get_channels,
1691 .get_pauseparam = qlcnic_get_pauseparam,
1692 .get_wol = qlcnic_get_wol,
1693 .get_strings = qlcnic_get_strings,
1694 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1695 .get_sset_count = qlcnic_get_sset_count,
1696 .get_coalesce = qlcnic_get_intr_coalesce,
1697 .set_coalesce = qlcnic_set_intr_coalesce,
1698 .set_msglevel = qlcnic_set_msglevel,
1699 .get_msglevel = qlcnic_get_msglevel,
1700};