blob: 0aaa52b3bcedb20e8cd93be630d3ea1fd66014cb [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
Pratik Pujar710a1a42013-10-18 12:22:29 -0400190#define QLCNIC_TX_INTR_NOT_CONFIGURED 0X78563412
191
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000192#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
Pratik Pujar710a1a42013-10-18 12:22:29 -0400222#define QLCNIC_ETHTOOL_REGS_VER 4
223
224static inline int qlcnic_get_ring_regs_len(struct qlcnic_adapter *adapter)
225{
226 int ring_regs_cnt = (adapter->max_drv_tx_rings * 5) +
227 (adapter->max_rds_rings * 2) +
228 (adapter->max_sds_rings * 3) + 5;
229 return ring_regs_cnt * sizeof(u32);
230}
Sony Chacko7e38d042013-01-01 03:20:28 +0000231
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000232static int qlcnic_get_regs_len(struct net_device *dev)
233{
Sony Chacko7e38d042013-01-01 03:20:28 +0000234 struct qlcnic_adapter *adapter = netdev_priv(dev);
235 u32 len;
236
237 if (qlcnic_83xx_check(adapter))
238 len = qlcnic_83xx_get_regs_len(adapter);
239 else
240 len = sizeof(ext_diag_registers) + sizeof(diag_registers);
241
Pratik Pujar710a1a42013-10-18 12:22:29 -0400242 len += ((QLCNIC_DEV_INFO_SIZE + 2) * sizeof(u32));
243 len += qlcnic_get_ring_regs_len(adapter);
244 return len;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000245}
246
247static int qlcnic_get_eeprom_len(struct net_device *dev)
248{
249 return QLCNIC_FLASH_TOTAL_SIZE;
250}
251
252static void
253qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
254{
255 struct qlcnic_adapter *adapter = netdev_priv(dev);
256 u32 fw_major, fw_minor, fw_build;
Sony Chacko7e38d042013-01-01 03:20:28 +0000257 fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
258 fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
259 fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
Rick Jones68aad782011-11-07 13:29:27 +0000260 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
261 "%d.%d.%d", fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000262
Rick Jones68aad782011-11-07 13:29:27 +0000263 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
264 sizeof(drvinfo->bus_info));
265 strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
266 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
267 sizeof(drvinfo->version));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000268}
269
270static int
271qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
272{
273 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhanib9386622013-05-09 09:25:12 +0000274
275 if (qlcnic_82xx_check(adapter))
276 return qlcnic_82xx_get_settings(adapter, ecmd);
277 else if (qlcnic_83xx_check(adapter))
278 return qlcnic_83xx_get_settings(adapter, ecmd);
279
280 return -EIO;
281}
282
283int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
284 struct ethtool_cmd *ecmd)
285{
Sony Chacko7e38d042013-01-01 03:20:28 +0000286 struct qlcnic_hardware_context *ahw = adapter->ahw;
287 u32 speed, reg;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400288 int check_sfp_module = 0, err = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000289 u16 pcifn = ahw->pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000290
291 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000292 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000293 ecmd->supported = (SUPPORTED_10baseT_Half |
294 SUPPORTED_10baseT_Full |
295 SUPPORTED_100baseT_Half |
296 SUPPORTED_100baseT_Full |
297 SUPPORTED_1000baseT_Half |
298 SUPPORTED_1000baseT_Full);
299
300 ecmd->advertising = (ADVERTISED_100baseT_Half |
301 ADVERTISED_100baseT_Full |
302 ADVERTISED_1000baseT_Half |
303 ADVERTISED_1000baseT_Full);
304
Sony Chacko79788452012-12-04 03:33:53 +0000305 ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
306 ecmd->duplex = adapter->ahw->link_duplex;
307 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000308
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000309 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Sony Chacko7e38d042013-01-01 03:20:28 +0000310 u32 val = 0;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400311 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000312
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000313 if (val == QLCNIC_PORT_MODE_802_3_AP) {
314 ecmd->supported = SUPPORTED_1000baseT_Full;
315 ecmd->advertising = ADVERTISED_1000baseT_Full;
316 } else {
317 ecmd->supported = SUPPORTED_10000baseT_Full;
318 ecmd->advertising = ADVERTISED_10000baseT_Full;
319 }
320
Himanshu Madhanib9386622013-05-09 09:25:12 +0000321 if (netif_running(adapter->netdev) && ahw->has_link_events) {
Rajesh Borundiabeb3d3a2013-08-02 23:15:59 -0400322 if (ahw->linkup) {
323 reg = QLCRD32(adapter,
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400324 P3P_LINK_SPEED_REG(pcifn), &err);
Rajesh Borundiabeb3d3a2013-08-02 23:15:59 -0400325 speed = P3P_LINK_SPEED_VAL(pcifn, reg);
326 ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
327 }
328
Himanshu Madhanib9386622013-05-09 09:25:12 +0000329 ethtool_cmd_speed_set(ecmd, ahw->link_speed);
330 ecmd->autoneg = ahw->link_autoneg;
331 ecmd->duplex = ahw->link_duplex;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000332 goto skip;
333 }
334
Sony Chacko476a4b62012-02-03 13:45:42 +0000335 ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
336 ecmd->duplex = DUPLEX_UNKNOWN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000337 ecmd->autoneg = AUTONEG_DISABLE;
338 } else
339 return -EIO;
340
341skip:
Sony Chacko79788452012-12-04 03:33:53 +0000342 ecmd->phy_address = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000343 ecmd->transceiver = XCVR_EXTERNAL;
344
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000345 switch (adapter->ahw->board_type) {
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000346 case QLCNIC_BRDTYPE_P3P_REF_QG:
347 case QLCNIC_BRDTYPE_P3P_4_GB:
348 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000349
350 ecmd->supported |= SUPPORTED_Autoneg;
351 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000352 case QLCNIC_BRDTYPE_P3P_10G_CX4:
353 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
354 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000355 ecmd->supported |= SUPPORTED_TP;
356 ecmd->advertising |= ADVERTISED_TP;
357 ecmd->port = PORT_TP;
Sony Chacko79788452012-12-04 03:33:53 +0000358 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000359 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000360 case QLCNIC_BRDTYPE_P3P_IMEZ:
361 case QLCNIC_BRDTYPE_P3P_XG_LOM:
362 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000363 ecmd->supported |= SUPPORTED_MII;
364 ecmd->advertising |= ADVERTISED_MII;
365 ecmd->port = PORT_MII;
366 ecmd->autoneg = AUTONEG_DISABLE;
367 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000368 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
369 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
370 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000371 ecmd->advertising |= ADVERTISED_TP;
372 ecmd->supported |= SUPPORTED_TP;
Himanshu Madhanib9386622013-05-09 09:25:12 +0000373 check_sfp_module = netif_running(adapter->netdev) &&
374 ahw->has_link_events;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000375 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000376 ecmd->supported |= SUPPORTED_FIBRE;
377 ecmd->advertising |= ADVERTISED_FIBRE;
378 ecmd->port = PORT_FIBRE;
379 ecmd->autoneg = AUTONEG_DISABLE;
380 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000381 case QLCNIC_BRDTYPE_P3P_10G_TP:
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000382 if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000383 ecmd->autoneg = AUTONEG_DISABLE;
384 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
385 ecmd->advertising |=
386 (ADVERTISED_FIBRE | ADVERTISED_TP);
387 ecmd->port = PORT_FIBRE;
Himanshu Madhanib9386622013-05-09 09:25:12 +0000388 check_sfp_module = netif_running(adapter->netdev) &&
389 ahw->has_link_events;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000390 } else {
391 ecmd->autoneg = AUTONEG_ENABLE;
392 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
393 ecmd->advertising |=
394 (ADVERTISED_TP | ADVERTISED_Autoneg);
395 ecmd->port = PORT_TP;
396 }
397 break;
398 default:
399 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000400 adapter->ahw->board_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000401 return -EIO;
402 }
403
404 if (check_sfp_module) {
Sony Chacko79788452012-12-04 03:33:53 +0000405 switch (adapter->ahw->module_type) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000406 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
407 case LINKEVENT_MODULE_OPTICAL_SRLR:
408 case LINKEVENT_MODULE_OPTICAL_LRM:
409 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
410 ecmd->port = PORT_FIBRE;
411 break;
412 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
413 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
414 case LINKEVENT_MODULE_TWINAX:
415 ecmd->port = PORT_TP;
416 break;
417 default:
418 ecmd->port = PORT_OTHER;
419 }
420 }
421
422 return 0;
423}
424
Sony Chacko7e38d042013-01-01 03:20:28 +0000425static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,
426 struct ethtool_cmd *ecmd)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000427{
Sony Chacko7e38d042013-01-01 03:20:28 +0000428 u32 ret = 0, config = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000429 /* read which mode */
Sony Chacko7e610ca2011-04-28 11:48:19 +0000430 if (ecmd->duplex)
431 config |= 0x1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000432
Sony Chacko7e610ca2011-04-28 11:48:19 +0000433 if (ecmd->autoneg)
434 config |= 0x2;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000435
Sony Chacko7e610ca2011-04-28 11:48:19 +0000436 switch (ethtool_cmd_speed(ecmd)) {
437 case SPEED_10:
438 config |= (0 << 8);
439 break;
440 case SPEED_100:
441 config |= (1 << 8);
442 break;
443 case SPEED_1000:
444 config |= (10 << 8);
445 break;
446 default:
447 return -EIO;
448 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000449
Sony Chacko7e610ca2011-04-28 11:48:19 +0000450 ret = qlcnic_fw_cmd_set_port(adapter, config);
451
452 if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000453 return -EOPNOTSUPP;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000454 else if (ret)
455 return -EIO;
Sony Chacko7e38d042013-01-01 03:20:28 +0000456 return ret;
457}
458
459static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
460{
461 u32 ret = 0;
462 struct qlcnic_adapter *adapter = netdev_priv(dev);
463
464 if (adapter->ahw->port_type != QLCNIC_GBE)
465 return -EOPNOTSUPP;
466
467 if (qlcnic_83xx_check(adapter))
468 ret = qlcnic_83xx_set_settings(adapter, ecmd);
469 else
470 ret = qlcnic_set_port_config(adapter, ecmd);
471
472 if (!ret)
473 return ret;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000474
Sony Chacko79788452012-12-04 03:33:53 +0000475 adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
476 adapter->ahw->link_duplex = ecmd->duplex;
477 adapter->ahw->link_autoneg = ecmd->autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000478
479 if (!netif_running(dev))
480 return 0;
481
482 dev->netdev_ops->ndo_stop(dev);
483 return dev->netdev_ops->ndo_open(dev);
484}
485
Sony Chacko7e38d042013-01-01 03:20:28 +0000486static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
487 u32 *regs_buff)
488{
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400489 int i, j = 0, err = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000490
491 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
492 regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
493 j = 0;
494 while (ext_diag_registers[j] != -1)
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400495 regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++],
496 &err);
Sony Chacko7e38d042013-01-01 03:20:28 +0000497 return i;
498}
499
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000500static void
501qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
502{
503 struct qlcnic_adapter *adapter = netdev_priv(dev);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000504 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000505 struct qlcnic_host_sds_ring *sds_ring;
Pratik Pujar710a1a42013-10-18 12:22:29 -0400506 struct qlcnic_host_rds_ring *rds_rings;
507 struct qlcnic_host_tx_ring *tx_ring;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000508 u32 *regs_buff = p;
Sony Chacko7e38d042013-01-01 03:20:28 +0000509 int ring, i = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000510
511 memset(p, 0, qlcnic_get_regs_len(dev));
Sony Chacko7e38d042013-01-01 03:20:28 +0000512
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000513 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000514 (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000515
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000516 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
517 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
518
Sony Chacko7e38d042013-01-01 03:20:28 +0000519 if (qlcnic_82xx_check(adapter))
520 i = qlcnic_82xx_get_registers(adapter, regs_buff);
521 else
522 i = qlcnic_83xx_get_registers(adapter, regs_buff);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000523
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000524 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000525 return;
526
Pratik Pujar710a1a42013-10-18 12:22:29 -0400527 /* Marker btw regs and TX ring count */
528 regs_buff[i++] = 0xFFEFCDAB;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000529
Pratik Pujar710a1a42013-10-18 12:22:29 -0400530 regs_buff[i++] = adapter->max_drv_tx_rings; /* No. of TX ring */
531 for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
532 tx_ring = &adapter->tx_ring[ring];
533 regs_buff[i++] = le32_to_cpu(*(tx_ring->hw_consumer));
534 regs_buff[i++] = tx_ring->sw_consumer;
535 regs_buff[i++] = readl(tx_ring->crb_cmd_producer);
536 regs_buff[i++] = tx_ring->producer;
537 if (tx_ring->crb_intr_mask)
538 regs_buff[i++] = readl(tx_ring->crb_intr_mask);
539 else
540 regs_buff[i++] = QLCNIC_TX_INTR_NOT_CONFIGURED;
541 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000542
Pratik Pujar710a1a42013-10-18 12:22:29 -0400543 regs_buff[i++] = adapter->max_rds_rings; /* No. of RX ring */
544 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
545 rds_rings = &recv_ctx->rds_rings[ring];
546 regs_buff[i++] = readl(rds_rings->crb_rcv_producer);
547 regs_buff[i++] = rds_rings->producer;
548 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000549
Pratik Pujar710a1a42013-10-18 12:22:29 -0400550 regs_buff[i++] = adapter->max_sds_rings; /* No. of SDS ring */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000551 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
552 sds_ring = &(recv_ctx->sds_rings[ring]);
553 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
Pratik Pujar710a1a42013-10-18 12:22:29 -0400554 regs_buff[i++] = sds_ring->consumer;
555 regs_buff[i++] = readl(sds_ring->crb_intr_mask);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000556 }
557}
558
559static u32 qlcnic_test_link(struct net_device *dev)
560{
561 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400562 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000563 u32 val;
564
Sony Chacko7e38d042013-01-01 03:20:28 +0000565 if (qlcnic_83xx_check(adapter)) {
566 val = qlcnic_83xx_test_link(adapter);
567 return (val & 1) ? 0 : 1;
568 }
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400569 val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err);
570 if (err == -EIO)
571 return err;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000572 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000573 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000574}
575
576static int
577qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
578 u8 *bytes)
579{
580 struct qlcnic_adapter *adapter = netdev_priv(dev);
581 int offset;
Sony Chacko7e38d042013-01-01 03:20:28 +0000582 int ret = -1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000583
Sony Chacko7e38d042013-01-01 03:20:28 +0000584 if (qlcnic_83xx_check(adapter))
585 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000586 if (eeprom->len == 0)
587 return -EINVAL;
588
589 eeprom->magic = (adapter->pdev)->vendor |
590 ((adapter->pdev)->device << 16);
591 offset = eeprom->offset;
592
Sony Chacko7e38d042013-01-01 03:20:28 +0000593 if (qlcnic_82xx_check(adapter))
594 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
595 eeprom->len);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000596 if (ret < 0)
597 return ret;
598
599 return 0;
600}
601
602static void
603qlcnic_get_ringparam(struct net_device *dev,
604 struct ethtool_ringparam *ring)
605{
606 struct qlcnic_adapter *adapter = netdev_priv(dev);
607
608 ring->rx_pending = adapter->num_rxd;
609 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000610 ring->tx_pending = adapter->num_txd;
611
Sony Chacko90d19002010-10-26 17:53:08 +0000612 ring->rx_max_pending = adapter->max_rxd;
613 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000614 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000615}
616
617static u32
618qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
619{
620 u32 num_desc;
621 num_desc = max(val, min);
622 num_desc = min(num_desc, max);
623 num_desc = roundup_pow_of_two(num_desc);
624
625 if (val != num_desc) {
626 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
627 qlcnic_driver_name, r_name, num_desc, val);
628 }
629
630 return num_desc;
631}
632
633static int
634qlcnic_set_ringparam(struct net_device *dev,
635 struct ethtool_ringparam *ring)
636{
637 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000638 u16 num_rxd, num_jumbo_rxd, num_txd;
639
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000640 if (ring->rx_mini_pending)
641 return -EOPNOTSUPP;
642
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000643 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000644 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000645
646 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000647 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
648 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000649
650 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
651 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
652
653 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
654 num_jumbo_rxd == adapter->num_jumbo_rxd)
655 return 0;
656
657 adapter->num_rxd = num_rxd;
658 adapter->num_jumbo_rxd = num_jumbo_rxd;
659 adapter->num_txd = num_txd;
660
661 return qlcnic_reset_context(adapter);
662}
663
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000664static void qlcnic_get_channels(struct net_device *dev,
665 struct ethtool_channels *channel)
666{
667 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400668 int min;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000669
Sony Chacko79788452012-12-04 03:33:53 +0000670 min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus());
671 channel->max_rx = rounddown_pow_of_two(min);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400672 channel->max_tx = min_t(int, QLCNIC_MAX_TX_RINGS, num_online_cpus());
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000673
674 channel->rx_count = adapter->max_sds_rings;
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400675 channel->tx_count = adapter->max_drv_tx_rings;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000676}
677
678static int qlcnic_set_channels(struct net_device *dev,
679 struct ethtool_channels *channel)
680{
681 struct qlcnic_adapter *adapter = netdev_priv(dev);
682 int err;
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400683 int txq = 0;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000684
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400685 if (channel->other_count || channel->combined_count)
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000686 return -EINVAL;
687
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400688 if (channel->rx_count) {
689 err = qlcnic_validate_max_rss(adapter, channel->rx_count);
690 if (err)
691 return err;
692 }
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000693
Himanshu Madhani66c562e2013-10-17 18:26:38 -0400694 if (qlcnic_82xx_check(adapter) && channel->tx_count) {
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400695 err = qlcnic_validate_max_tx_rings(adapter, channel->tx_count);
696 if (err)
697 return err;
698 txq = channel->tx_count;
699 }
700
701 err = qlcnic_set_max_rss(adapter, channel->rx_count, txq);
702 netdev_info(dev, "allocated 0x%x sds rings and 0x%x tx rings\n",
703 adapter->max_sds_rings, adapter->max_drv_tx_rings);
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000704 return err;
705}
706
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000707static void
708qlcnic_get_pauseparam(struct net_device *netdev,
709 struct ethtool_pauseparam *pause)
710{
711 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000712 int port = adapter->ahw->physical_port;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400713 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000714 __u32 val;
715
Sony Chacko7e38d042013-01-01 03:20:28 +0000716 if (qlcnic_83xx_check(adapter)) {
717 qlcnic_83xx_get_pauseparam(adapter, pause);
718 return;
719 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000720 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000721 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
722 return;
723 /* get flow control settings */
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400724 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
725 if (err == -EIO)
726 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000727 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400728 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
729 if (err == -EIO)
730 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000731 switch (port) {
732 case 0:
733 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
734 break;
735 case 1:
736 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
737 break;
738 case 2:
739 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
740 break;
741 case 3:
742 default:
743 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
744 break;
745 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000746 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000747 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
748 return;
749 pause->rx_pause = 1;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400750 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
751 if (err == -EIO)
752 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000753 if (port == 0)
754 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
755 else
756 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
757 } else {
758 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000759 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000760 }
761}
762
763static int
764qlcnic_set_pauseparam(struct net_device *netdev,
765 struct ethtool_pauseparam *pause)
766{
767 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000768 int port = adapter->ahw->physical_port;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400769 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000770 __u32 val;
771
Sony Chacko7e38d042013-01-01 03:20:28 +0000772 if (qlcnic_83xx_check(adapter))
773 return qlcnic_83xx_set_pauseparam(adapter, pause);
774
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000775 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000776 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000777 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
778 return -EIO;
779 /* set flow control */
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400780 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
781 if (err == -EIO)
782 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000783
784 if (pause->rx_pause)
785 qlcnic_gb_rx_flowctl(val);
786 else
787 qlcnic_gb_unset_rx_flowctl(val);
788
789 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
790 val);
Sony Chacko7e38d042013-01-01 03:20:28 +0000791 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000792 /* set autoneg */
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400793 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
794 if (err == -EIO)
795 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000796 switch (port) {
797 case 0:
798 if (pause->tx_pause)
799 qlcnic_gb_unset_gb0_mask(val);
800 else
801 qlcnic_gb_set_gb0_mask(val);
802 break;
803 case 1:
804 if (pause->tx_pause)
805 qlcnic_gb_unset_gb1_mask(val);
806 else
807 qlcnic_gb_set_gb1_mask(val);
808 break;
809 case 2:
810 if (pause->tx_pause)
811 qlcnic_gb_unset_gb2_mask(val);
812 else
813 qlcnic_gb_set_gb2_mask(val);
814 break;
815 case 3:
816 default:
817 if (pause->tx_pause)
818 qlcnic_gb_unset_gb3_mask(val);
819 else
820 qlcnic_gb_set_gb3_mask(val);
821 break;
822 }
823 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000824 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000825 if (!pause->rx_pause || pause->autoneg)
826 return -EOPNOTSUPP;
827
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000828 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
829 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000830
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400831 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
832 if (err == -EIO)
833 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000834 if (port == 0) {
835 if (pause->tx_pause)
836 qlcnic_xg_unset_xg0_mask(val);
837 else
838 qlcnic_xg_set_xg0_mask(val);
839 } else {
840 if (pause->tx_pause)
841 qlcnic_xg_unset_xg1_mask(val);
842 else
843 qlcnic_xg_set_xg1_mask(val);
844 }
845 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
846 } else {
847 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000848 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000849 }
850 return 0;
851}
852
853static int qlcnic_reg_test(struct net_device *dev)
854{
855 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000856 u32 data_read;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400857 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000858
Sony Chacko7e38d042013-01-01 03:20:28 +0000859 if (qlcnic_83xx_check(adapter))
860 return qlcnic_83xx_reg_test(adapter);
861
Himanshu Madhani4bd8e732013-08-02 23:16:01 -0400862 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err);
863 if (err == -EIO)
864 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000865 if ((data_read & 0xffff) != adapter->pdev->vendor)
866 return 1;
867
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000868 return 0;
869}
870
Sony Chacko7e38d042013-01-01 03:20:28 +0000871static int qlcnic_eeprom_test(struct net_device *dev)
872{
873 struct qlcnic_adapter *adapter = netdev_priv(dev);
874
875 if (qlcnic_82xx_check(adapter))
876 return 0;
877
878 return qlcnic_83xx_flash_test(adapter);
879}
880
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000881static int qlcnic_get_sset_count(struct net_device *dev, int sset)
882{
Sony Chacko7e38d042013-01-01 03:20:28 +0000883 int len;
884
amit salecha3666e0b2010-10-18 01:47:48 +0000885 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000886 switch (sset) {
887 case ETH_SS_TEST:
888 return QLCNIC_TEST_LEN;
889 case ETH_SS_STATS:
Sony Chacko7e38d042013-01-01 03:20:28 +0000890 len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
891 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
892 qlcnic_83xx_check(adapter))
893 return len;
894 return qlcnic_82xx_statistics();
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000895 default:
896 return -EOPNOTSUPP;
897 }
898}
899
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000900static int qlcnic_irq_test(struct net_device *netdev)
901{
902 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000903 struct qlcnic_hardware_context *ahw = adapter->ahw;
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000904 struct qlcnic_cmd_args cmd;
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000905 int ret, max_sds_rings = adapter->max_sds_rings;
906
907 if (qlcnic_83xx_check(adapter))
908 return qlcnic_83xx_interrupt_test(netdev);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000909
910 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
911 return -EIO;
912
913 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
914 if (ret)
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000915 goto clear_diag_irq;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000916
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000917 ahw->diag_cnt = 0;
Shahed Shaikhb6b43162013-06-22 04:12:00 -0400918 ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
919 if (ret)
920 goto free_diag_res;
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000921
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000922 cmd.req.arg[1] = ahw->pci_func;
923 ret = qlcnic_issue_cmd(adapter, &cmd);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000924 if (ret)
925 goto done;
926
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000927 usleep_range(1000, 12000);
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000928 ret = !ahw->diag_cnt;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000929
930done:
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000931 qlcnic_free_mbx_args(&cmd);
Shahed Shaikhb6b43162013-06-22 04:12:00 -0400932
933free_diag_res:
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000934 qlcnic_diag_free_res(netdev, max_sds_rings);
935
Jitendra Kalsaria58ead412013-02-09 09:29:52 +0000936clear_diag_irq:
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000937 adapter->max_sds_rings = max_sds_rings;
938 clear_bit(__QLCNIC_RESETTING, &adapter->state);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -0400939
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000940 return ret;
941}
942
Rajesh Borundiad1a11052013-04-19 07:01:13 +0000943#define QLCNIC_ILB_PKT_SIZE 64
944#define QLCNIC_NUM_ILB_PKT 16
945#define QLCNIC_ILB_MAX_RCV_LOOP 10
946#define QLCNIC_LB_PKT_POLL_DELAY_MSEC 1
947#define QLCNIC_LB_PKT_POLL_COUNT 20
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000948
949static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
950{
951 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
952
953 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
954
955 memcpy(data, mac, ETH_ALEN);
956 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
957
958 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
959}
960
961int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
962{
963 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
964 qlcnic_create_loopback_buff(buff, mac);
965 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
966}
967
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000968int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000969{
970 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
971 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
972 struct sk_buff *skb;
973 int i, loop, cnt = 0;
974
975 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
Pradeep A. Dalvidae2e9f2012-02-06 11:16:13 +0000976 skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000977 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
978 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
Sony Chacko79788452012-12-04 03:33:53 +0000979 adapter->ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000980 qlcnic_xmit_frame(skb, adapter->netdev);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000981 loop = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000982
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000983 do {
Rajesh Borundiad1a11052013-04-19 07:01:13 +0000984 msleep(QLCNIC_LB_PKT_POLL_DELAY_MSEC);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000985 qlcnic_process_rcv_ring_diag(sds_ring);
Rajesh Borundiad1a11052013-04-19 07:01:13 +0000986 if (loop++ > QLCNIC_LB_PKT_POLL_COUNT)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000987 break;
Sony Chacko79788452012-12-04 03:33:53 +0000988 } while (!adapter->ahw->diag_cnt);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000989
990 dev_kfree_skb_any(skb);
991
Sony Chacko79788452012-12-04 03:33:53 +0000992 if (!adapter->ahw->diag_cnt)
Sony Chacko7e38d042013-01-01 03:20:28 +0000993 dev_warn(&adapter->pdev->dev,
994 "LB Test: packet #%d was not received\n",
995 i + 1);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000996 else
997 cnt++;
998 }
999 if (cnt != i) {
Sony Chacko7e38d042013-01-01 03:20:28 +00001000 dev_err(&adapter->pdev->dev,
1001 "LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
1002 if (mode != QLCNIC_ILB_MODE)
Manish chopradf3cfbe2011-08-29 12:50:27 +00001003 dev_warn(&adapter->pdev->dev,
Sony Chacko7e38d042013-01-01 03:20:28 +00001004 "WARNING: Please check loopback cable\n");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001005 return -1;
1006 }
1007 return 0;
1008}
1009
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001010int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001011{
1012 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Himanshu Madhanic2c5e3a2013-08-21 11:24:12 -04001013 int max_drv_tx_rings = adapter->max_drv_tx_rings;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001014 int max_sds_rings = adapter->max_sds_rings;
1015 struct qlcnic_host_sds_ring *sds_ring;
Sony Chacko7e38d042013-01-01 03:20:28 +00001016 struct qlcnic_hardware_context *ahw = adapter->ahw;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001017 int loop = 0;
1018 int ret;
1019
Sony Chacko7e38d042013-01-01 03:20:28 +00001020 if (qlcnic_83xx_check(adapter))
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001021 return qlcnic_83xx_loopback_test(netdev, mode);
1022
Sony Chacko7e38d042013-01-01 03:20:28 +00001023 if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
1024 dev_info(&adapter->pdev->dev,
1025 "Firmware do not support loopback test\n");
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001026 return -EOPNOTSUPP;
1027 }
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001028
Sony Chacko7e38d042013-01-01 03:20:28 +00001029 dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
1030 mode == QLCNIC_ILB_MODE ? "internal" : "external");
1031 if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
1032 dev_warn(&adapter->pdev->dev,
1033 "Loopback test not supported in nonprivileged mode\n");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001034 return 0;
1035 }
1036
1037 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001038 return -EBUSY;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001039
1040 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
1041 if (ret)
1042 goto clear_it;
1043
1044 sds_ring = &adapter->recv_ctx->sds_rings[0];
Amit Kumar Salechae1428d22011-06-29 20:00:50 +00001045 ret = qlcnic_set_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001046 if (ret)
1047 goto free_res;
1048
Sony Chacko7e38d042013-01-01 03:20:28 +00001049 ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001050 do {
1051 msleep(500);
1052 qlcnic_process_rcv_ring_diag(sds_ring);
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001053 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
Jitendra Kalsariab9c11982013-08-02 00:57:39 -04001054 netdev_info(netdev,
1055 "Firmware didn't sent link up event to loopback request\n");
1056 ret = -ETIMEDOUT;
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001057 goto free_res;
Sony Chacko79788452012-12-04 03:33:53 +00001058 } else if (adapter->ahw->diag_cnt) {
1059 ret = adapter->ahw->diag_cnt;
Amit Kumar Salechafef0c062011-07-14 03:16:54 +00001060 goto free_res;
1061 }
Sony Chacko7e38d042013-01-01 03:20:28 +00001062 } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001063
Manish chopradf3cfbe2011-08-29 12:50:27 +00001064 ret = qlcnic_do_lb_test(adapter, mode);
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +00001065
Sony Chacko7e2cf4f2013-01-01 03:20:17 +00001066 qlcnic_clear_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001067
1068 free_res:
1069 qlcnic_diag_free_res(netdev, max_sds_rings);
1070
1071 clear_it:
1072 adapter->max_sds_rings = max_sds_rings;
Himanshu Madhanic2c5e3a2013-08-21 11:24:12 -04001073 adapter->max_drv_tx_rings = max_drv_tx_rings;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001074 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1075 return ret;
1076}
1077
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001078static void
1079qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
1080 u64 *data)
1081{
1082 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001083
Sony Chacko8dec32cc2010-08-17 00:34:24 +00001084 data[0] = qlcnic_reg_test(dev);
1085 if (data[0])
1086 eth_test->flags |= ETH_TEST_FL_FAILED;
1087
1088 data[1] = (u64) qlcnic_test_link(dev);
1089 if (data[1])
1090 eth_test->flags |= ETH_TEST_FL_FAILED;
1091
Sony Chacko13b93ed2011-01-10 00:15:22 +00001092 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001093 data[2] = qlcnic_irq_test(dev);
1094 if (data[2])
1095 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001096
Amit Kumar Salechae1428d22011-06-29 20:00:50 +00001097 data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001098 if (data[3])
1099 eth_test->flags |= ETH_TEST_FL_FAILED;
Sony Chacko7e38d042013-01-01 03:20:28 +00001100
Shahed Shaikh2e3ea7e2013-08-02 23:15:58 -04001101 if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
1102 data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
1103 if (data[4])
1104 eth_test->flags |= ETH_TEST_FL_FAILED;
1105 eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
1106 }
1107
1108 data[5] = qlcnic_eeprom_test(dev);
1109 if (data[5])
Sony Chacko7e38d042013-01-01 03:20:28 +00001110 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001111 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001112}
1113
1114static void
Sony Chacko7e38d042013-01-01 03:20:28 +00001115qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001116{
amit salecha3666e0b2010-10-18 01:47:48 +00001117 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e38d042013-01-01 03:20:28 +00001118 int index, i, num_stats;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001119
1120 switch (stringset) {
1121 case ETH_SS_TEST:
1122 memcpy(data, *qlcnic_gstrings_test,
1123 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
1124 break;
1125 case ETH_SS_STATS:
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001126 num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings);
1127 for (i = 0; i < adapter->max_drv_tx_rings; i++) {
1128 for (index = 0; index < num_stats; index++) {
1129 sprintf(data, "tx_ring_%d %s", i,
1130 qlcnic_tx_ring_stats_strings[index]);
1131 data += ETH_GSTRING_LEN;
1132 }
1133 }
1134
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001135 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
1136 memcpy(data + index * ETH_GSTRING_LEN,
1137 qlcnic_gstrings_stats[index].stat_string,
1138 ETH_GSTRING_LEN);
1139 }
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001140
Sony Chacko7e38d042013-01-01 03:20:28 +00001141 if (qlcnic_83xx_check(adapter)) {
1142 num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
1143 for (i = 0; i < num_stats; i++, index++)
1144 memcpy(data + index * ETH_GSTRING_LEN,
1145 qlcnic_83xx_tx_stats_strings[i],
1146 ETH_GSTRING_LEN);
1147 num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
1148 for (i = 0; i < num_stats; i++, index++)
1149 memcpy(data + index * ETH_GSTRING_LEN,
1150 qlcnic_83xx_mac_stats_strings[i],
1151 ETH_GSTRING_LEN);
1152 num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
1153 for (i = 0; i < num_stats; i++, index++)
1154 memcpy(data + index * ETH_GSTRING_LEN,
1155 qlcnic_83xx_rx_stats_strings[i],
1156 ETH_GSTRING_LEN);
1157 return;
1158 } else {
1159 num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
1160 for (i = 0; i < num_stats; i++, index++)
1161 memcpy(data + index * ETH_GSTRING_LEN,
1162 qlcnic_83xx_mac_stats_strings[i],
1163 ETH_GSTRING_LEN);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001164 }
amit salecha3666e0b2010-10-18 01:47:48 +00001165 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
1166 return;
Sony Chacko7e38d042013-01-01 03:20:28 +00001167 num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
1168 for (i = 0; i < num_stats; index++, i++) {
amit salecha3666e0b2010-10-18 01:47:48 +00001169 memcpy(data + index * ETH_GSTRING_LEN,
1170 qlcnic_device_gstrings_stats[i],
1171 ETH_GSTRING_LEN);
1172 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001173 }
1174}
1175
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001176static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type)
amit salecha3666e0b2010-10-18 01:47:48 +00001177{
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001178 if (type == QLCNIC_MAC_STATS) {
1179 struct qlcnic_mac_statistics *mac_stats =
1180 (struct qlcnic_mac_statistics *)stats;
Sony Chacko7e38d042013-01-01 03:20:28 +00001181 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
1182 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
1183 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
1184 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
1185 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
1186 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
1187 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
1188 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
1189 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
1190 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
1191 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
1192 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
1193 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
1194 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
1195 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
1196 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
1197 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
1198 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
1199 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
1200 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
1201 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
1202 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
1203 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
1204 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
1205 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
1206 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
1207 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
1208 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
1209 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
1210 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
1211 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
1212 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
1213 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001214 } else if (type == QLCNIC_ESW_STATS) {
1215 struct __qlcnic_esw_statistics *esw_stats =
1216 (struct __qlcnic_esw_statistics *)stats;
Sony Chacko7e38d042013-01-01 03:20:28 +00001217 *data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
1218 *data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
1219 *data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
1220 *data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
1221 *data++ = QLCNIC_FILL_STATS(esw_stats->errors);
1222 *data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
1223 *data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001224 }
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001225 return data;
amit salecha3666e0b2010-10-18 01:47:48 +00001226}
1227
Sony Chacko7e38d042013-01-01 03:20:28 +00001228static void qlcnic_get_ethtool_stats(struct net_device *dev,
1229 struct ethtool_stats *stats, u64 *data)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001230{
1231 struct qlcnic_adapter *adapter = netdev_priv(dev);
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001232 struct qlcnic_host_tx_ring *tx_ring;
amit salecha3666e0b2010-10-18 01:47:48 +00001233 struct qlcnic_esw_statistics port_stats;
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001234 struct qlcnic_mac_statistics mac_stats;
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001235 int index, ret, length, size, ring;
Sony Chacko7e38d042013-01-01 03:20:28 +00001236 char *p;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001237
Himanshu Madhaniaa4a1f72013-08-21 11:24:11 -04001238 memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64));
1239 for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) {
1240 if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1241 tx_ring = &adapter->tx_ring[ring];
1242 *data++ = tx_ring->xmit_on;
1243 *data++ = tx_ring->xmit_off;
1244 *data++ = tx_ring->xmit_called;
1245 *data++ = tx_ring->xmit_finished;
1246 }
1247 }
Sony Chacko7e38d042013-01-01 03:20:28 +00001248 memset(data, 0, stats->n_stats * sizeof(u64));
1249 length = QLCNIC_STATS_LEN;
1250 for (index = 0; index < length; index++) {
1251 p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset;
1252 size = qlcnic_gstrings_stats[index].sizeof_stat;
1253 *data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001254 }
amit salecha3666e0b2010-10-18 01:47:48 +00001255
Sony Chacko7e38d042013-01-01 03:20:28 +00001256 if (qlcnic_83xx_check(adapter)) {
1257 if (adapter->ahw->linkup)
1258 qlcnic_83xx_get_stats(adapter, data);
1259 return;
1260 } else {
1261 /* Retrieve MAC statistics from firmware */
1262 memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
1263 qlcnic_get_mac_stats(adapter, &mac_stats);
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001264 data = qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
Sony Chacko7e38d042013-01-01 03:20:28 +00001265 }
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001266
amit salecha3666e0b2010-10-18 01:47:48 +00001267 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
1268 return;
1269
1270 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001271 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001272 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
1273 if (ret)
1274 return;
1275
Shahed Shaikh9434dbf2013-03-08 09:53:52 +00001276 data = qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001277 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001278 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
1279 if (ret)
1280 return;
1281
Sony Chacko7e38d042013-01-01 03:20:28 +00001282 qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001283}
1284
stephen hemminger94469f72011-04-06 11:47:23 +00001285static int qlcnic_set_led(struct net_device *dev,
1286 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001287{
1288 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001289 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001290 int err = -EIO, active = 1;
1291
Sony Chacko7e38d042013-01-01 03:20:28 +00001292 if (qlcnic_83xx_check(adapter))
Himanshu Madhanid16951d2013-03-08 09:53:50 +00001293 return qlcnic_83xx_set_led(dev, state);
1294
Sony Chacko79788452012-12-04 03:33:53 +00001295 if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001296 netdev_warn(dev, "LED test not supported for non "
1297 "privilege function\n");
1298 return -EOPNOTSUPP;
1299 }
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001300
stephen hemminger94469f72011-04-06 11:47:23 +00001301 switch (state) {
1302 case ETHTOOL_ID_ACTIVE:
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001303 if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
1304 return -EBUSY;
1305
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001306 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1307 break;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001308
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001309 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1310 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1311 break;
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001312 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001313 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001314
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001315 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
1316 err = 0;
1317 break;
1318 }
stephen hemminger94469f72011-04-06 11:47:23 +00001319
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001320 dev_err(&adapter->pdev->dev,
1321 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +00001322 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001323
stephen hemminger94469f72011-04-06 11:47:23 +00001324 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001325 active = 0;
1326
1327 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1328 break;
1329
1330 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1331 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1332 break;
1333 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
1334 }
1335
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001336 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
1337 dev_err(&adapter->pdev->dev,
1338 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001339
stephen hemminger94469f72011-04-06 11:47:23 +00001340 break;
1341
1342 default:
1343 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001344 }
1345
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001346 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001347 qlcnic_diag_free_res(dev, max_sds_rings);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001348
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001349 if (!active || err)
1350 clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001351
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001352 return err;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001353}
1354
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001355static void
1356qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1357{
1358 struct qlcnic_adapter *adapter = netdev_priv(dev);
1359 u32 wol_cfg;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001360 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001361
Sony Chacko7e38d042013-01-01 03:20:28 +00001362 if (qlcnic_83xx_check(adapter))
1363 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001364 wol->supported = 0;
1365 wol->wolopts = 0;
1366
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001367 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
1368 if (err == -EIO)
1369 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001370 if (wol_cfg & (1UL << adapter->portnum))
1371 wol->supported |= WAKE_MAGIC;
1372
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001373 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001374 if (wol_cfg & (1UL << adapter->portnum))
1375 wol->wolopts |= WAKE_MAGIC;
1376}
1377
1378static int
1379qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1380{
1381 struct qlcnic_adapter *adapter = netdev_priv(dev);
1382 u32 wol_cfg;
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001383 int err = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001384
Sony Chacko7e38d042013-01-01 03:20:28 +00001385 if (qlcnic_83xx_check(adapter))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001386 return -EOPNOTSUPP;
Sony Chacko7e38d042013-01-01 03:20:28 +00001387 if (wol->wolopts & ~WAKE_MAGIC)
1388 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001389
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001390 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
1391 if (err == -EIO)
1392 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001393 if (!(wol_cfg & (1 << adapter->portnum)))
1394 return -EOPNOTSUPP;
1395
Himanshu Madhani4bd8e732013-08-02 23:16:01 -04001396 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
1397 if (err == -EIO)
1398 return err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001399 if (wol->wolopts & WAKE_MAGIC)
1400 wol_cfg |= 1UL << adapter->portnum;
1401 else
1402 wol_cfg &= ~(1UL << adapter->portnum);
1403
1404 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1405
1406 return 0;
1407}
1408
1409/*
1410 * Set the coalescing parameters. Currently only normal is supported.
1411 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1412 * firmware coalescing to default.
1413 */
1414static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1415 struct ethtool_coalesce *ethcoal)
1416{
1417 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001418 struct qlcnic_nic_intr_coalesce *coal;
1419 u32 rx_coalesce_usecs, rx_max_frames;
1420 u32 tx_coalesce_usecs, tx_max_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001421
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001422 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001423 return -EINVAL;
1424
1425 /*
1426 * Return Error if unsupported values or
1427 * unsupported parameters are set.
1428 */
1429 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1430 ethcoal->rx_max_coalesced_frames > 0xffff ||
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001431 ethcoal->tx_coalesce_usecs > 0xffff ||
1432 ethcoal->tx_max_coalesced_frames > 0xffff ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001433 ethcoal->rx_coalesce_usecs_irq ||
1434 ethcoal->rx_max_coalesced_frames_irq ||
1435 ethcoal->tx_coalesce_usecs_irq ||
1436 ethcoal->tx_max_coalesced_frames_irq ||
1437 ethcoal->stats_block_coalesce_usecs ||
1438 ethcoal->use_adaptive_rx_coalesce ||
1439 ethcoal->use_adaptive_tx_coalesce ||
1440 ethcoal->pkt_rate_low ||
1441 ethcoal->rx_coalesce_usecs_low ||
1442 ethcoal->rx_max_coalesced_frames_low ||
1443 ethcoal->tx_coalesce_usecs_low ||
1444 ethcoal->tx_max_coalesced_frames_low ||
1445 ethcoal->pkt_rate_high ||
1446 ethcoal->rx_coalesce_usecs_high ||
1447 ethcoal->rx_max_coalesced_frames_high ||
1448 ethcoal->tx_coalesce_usecs_high ||
1449 ethcoal->tx_max_coalesced_frames_high)
1450 return -EINVAL;
1451
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001452 coal = &adapter->ahw->coal;
1453
1454 if (qlcnic_83xx_check(adapter)) {
1455 if (!ethcoal->tx_coalesce_usecs ||
1456 !ethcoal->tx_max_coalesced_frames ||
1457 !ethcoal->rx_coalesce_usecs ||
1458 !ethcoal->rx_max_coalesced_frames) {
1459 coal->flag = QLCNIC_INTR_DEFAULT;
1460 coal->type = QLCNIC_INTR_COAL_TYPE_RX;
1461 coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
1462 coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
1463 coal->tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
1464 coal->tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
1465 } else {
1466 tx_coalesce_usecs = ethcoal->tx_coalesce_usecs;
1467 tx_max_frames = ethcoal->tx_max_coalesced_frames;
1468 rx_coalesce_usecs = ethcoal->rx_coalesce_usecs;
1469 rx_max_frames = ethcoal->rx_max_coalesced_frames;
1470 coal->flag = 0;
1471
1472 if ((coal->rx_time_us == rx_coalesce_usecs) &&
1473 (coal->rx_packets == rx_max_frames)) {
1474 coal->type = QLCNIC_INTR_COAL_TYPE_TX;
1475 coal->tx_time_us = tx_coalesce_usecs;
1476 coal->tx_packets = tx_max_frames;
1477 } else if ((coal->tx_time_us == tx_coalesce_usecs) &&
1478 (coal->tx_packets == tx_max_frames)) {
1479 coal->type = QLCNIC_INTR_COAL_TYPE_RX;
1480 coal->rx_time_us = rx_coalesce_usecs;
1481 coal->rx_packets = rx_max_frames;
1482 } else {
1483 coal->type = QLCNIC_INTR_COAL_TYPE_RX;
1484 coal->rx_time_us = rx_coalesce_usecs;
1485 coal->rx_packets = rx_max_frames;
1486 coal->tx_time_us = tx_coalesce_usecs;
1487 coal->tx_packets = tx_max_frames;
1488 }
1489 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001490 } else {
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001491 if (!ethcoal->rx_coalesce_usecs ||
1492 !ethcoal->rx_max_coalesced_frames) {
1493 coal->flag = QLCNIC_INTR_DEFAULT;
1494 coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
1495 coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
1496 } else {
1497 coal->flag = 0;
1498 coal->rx_time_us = ethcoal->rx_coalesce_usecs;
1499 coal->rx_packets = ethcoal->rx_max_coalesced_frames;
1500 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001501 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001502
1503 qlcnic_config_intr_coalesce(adapter);
1504
1505 return 0;
1506}
1507
1508static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1509 struct ethtool_coalesce *ethcoal)
1510{
1511 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1512
1513 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1514 return -EINVAL;
1515
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001516 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
1517 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Himanshu Madhanibe273dc2013-04-24 12:42:42 +00001518 ethcoal->tx_coalesce_usecs = adapter->ahw->coal.tx_time_us;
1519 ethcoal->tx_max_coalesced_frames = adapter->ahw->coal.tx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001520
1521 return 0;
1522}
1523
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001524static u32 qlcnic_get_msglevel(struct net_device *netdev)
1525{
1526 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1527
Sony Chacko79788452012-12-04 03:33:53 +00001528 return adapter->ahw->msg_enable;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001529}
1530
1531static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1532{
1533 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1534
Sony Chacko79788452012-12-04 03:33:53 +00001535 adapter->ahw->msg_enable = msglvl;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001536}
1537
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001538int qlcnic_enable_fw_dump_state(struct qlcnic_adapter *adapter)
1539{
1540 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1541 u32 val;
1542
1543 if (qlcnic_84xx_check(adapter)) {
1544 if (qlcnic_83xx_lock_driver(adapter))
1545 return -EBUSY;
1546
1547 val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
1548 val &= ~QLC_83XX_IDC_DISABLE_FW_DUMP;
1549 QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
1550
1551 qlcnic_83xx_unlock_driver(adapter);
1552 } else {
1553 fw_dump->enable = true;
1554 }
1555
1556 dev_info(&adapter->pdev->dev, "FW dump enabled\n");
1557
1558 return 0;
1559}
1560
1561static int qlcnic_disable_fw_dump_state(struct qlcnic_adapter *adapter)
1562{
1563 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1564 u32 val;
1565
1566 if (qlcnic_84xx_check(adapter)) {
1567 if (qlcnic_83xx_lock_driver(adapter))
1568 return -EBUSY;
1569
1570 val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
1571 val |= QLC_83XX_IDC_DISABLE_FW_DUMP;
1572 QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
1573
1574 qlcnic_83xx_unlock_driver(adapter);
1575 } else {
1576 fw_dump->enable = false;
1577 }
1578
1579 dev_info(&adapter->pdev->dev, "FW dump disabled\n");
1580
1581 return 0;
1582}
1583
1584bool qlcnic_check_fw_dump_state(struct qlcnic_adapter *adapter)
1585{
1586 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1587 bool state;
1588 u32 val;
1589
1590 if (qlcnic_84xx_check(adapter)) {
1591 val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
1592 state = (val & QLC_83XX_IDC_DISABLE_FW_DUMP) ? false : true;
1593 } else {
1594 state = fw_dump->enable;
1595 }
1596
1597 return state;
1598}
1599
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001600static int
1601qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1602{
1603 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1604 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1605
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001606 if (!fw_dump->tmpl_hdr) {
1607 netdev_err(adapter->netdev, "FW Dump not supported\n");
1608 return -ENOTSUPP;
1609 }
1610
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001611 if (fw_dump->clr)
1612 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1613 else
1614 dump->len = 0;
Manish choprabcebe552012-05-15 01:13:39 +00001615
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001616 if (!qlcnic_check_fw_dump_state(adapter))
Manish choprabcebe552012-05-15 01:13:39 +00001617 dump->flag = ETH_FW_DUMP_DISABLE;
1618 else
1619 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1620
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001621 dump->version = adapter->fw_version;
1622 return 0;
1623}
1624
1625static int
1626qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1627 void *buffer)
1628{
1629 int i, copy_sz;
Shahed Shaikh63507592012-11-23 23:56:52 +00001630 u32 *hdr_ptr;
1631 __le32 *data;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001632 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1633 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1634
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001635 if (!fw_dump->tmpl_hdr) {
1636 netdev_err(netdev, "FW Dump not supported\n");
1637 return -ENOTSUPP;
1638 }
1639
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001640 if (!fw_dump->clr) {
1641 netdev_info(netdev, "Dump not available\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001642 return -EINVAL;
1643 }
1644 /* Copy template header first */
1645 copy_sz = fw_dump->tmpl_hdr->size;
1646 hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
Joe Perches43d620c2011-06-16 19:08:06 +00001647 data = buffer;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001648 for (i = 0; i < copy_sz/sizeof(u32); i++)
1649 *data++ = cpu_to_le32(*hdr_ptr++);
1650
1651 /* Copy captured dump data */
1652 memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1653 dump->len = copy_sz + fw_dump->size;
1654 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1655
1656 /* Free dump area once data has been captured */
1657 vfree(fw_dump->data);
1658 fw_dump->data = NULL;
1659 fw_dump->clr = 0;
Manish choprac47884e42012-02-03 13:45:44 +00001660 netdev_info(netdev, "extracted the FW dump Successfully\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001661 return 0;
1662}
1663
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001664static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask)
1665{
1666 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1667 struct net_device *netdev = adapter->netdev;
1668
1669 if (!qlcnic_check_fw_dump_state(adapter)) {
1670 netdev_info(netdev,
1671 "Can not change driver mask to 0x%x. FW dump not enabled\n",
1672 mask);
1673 return -EOPNOTSUPP;
1674 }
1675
1676 fw_dump->tmpl_hdr->drv_cap_mask = mask;
1677 netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask);
1678 return 0;
1679}
1680
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001681static int
1682qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1683{
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001684 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1685 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001686 bool valid_mask = false;
1687 int i, ret = 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001688
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001689 switch (val->flag) {
1690 case QLCNIC_FORCE_FW_DUMP_KEY:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001691 if (!fw_dump->tmpl_hdr) {
1692 netdev_err(netdev, "FW dump not supported\n");
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001693 ret = -EOPNOTSUPP;
1694 break;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001695 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001696
1697 if (!qlcnic_check_fw_dump_state(adapter)) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001698 netdev_info(netdev, "FW dump not enabled\n");
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001699 ret = -EOPNOTSUPP;
1700 break;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001701 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001702
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001703 if (fw_dump->clr) {
Manish choprac47884e42012-02-03 13:45:44 +00001704 netdev_info(netdev,
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001705 "Previous dump not cleared, not forcing dump\n");
1706 break;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001707 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001708
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001709 netdev_info(netdev, "Forcing a FW dump\n");
Sony Chacko7e38d042013-01-01 03:20:28 +00001710 qlcnic_dev_request_reset(adapter, val->flag);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001711 break;
1712 case QLCNIC_DISABLE_FW_DUMP:
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001713 if (!fw_dump->tmpl_hdr) {
1714 netdev_err(netdev, "FW dump not supported\n");
1715 ret = -EOPNOTSUPP;
1716 break;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001717 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001718
1719 ret = qlcnic_disable_fw_dump_state(adapter);
1720 break;
1721
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001722 case QLCNIC_ENABLE_FW_DUMP:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001723 if (!fw_dump->tmpl_hdr) {
1724 netdev_err(netdev, "FW dump not supported\n");
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001725 ret = -EOPNOTSUPP;
1726 break;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001727 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001728
1729 ret = qlcnic_enable_fw_dump_state(adapter);
1730 break;
1731
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001732 case QLCNIC_FORCE_FW_RESET:
1733 netdev_info(netdev, "Forcing a FW reset\n");
Sony Chacko7e38d042013-01-01 03:20:28 +00001734 qlcnic_dev_request_reset(adapter, val->flag);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001735 adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001736 break;
Dan Carpenter3cc4a672013-09-03 12:13:47 +03001737
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001738 case QLCNIC_SET_QUIESCENT:
1739 case QLCNIC_RESET_QUIESCENT:
Sucheta Chakraborty78ea2d92013-11-04 13:31:29 -05001740 if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state))
1741 netdev_info(netdev, "Device is in non-operational state\n");
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001742 break;
1743
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001744 default:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001745 if (!fw_dump->tmpl_hdr) {
1746 netdev_err(netdev, "FW dump not supported\n");
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001747 ret = -EOPNOTSUPP;
1748 break;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001749 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001750
Sony Chacko7e38d042013-01-01 03:20:28 +00001751 for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
1752 if (val->flag == qlcnic_fw_dump_level[i]) {
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001753 valid_mask = true;
1754 break;
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001755 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001756 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001757
1758 if (valid_mask) {
1759 ret = qlcnic_set_dump_mask(adapter, val->flag);
1760 } else {
1761 netdev_info(netdev, "Invalid dump level: 0x%x\n",
1762 val->flag);
1763 ret = -EINVAL;
1764 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001765 }
Shahed Shaikh890b6e02013-08-30 13:51:19 -04001766 return ret;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001767}
1768
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001769const struct ethtool_ops qlcnic_ethtool_ops = {
1770 .get_settings = qlcnic_get_settings,
1771 .set_settings = qlcnic_set_settings,
1772 .get_drvinfo = qlcnic_get_drvinfo,
1773 .get_regs_len = qlcnic_get_regs_len,
1774 .get_regs = qlcnic_get_regs,
1775 .get_link = ethtool_op_get_link,
1776 .get_eeprom_len = qlcnic_get_eeprom_len,
1777 .get_eeprom = qlcnic_get_eeprom,
1778 .get_ringparam = qlcnic_get_ringparam,
1779 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +00001780 .get_channels = qlcnic_get_channels,
1781 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001782 .get_pauseparam = qlcnic_get_pauseparam,
1783 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001784 .get_wol = qlcnic_get_wol,
1785 .set_wol = qlcnic_set_wol,
1786 .self_test = qlcnic_diag_test,
1787 .get_strings = qlcnic_get_strings,
1788 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1789 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001790 .get_coalesce = qlcnic_get_intr_coalesce,
1791 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +00001792 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001793 .set_msglevel = qlcnic_set_msglevel,
1794 .get_msglevel = qlcnic_get_msglevel,
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001795 .get_dump_flag = qlcnic_get_dump_flag,
1796 .get_dump_data = qlcnic_get_dump_data,
1797 .set_dump = qlcnic_set_dump,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001798};
Rajesh Borundiad1a11052013-04-19 07:01:13 +00001799
1800const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = {
1801 .get_settings = qlcnic_get_settings,
1802 .get_drvinfo = qlcnic_get_drvinfo,
1803 .get_regs_len = qlcnic_get_regs_len,
1804 .get_regs = qlcnic_get_regs,
1805 .get_link = ethtool_op_get_link,
1806 .get_eeprom_len = qlcnic_get_eeprom_len,
1807 .get_eeprom = qlcnic_get_eeprom,
1808 .get_ringparam = qlcnic_get_ringparam,
1809 .set_ringparam = qlcnic_set_ringparam,
1810 .get_channels = qlcnic_get_channels,
1811 .get_pauseparam = qlcnic_get_pauseparam,
1812 .get_wol = qlcnic_get_wol,
1813 .get_strings = qlcnic_get_strings,
1814 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1815 .get_sset_count = qlcnic_get_sset_count,
1816 .get_coalesce = qlcnic_get_intr_coalesce,
1817 .set_coalesce = qlcnic_set_intr_coalesce,
1818 .set_msglevel = qlcnic_set_msglevel,
1819 .get_msglevel = qlcnic_get_msglevel,
1820};
Sucheta Chakraborty66451612013-09-27 02:12:36 -04001821
1822const struct ethtool_ops qlcnic_ethtool_failed_ops = {
1823 .get_settings = qlcnic_get_settings,
1824 .get_drvinfo = qlcnic_get_drvinfo,
1825 .set_msglevel = qlcnic_set_msglevel,
1826 .get_msglevel = qlcnic_get_msglevel,
1827 .set_dump = qlcnic_set_dump,
1828};