blob: 58e255437d5afc0165f4ed4ba6bcfa31733953ca [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",
118};
119
Sony Chacko7e38d042013-01-01 03:20:28 +0000120#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
121static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
122 "ctx_rx_bytes",
123 "ctx_rx_pkts",
124 "ctx_lro_pkt_cnt",
125 "ctx_ip_csum_error",
126 "ctx_rx_pkts_wo_ctx",
127 "ctx_rx_pkts_dropped_wo_sts",
128 "ctx_rx_osized_pkts",
129 "ctx_rx_pkts_dropped_wo_rds",
130 "ctx_rx_unexpected_mcast_pkts",
131 "ctx_invalid_mac_address",
132 "ctx_rx_rds_ring_prim_attemoted",
133 "ctx_rx_rds_ring_prim_success",
134 "ctx_num_lro_flows_added",
135 "ctx_num_lro_flows_removed",
136 "ctx_num_lro_flows_active",
137 "ctx_pkts_dropped_unknown",
138};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000139
140static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
141 "Register_Test_on_offline",
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000142 "Link_Test_on_offline",
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000143 "Interrupt_Test_offline",
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000144 "Internal_Loopback_offline",
Sony Chacko7e38d042013-01-01 03:20:28 +0000145 "EEPROM_Test_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000146};
147
148#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
149
Sony Chacko7e38d042013-01-01 03:20:28 +0000150static inline int qlcnic_82xx_statistics(void)
151{
152 return QLCNIC_STATS_LEN + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
153}
154
155static inline int qlcnic_83xx_statistics(void)
156{
157 return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
158 ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
159 ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
160}
161
162static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)
163{
164 if (qlcnic_82xx_check(adapter))
165 return qlcnic_82xx_statistics();
166 else if (qlcnic_83xx_check(adapter))
167 return qlcnic_83xx_statistics();
168 else
169 return -1;
170}
171
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000172#define QLCNIC_RING_REGS_COUNT 20
173#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
174#define QLCNIC_MAX_EEPROM_LEN 1024
175
176static const u32 diag_registers[] = {
Shahed Shaikh2c6196d2013-01-01 03:20:29 +0000177 QLCNIC_CMDPEG_STATE,
178 QLCNIC_RCVPEG_STATE,
179 QLCNIC_FW_CAPABILITIES,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000180 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000181 QLCNIC_CRB_DEV_STATE,
182 QLCNIC_CRB_DRV_STATE,
183 QLCNIC_CRB_DRV_SCRATCH,
184 QLCNIC_CRB_DEV_PARTITION_INFO,
185 QLCNIC_CRB_DRV_IDC_VER,
186 QLCNIC_PEG_ALIVE_COUNTER,
187 QLCNIC_PEG_HALT_STATUS1,
188 QLCNIC_PEG_HALT_STATUS2,
Sony Chacko7e38d042013-01-01 03:20:28 +0000189 -1
190};
191
Shahed Shaikh2c6196d2013-01-01 03:20:29 +0000192
Sony Chacko7e38d042013-01-01 03:20:28 +0000193static const u32 ext_diag_registers[] = {
194 CRB_XG_STATE_P3P,
195 ISR_INT_STATE_REG,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000196 QLCNIC_CRB_PEG_NET_0+0x3c,
197 QLCNIC_CRB_PEG_NET_1+0x3c,
198 QLCNIC_CRB_PEG_NET_2+0x3c,
199 QLCNIC_CRB_PEG_NET_4+0x3c,
200 -1
201};
202
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000203#define QLCNIC_MGMT_API_VERSION 2
Sony Chacko7e38d042013-01-01 03:20:28 +0000204#define QLCNIC_ETHTOOL_REGS_VER 3
205
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000206static int qlcnic_get_regs_len(struct net_device *dev)
207{
Sony Chacko7e38d042013-01-01 03:20:28 +0000208 struct qlcnic_adapter *adapter = netdev_priv(dev);
209 u32 len;
210
211 if (qlcnic_83xx_check(adapter))
212 len = qlcnic_83xx_get_regs_len(adapter);
213 else
214 len = sizeof(ext_diag_registers) + sizeof(diag_registers);
215
216 return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000217}
218
219static int qlcnic_get_eeprom_len(struct net_device *dev)
220{
221 return QLCNIC_FLASH_TOTAL_SIZE;
222}
223
224static void
225qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
226{
227 struct qlcnic_adapter *adapter = netdev_priv(dev);
228 u32 fw_major, fw_minor, fw_build;
Sony Chacko7e38d042013-01-01 03:20:28 +0000229 fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
230 fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
231 fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
Rick Jones68aad782011-11-07 13:29:27 +0000232 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
233 "%d.%d.%d", fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000234
Rick Jones68aad782011-11-07 13:29:27 +0000235 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
236 sizeof(drvinfo->bus_info));
237 strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
238 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
239 sizeof(drvinfo->version));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000240}
241
242static int
243qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
244{
245 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e38d042013-01-01 03:20:28 +0000246 struct qlcnic_hardware_context *ahw = adapter->ahw;
247 u32 speed, reg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000248 int check_sfp_module = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000249 u16 pcifn = ahw->pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000250
251 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000252 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000253 ecmd->supported = (SUPPORTED_10baseT_Half |
254 SUPPORTED_10baseT_Full |
255 SUPPORTED_100baseT_Half |
256 SUPPORTED_100baseT_Full |
257 SUPPORTED_1000baseT_Half |
258 SUPPORTED_1000baseT_Full);
259
260 ecmd->advertising = (ADVERTISED_100baseT_Half |
261 ADVERTISED_100baseT_Full |
262 ADVERTISED_1000baseT_Half |
263 ADVERTISED_1000baseT_Full);
264
Sony Chacko79788452012-12-04 03:33:53 +0000265 ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
266 ecmd->duplex = adapter->ahw->link_duplex;
267 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000268
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000269 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Sony Chacko7e38d042013-01-01 03:20:28 +0000270 u32 val = 0;
271 if (qlcnic_83xx_check(adapter))
272 qlcnic_83xx_get_settings(adapter);
273 else
274 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000275
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000276 if (val == QLCNIC_PORT_MODE_802_3_AP) {
277 ecmd->supported = SUPPORTED_1000baseT_Full;
278 ecmd->advertising = ADVERTISED_1000baseT_Full;
279 } else {
280 ecmd->supported = SUPPORTED_10000baseT_Full;
281 ecmd->advertising = ADVERTISED_10000baseT_Full;
282 }
283
Sony Chacko79788452012-12-04 03:33:53 +0000284 if (netif_running(dev) && adapter->ahw->has_link_events) {
Sony Chacko7e38d042013-01-01 03:20:28 +0000285 if (qlcnic_82xx_check(adapter)) {
286 reg = QLCRD32(adapter,
287 P3P_LINK_SPEED_REG(pcifn));
288 speed = P3P_LINK_SPEED_VAL(pcifn, reg);
289 ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
290 }
Sony Chacko79788452012-12-04 03:33:53 +0000291 ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
292 ecmd->autoneg = adapter->ahw->link_autoneg;
293 ecmd->duplex = adapter->ahw->link_duplex;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000294 goto skip;
295 }
296
Sony Chacko476a4b62012-02-03 13:45:42 +0000297 ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
298 ecmd->duplex = DUPLEX_UNKNOWN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000299 ecmd->autoneg = AUTONEG_DISABLE;
300 } else
301 return -EIO;
302
303skip:
Sony Chacko79788452012-12-04 03:33:53 +0000304 ecmd->phy_address = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000305 ecmd->transceiver = XCVR_EXTERNAL;
306
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000307 switch (adapter->ahw->board_type) {
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000308 case QLCNIC_BRDTYPE_P3P_REF_QG:
309 case QLCNIC_BRDTYPE_P3P_4_GB:
310 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000311
312 ecmd->supported |= SUPPORTED_Autoneg;
313 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000314 case QLCNIC_BRDTYPE_P3P_10G_CX4:
315 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
316 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000317 ecmd->supported |= SUPPORTED_TP;
318 ecmd->advertising |= ADVERTISED_TP;
319 ecmd->port = PORT_TP;
Sony Chacko79788452012-12-04 03:33:53 +0000320 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000321 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000322 case QLCNIC_BRDTYPE_P3P_IMEZ:
323 case QLCNIC_BRDTYPE_P3P_XG_LOM:
324 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000325 ecmd->supported |= SUPPORTED_MII;
326 ecmd->advertising |= ADVERTISED_MII;
327 ecmd->port = PORT_MII;
328 ecmd->autoneg = AUTONEG_DISABLE;
329 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000330 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
331 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
332 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000333 ecmd->advertising |= ADVERTISED_TP;
334 ecmd->supported |= SUPPORTED_TP;
335 check_sfp_module = netif_running(dev) &&
Sony Chacko79788452012-12-04 03:33:53 +0000336 adapter->ahw->has_link_events;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000337 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000338 ecmd->supported |= SUPPORTED_FIBRE;
339 ecmd->advertising |= ADVERTISED_FIBRE;
340 ecmd->port = PORT_FIBRE;
341 ecmd->autoneg = AUTONEG_DISABLE;
342 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000343 case QLCNIC_BRDTYPE_P3P_10G_TP:
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000344 if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000345 ecmd->autoneg = AUTONEG_DISABLE;
346 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
347 ecmd->advertising |=
348 (ADVERTISED_FIBRE | ADVERTISED_TP);
349 ecmd->port = PORT_FIBRE;
350 check_sfp_module = netif_running(dev) &&
Sony Chacko79788452012-12-04 03:33:53 +0000351 adapter->ahw->has_link_events;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000352 } else {
353 ecmd->autoneg = AUTONEG_ENABLE;
354 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
355 ecmd->advertising |=
356 (ADVERTISED_TP | ADVERTISED_Autoneg);
357 ecmd->port = PORT_TP;
358 }
359 break;
Sony Chacko7e38d042013-01-01 03:20:28 +0000360 case QLCNIC_BRDTYPE_83XX_10G:
361 ecmd->autoneg = AUTONEG_DISABLE;
362 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
363 ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP);
364 ecmd->port = PORT_FIBRE;
365 check_sfp_module = netif_running(dev) && ahw->has_link_events;
366 break;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000367 default:
368 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000369 adapter->ahw->board_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000370 return -EIO;
371 }
372
373 if (check_sfp_module) {
Sony Chacko79788452012-12-04 03:33:53 +0000374 switch (adapter->ahw->module_type) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000375 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
376 case LINKEVENT_MODULE_OPTICAL_SRLR:
377 case LINKEVENT_MODULE_OPTICAL_LRM:
378 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
379 ecmd->port = PORT_FIBRE;
380 break;
381 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
382 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
383 case LINKEVENT_MODULE_TWINAX:
384 ecmd->port = PORT_TP;
385 break;
386 default:
387 ecmd->port = PORT_OTHER;
388 }
389 }
390
391 return 0;
392}
393
Sony Chacko7e38d042013-01-01 03:20:28 +0000394static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,
395 struct ethtool_cmd *ecmd)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000396{
Sony Chacko7e38d042013-01-01 03:20:28 +0000397 u32 ret = 0, config = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000398 /* read which mode */
Sony Chacko7e610ca2011-04-28 11:48:19 +0000399 if (ecmd->duplex)
400 config |= 0x1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000401
Sony Chacko7e610ca2011-04-28 11:48:19 +0000402 if (ecmd->autoneg)
403 config |= 0x2;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000404
Sony Chacko7e610ca2011-04-28 11:48:19 +0000405 switch (ethtool_cmd_speed(ecmd)) {
406 case SPEED_10:
407 config |= (0 << 8);
408 break;
409 case SPEED_100:
410 config |= (1 << 8);
411 break;
412 case SPEED_1000:
413 config |= (10 << 8);
414 break;
415 default:
416 return -EIO;
417 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000418
Sony Chacko7e610ca2011-04-28 11:48:19 +0000419 ret = qlcnic_fw_cmd_set_port(adapter, config);
420
421 if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000422 return -EOPNOTSUPP;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000423 else if (ret)
424 return -EIO;
Sony Chacko7e38d042013-01-01 03:20:28 +0000425 return ret;
426}
427
428static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
429{
430 u32 ret = 0;
431 struct qlcnic_adapter *adapter = netdev_priv(dev);
432
433 if (adapter->ahw->port_type != QLCNIC_GBE)
434 return -EOPNOTSUPP;
435
436 if (qlcnic_83xx_check(adapter))
437 ret = qlcnic_83xx_set_settings(adapter, ecmd);
438 else
439 ret = qlcnic_set_port_config(adapter, ecmd);
440
441 if (!ret)
442 return ret;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000443
Sony Chacko79788452012-12-04 03:33:53 +0000444 adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
445 adapter->ahw->link_duplex = ecmd->duplex;
446 adapter->ahw->link_autoneg = ecmd->autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000447
448 if (!netif_running(dev))
449 return 0;
450
451 dev->netdev_ops->ndo_stop(dev);
452 return dev->netdev_ops->ndo_open(dev);
453}
454
Sony Chacko7e38d042013-01-01 03:20:28 +0000455static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
456 u32 *regs_buff)
457{
458 int i, j = 0;
459
460 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
461 regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
462 j = 0;
463 while (ext_diag_registers[j] != -1)
464 regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
465 return i;
466}
467
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000468static void
469qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
470{
471 struct qlcnic_adapter *adapter = netdev_priv(dev);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000472 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000473 struct qlcnic_host_sds_ring *sds_ring;
474 u32 *regs_buff = p;
Sony Chacko7e38d042013-01-01 03:20:28 +0000475 int ring, i = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000476
477 memset(p, 0, qlcnic_get_regs_len(dev));
Sony Chacko7e38d042013-01-01 03:20:28 +0000478
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000479 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000480 (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000481
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000482 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
483 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
484
Sony Chacko7e38d042013-01-01 03:20:28 +0000485 if (qlcnic_82xx_check(adapter))
486 i = qlcnic_82xx_get_registers(adapter, regs_buff);
487 else
488 i = qlcnic_83xx_get_registers(adapter, regs_buff);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000489
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000490 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000491 return;
492
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000493 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
494
495 regs_buff[i++] = 1; /* No. of tx ring */
496 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
497 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
498
499 regs_buff[i++] = 2; /* No. of rx ring */
500 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
501 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
502
503 regs_buff[i++] = adapter->max_sds_rings;
504
505 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
506 sds_ring = &(recv_ctx->sds_rings[ring]);
507 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
508 }
509}
510
511static u32 qlcnic_test_link(struct net_device *dev)
512{
513 struct qlcnic_adapter *adapter = netdev_priv(dev);
514 u32 val;
515
Sony Chacko7e38d042013-01-01 03:20:28 +0000516 if (qlcnic_83xx_check(adapter)) {
517 val = qlcnic_83xx_test_link(adapter);
518 return (val & 1) ? 0 : 1;
519 }
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000520 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000521 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000522 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000523}
524
525static int
526qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
527 u8 *bytes)
528{
529 struct qlcnic_adapter *adapter = netdev_priv(dev);
530 int offset;
Sony Chacko7e38d042013-01-01 03:20:28 +0000531 int ret = -1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000532
Sony Chacko7e38d042013-01-01 03:20:28 +0000533 if (qlcnic_83xx_check(adapter))
534 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000535 if (eeprom->len == 0)
536 return -EINVAL;
537
538 eeprom->magic = (adapter->pdev)->vendor |
539 ((adapter->pdev)->device << 16);
540 offset = eeprom->offset;
541
Sony Chacko7e38d042013-01-01 03:20:28 +0000542 if (qlcnic_82xx_check(adapter))
543 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
544 eeprom->len);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000545 if (ret < 0)
546 return ret;
547
548 return 0;
549}
550
551static void
552qlcnic_get_ringparam(struct net_device *dev,
553 struct ethtool_ringparam *ring)
554{
555 struct qlcnic_adapter *adapter = netdev_priv(dev);
556
557 ring->rx_pending = adapter->num_rxd;
558 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000559 ring->tx_pending = adapter->num_txd;
560
Sony Chacko90d19002010-10-26 17:53:08 +0000561 ring->rx_max_pending = adapter->max_rxd;
562 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000563 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000564}
565
566static u32
567qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
568{
569 u32 num_desc;
570 num_desc = max(val, min);
571 num_desc = min(num_desc, max);
572 num_desc = roundup_pow_of_two(num_desc);
573
574 if (val != num_desc) {
575 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
576 qlcnic_driver_name, r_name, num_desc, val);
577 }
578
579 return num_desc;
580}
581
582static int
583qlcnic_set_ringparam(struct net_device *dev,
584 struct ethtool_ringparam *ring)
585{
586 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000587 u16 num_rxd, num_jumbo_rxd, num_txd;
588
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000589 if (ring->rx_mini_pending)
590 return -EOPNOTSUPP;
591
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000592 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000593 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000594
595 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000596 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
597 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000598
599 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
600 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
601
602 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
603 num_jumbo_rxd == adapter->num_jumbo_rxd)
604 return 0;
605
606 adapter->num_rxd = num_rxd;
607 adapter->num_jumbo_rxd = num_jumbo_rxd;
608 adapter->num_txd = num_txd;
609
610 return qlcnic_reset_context(adapter);
611}
612
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000613static void qlcnic_get_channels(struct net_device *dev,
614 struct ethtool_channels *channel)
615{
Sony Chacko79788452012-12-04 03:33:53 +0000616 int min;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000617 struct qlcnic_adapter *adapter = netdev_priv(dev);
618
Sony Chacko79788452012-12-04 03:33:53 +0000619 min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus());
620 channel->max_rx = rounddown_pow_of_two(min);
621 channel->max_tx = adapter->ahw->max_tx_ques;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000622
623 channel->rx_count = adapter->max_sds_rings;
Sony Chacko79788452012-12-04 03:33:53 +0000624 channel->tx_count = adapter->ahw->max_tx_ques;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000625}
626
627static int qlcnic_set_channels(struct net_device *dev,
628 struct ethtool_channels *channel)
629{
630 struct qlcnic_adapter *adapter = netdev_priv(dev);
631 int err;
632
633 if (channel->other_count || channel->combined_count ||
634 channel->tx_count != channel->max_tx)
635 return -EINVAL;
636
Sony Chacko319ecf12013-01-01 03:20:22 +0000637 err = qlcnic_validate_max_rss(channel->max_rx, channel->rx_count);
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000638 if (err)
639 return err;
640
Sony Chacko319ecf12013-01-01 03:20:22 +0000641 err = qlcnic_set_max_rss(adapter, channel->rx_count, 0);
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000642 netdev_info(dev, "allocated 0x%x sds rings\n",
643 adapter->max_sds_rings);
644 return err;
645}
646
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000647static void
648qlcnic_get_pauseparam(struct net_device *netdev,
649 struct ethtool_pauseparam *pause)
650{
651 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000652 int port = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000653 __u32 val;
654
Sony Chacko7e38d042013-01-01 03:20:28 +0000655 if (qlcnic_83xx_check(adapter)) {
656 qlcnic_83xx_get_pauseparam(adapter, pause);
657 return;
658 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000659 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000660 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
661 return;
662 /* get flow control settings */
663 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
664 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
665 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
666 switch (port) {
667 case 0:
668 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
669 break;
670 case 1:
671 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
672 break;
673 case 2:
674 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
675 break;
676 case 3:
677 default:
678 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
679 break;
680 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000681 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000682 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
683 return;
684 pause->rx_pause = 1;
685 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
686 if (port == 0)
687 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
688 else
689 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
690 } else {
691 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000692 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000693 }
694}
695
696static int
697qlcnic_set_pauseparam(struct net_device *netdev,
698 struct ethtool_pauseparam *pause)
699{
700 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000701 int port = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000702 __u32 val;
703
Sony Chacko7e38d042013-01-01 03:20:28 +0000704 if (qlcnic_83xx_check(adapter))
705 return qlcnic_83xx_set_pauseparam(adapter, pause);
706
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000707 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000708 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000709 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
710 return -EIO;
711 /* set flow control */
712 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
713
714 if (pause->rx_pause)
715 qlcnic_gb_rx_flowctl(val);
716 else
717 qlcnic_gb_unset_rx_flowctl(val);
718
719 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
720 val);
Sony Chacko7e38d042013-01-01 03:20:28 +0000721 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000722 /* set autoneg */
723 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
724 switch (port) {
725 case 0:
726 if (pause->tx_pause)
727 qlcnic_gb_unset_gb0_mask(val);
728 else
729 qlcnic_gb_set_gb0_mask(val);
730 break;
731 case 1:
732 if (pause->tx_pause)
733 qlcnic_gb_unset_gb1_mask(val);
734 else
735 qlcnic_gb_set_gb1_mask(val);
736 break;
737 case 2:
738 if (pause->tx_pause)
739 qlcnic_gb_unset_gb2_mask(val);
740 else
741 qlcnic_gb_set_gb2_mask(val);
742 break;
743 case 3:
744 default:
745 if (pause->tx_pause)
746 qlcnic_gb_unset_gb3_mask(val);
747 else
748 qlcnic_gb_set_gb3_mask(val);
749 break;
750 }
751 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000752 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000753 if (!pause->rx_pause || pause->autoneg)
754 return -EOPNOTSUPP;
755
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000756 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
757 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000758
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000759 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
760 if (port == 0) {
761 if (pause->tx_pause)
762 qlcnic_xg_unset_xg0_mask(val);
763 else
764 qlcnic_xg_set_xg0_mask(val);
765 } else {
766 if (pause->tx_pause)
767 qlcnic_xg_unset_xg1_mask(val);
768 else
769 qlcnic_xg_set_xg1_mask(val);
770 }
771 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
772 } else {
773 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000774 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000775 }
776 return 0;
777}
778
779static int qlcnic_reg_test(struct net_device *dev)
780{
781 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000782 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000783
Sony Chacko7e38d042013-01-01 03:20:28 +0000784 if (qlcnic_83xx_check(adapter))
785 return qlcnic_83xx_reg_test(adapter);
786
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000787 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
788 if ((data_read & 0xffff) != adapter->pdev->vendor)
789 return 1;
790
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000791 return 0;
792}
793
Sony Chacko7e38d042013-01-01 03:20:28 +0000794static int qlcnic_eeprom_test(struct net_device *dev)
795{
796 struct qlcnic_adapter *adapter = netdev_priv(dev);
797
798 if (qlcnic_82xx_check(adapter))
799 return 0;
800
801 return qlcnic_83xx_flash_test(adapter);
802}
803
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000804static int qlcnic_get_sset_count(struct net_device *dev, int sset)
805{
Sony Chacko7e38d042013-01-01 03:20:28 +0000806 int len;
807
amit salecha3666e0b2010-10-18 01:47:48 +0000808 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000809 switch (sset) {
810 case ETH_SS_TEST:
811 return QLCNIC_TEST_LEN;
812 case ETH_SS_STATS:
Sony Chacko7e38d042013-01-01 03:20:28 +0000813 len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
814 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
815 qlcnic_83xx_check(adapter))
816 return len;
817 return qlcnic_82xx_statistics();
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000818 default:
819 return -EOPNOTSUPP;
820 }
821}
822
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000823static int qlcnic_irq_test(struct net_device *netdev)
824{
825 struct qlcnic_adapter *adapter = netdev_priv(netdev);
826 int max_sds_rings = adapter->max_sds_rings;
827 int ret;
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000828 struct qlcnic_cmd_args cmd;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000829
830 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
831 return -EIO;
832
833 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
834 if (ret)
835 goto clear_it;
836
Sony Chacko79788452012-12-04 03:33:53 +0000837 adapter->ahw->diag_cnt = 0;
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000838 qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
839
Sony Chacko7e38d042013-01-01 03:20:28 +0000840 if (qlcnic_83xx_check(adapter)) {
841 ret = qlcnic_83xx_interrupt_test(adapter, &cmd);
842 } else {
843 cmd.req.arg[1] = adapter->ahw->pci_func;
844 ret = qlcnic_issue_cmd(adapter, &cmd);
845 }
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000846
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000847 if (ret)
848 goto done;
849
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000850 usleep_range(1000, 12000);
Sony Chacko79788452012-12-04 03:33:53 +0000851 ret = !adapter->ahw->diag_cnt;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000852
853done:
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000854 qlcnic_free_mbx_args(&cmd);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000855 qlcnic_diag_free_res(netdev, max_sds_rings);
856
857clear_it:
858 adapter->max_sds_rings = max_sds_rings;
859 clear_bit(__QLCNIC_RESETTING, &adapter->state);
860 return ret;
861}
862
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000863#define QLCNIC_ILB_PKT_SIZE 64
864#define QLCNIC_NUM_ILB_PKT 16
865#define QLCNIC_ILB_MAX_RCV_LOOP 10
866
867static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
868{
869 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
870
871 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
872
873 memcpy(data, mac, ETH_ALEN);
874 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
875
876 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
877}
878
879int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
880{
881 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
882 qlcnic_create_loopback_buff(buff, mac);
883 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
884}
885
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000886int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000887{
888 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
889 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
890 struct sk_buff *skb;
891 int i, loop, cnt = 0;
892
893 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
Pradeep A. Dalvidae2e9f2012-02-06 11:16:13 +0000894 skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000895 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
896 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
Sony Chacko79788452012-12-04 03:33:53 +0000897 adapter->ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000898 qlcnic_xmit_frame(skb, adapter->netdev);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000899 loop = 0;
Sony Chacko7e38d042013-01-01 03:20:28 +0000900
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000901 do {
902 msleep(1);
903 qlcnic_process_rcv_ring_diag(sds_ring);
904 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
905 break;
Sony Chacko79788452012-12-04 03:33:53 +0000906 } while (!adapter->ahw->diag_cnt);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000907
908 dev_kfree_skb_any(skb);
909
Sony Chacko79788452012-12-04 03:33:53 +0000910 if (!adapter->ahw->diag_cnt)
Sony Chacko7e38d042013-01-01 03:20:28 +0000911 dev_warn(&adapter->pdev->dev,
912 "LB Test: packet #%d was not received\n",
913 i + 1);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000914 else
915 cnt++;
916 }
917 if (cnt != i) {
Sony Chacko7e38d042013-01-01 03:20:28 +0000918 dev_err(&adapter->pdev->dev,
919 "LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
920 if (mode != QLCNIC_ILB_MODE)
Manish chopradf3cfbe2011-08-29 12:50:27 +0000921 dev_warn(&adapter->pdev->dev,
Sony Chacko7e38d042013-01-01 03:20:28 +0000922 "WARNING: Please check loopback cable\n");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000923 return -1;
924 }
925 return 0;
926}
927
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000928int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000929{
930 struct qlcnic_adapter *adapter = netdev_priv(netdev);
931 int max_sds_rings = adapter->max_sds_rings;
932 struct qlcnic_host_sds_ring *sds_ring;
Sony Chacko7e38d042013-01-01 03:20:28 +0000933 struct qlcnic_hardware_context *ahw = adapter->ahw;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000934 int loop = 0;
935 int ret;
936
Sony Chacko7e38d042013-01-01 03:20:28 +0000937 if (qlcnic_83xx_check(adapter))
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000938 return qlcnic_83xx_loopback_test(netdev, mode);
939
Sony Chacko7e38d042013-01-01 03:20:28 +0000940 if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
941 dev_info(&adapter->pdev->dev,
942 "Firmware do not support loopback test\n");
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000943 return -EOPNOTSUPP;
944 }
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000945
Sony Chacko7e38d042013-01-01 03:20:28 +0000946 dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
947 mode == QLCNIC_ILB_MODE ? "internal" : "external");
948 if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
949 dev_warn(&adapter->pdev->dev,
950 "Loopback test not supported in nonprivileged mode\n");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000951 return 0;
952 }
953
954 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000955 return -EBUSY;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000956
957 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
958 if (ret)
959 goto clear_it;
960
961 sds_ring = &adapter->recv_ctx->sds_rings[0];
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000962 ret = qlcnic_set_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000963 if (ret)
964 goto free_res;
965
Sony Chacko7e38d042013-01-01 03:20:28 +0000966 ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000967 do {
968 msleep(500);
969 qlcnic_process_rcv_ring_diag(sds_ring);
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000970 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
971 netdev_info(netdev, "firmware didnt respond to loopback"
972 " configure request\n");
973 ret = -QLCNIC_FW_NOT_RESPOND;
974 goto free_res;
Sony Chacko79788452012-12-04 03:33:53 +0000975 } else if (adapter->ahw->diag_cnt) {
976 ret = adapter->ahw->diag_cnt;
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000977 goto free_res;
978 }
Sony Chacko7e38d042013-01-01 03:20:28 +0000979 } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000980
Manish chopradf3cfbe2011-08-29 12:50:27 +0000981 ret = qlcnic_do_lb_test(adapter, mode);
Jitendra Kalsariaba4468db2013-02-09 09:29:51 +0000982
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000983 qlcnic_clear_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000984
985 free_res:
986 qlcnic_diag_free_res(netdev, max_sds_rings);
987
988 clear_it:
989 adapter->max_sds_rings = max_sds_rings;
990 clear_bit(__QLCNIC_RESETTING, &adapter->state);
991 return ret;
992}
993
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000994static void
995qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
996 u64 *data)
997{
998 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000999
Sony Chacko8dec32cc2010-08-17 00:34:24 +00001000 data[0] = qlcnic_reg_test(dev);
1001 if (data[0])
1002 eth_test->flags |= ETH_TEST_FL_FAILED;
1003
1004 data[1] = (u64) qlcnic_test_link(dev);
1005 if (data[1])
1006 eth_test->flags |= ETH_TEST_FL_FAILED;
1007
Sony Chacko13b93ed2011-01-10 00:15:22 +00001008 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001009 data[2] = qlcnic_irq_test(dev);
1010 if (data[2])
1011 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001012
Amit Kumar Salechae1428d22011-06-29 20:00:50 +00001013 data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +00001014 if (data[3])
1015 eth_test->flags |= ETH_TEST_FL_FAILED;
Sony Chacko7e38d042013-01-01 03:20:28 +00001016
1017 data[4] = qlcnic_eeprom_test(dev);
1018 if (data[4])
1019 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001020 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001021}
1022
1023static void
Sony Chacko7e38d042013-01-01 03:20:28 +00001024qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001025{
amit salecha3666e0b2010-10-18 01:47:48 +00001026 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e38d042013-01-01 03:20:28 +00001027 int index, i, num_stats;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001028
1029 switch (stringset) {
1030 case ETH_SS_TEST:
1031 memcpy(data, *qlcnic_gstrings_test,
1032 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
1033 break;
1034 case ETH_SS_STATS:
1035 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
1036 memcpy(data + index * ETH_GSTRING_LEN,
1037 qlcnic_gstrings_stats[index].stat_string,
1038 ETH_GSTRING_LEN);
1039 }
Sony Chacko7e38d042013-01-01 03:20:28 +00001040 if (qlcnic_83xx_check(adapter)) {
1041 num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
1042 for (i = 0; i < num_stats; i++, index++)
1043 memcpy(data + index * ETH_GSTRING_LEN,
1044 qlcnic_83xx_tx_stats_strings[i],
1045 ETH_GSTRING_LEN);
1046 num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
1047 for (i = 0; i < num_stats; i++, index++)
1048 memcpy(data + index * ETH_GSTRING_LEN,
1049 qlcnic_83xx_mac_stats_strings[i],
1050 ETH_GSTRING_LEN);
1051 num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
1052 for (i = 0; i < num_stats; i++, index++)
1053 memcpy(data + index * ETH_GSTRING_LEN,
1054 qlcnic_83xx_rx_stats_strings[i],
1055 ETH_GSTRING_LEN);
1056 return;
1057 } else {
1058 num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
1059 for (i = 0; i < num_stats; i++, index++)
1060 memcpy(data + index * ETH_GSTRING_LEN,
1061 qlcnic_83xx_mac_stats_strings[i],
1062 ETH_GSTRING_LEN);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001063 }
amit salecha3666e0b2010-10-18 01:47:48 +00001064 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
1065 return;
Sony Chacko7e38d042013-01-01 03:20:28 +00001066 num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
1067 for (i = 0; i < num_stats; index++, i++) {
amit salecha3666e0b2010-10-18 01:47:48 +00001068 memcpy(data + index * ETH_GSTRING_LEN,
1069 qlcnic_device_gstrings_stats[i],
1070 ETH_GSTRING_LEN);
1071 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001072 }
1073}
1074
amit salecha3666e0b2010-10-18 01:47:48 +00001075static void
Sony Chacko7e38d042013-01-01 03:20:28 +00001076qlcnic_fill_stats(u64 *data, void *stats, int type)
amit salecha3666e0b2010-10-18 01:47:48 +00001077{
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001078 if (type == QLCNIC_MAC_STATS) {
1079 struct qlcnic_mac_statistics *mac_stats =
1080 (struct qlcnic_mac_statistics *)stats;
Sony Chacko7e38d042013-01-01 03:20:28 +00001081 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
1082 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
1083 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
1084 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
1085 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
1086 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
1087 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
1088 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
1089 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
1090 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
1091 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
1092 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
1093 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
1094 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
1095 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
1096 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
1097 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
1098 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
1099 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
1100 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
1101 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
1102 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
1103 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
1104 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
1105 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
1106 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
1107 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
1108 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
1109 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
1110 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
1111 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
1112 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
1113 *data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001114 } else if (type == QLCNIC_ESW_STATS) {
1115 struct __qlcnic_esw_statistics *esw_stats =
1116 (struct __qlcnic_esw_statistics *)stats;
Sony Chacko7e38d042013-01-01 03:20:28 +00001117 *data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
1118 *data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
1119 *data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
1120 *data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
1121 *data++ = QLCNIC_FILL_STATS(esw_stats->errors);
1122 *data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
1123 *data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001124 }
amit salecha3666e0b2010-10-18 01:47:48 +00001125}
1126
Sony Chacko7e38d042013-01-01 03:20:28 +00001127static void qlcnic_get_ethtool_stats(struct net_device *dev,
1128 struct ethtool_stats *stats, u64 *data)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001129{
1130 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +00001131 struct qlcnic_esw_statistics port_stats;
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001132 struct qlcnic_mac_statistics mac_stats;
Sony Chacko7e38d042013-01-01 03:20:28 +00001133 int index, ret, length, size;
1134 char *p;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001135
Sony Chacko7e38d042013-01-01 03:20:28 +00001136 memset(data, 0, stats->n_stats * sizeof(u64));
1137 length = QLCNIC_STATS_LEN;
1138 for (index = 0; index < length; index++) {
1139 p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset;
1140 size = qlcnic_gstrings_stats[index].sizeof_stat;
1141 *data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001142 }
amit salecha3666e0b2010-10-18 01:47:48 +00001143
Sony Chacko7e38d042013-01-01 03:20:28 +00001144 if (qlcnic_83xx_check(adapter)) {
1145 if (adapter->ahw->linkup)
1146 qlcnic_83xx_get_stats(adapter, data);
1147 return;
1148 } else {
1149 /* Retrieve MAC statistics from firmware */
1150 memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
1151 qlcnic_get_mac_stats(adapter, &mac_stats);
1152 qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
1153 }
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001154
amit salecha3666e0b2010-10-18 01:47:48 +00001155 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
1156 return;
1157
1158 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001159 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001160 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
1161 if (ret)
1162 return;
1163
Sony Chacko7e38d042013-01-01 03:20:28 +00001164 qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001165 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001166 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
1167 if (ret)
1168 return;
1169
Sony Chacko7e38d042013-01-01 03:20:28 +00001170 qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001171}
1172
stephen hemminger94469f72011-04-06 11:47:23 +00001173static int qlcnic_set_led(struct net_device *dev,
1174 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001175{
1176 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001177 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001178 int err = -EIO, active = 1;
1179
Sony Chacko7e38d042013-01-01 03:20:28 +00001180 if (qlcnic_83xx_check(adapter))
1181 return -EOPNOTSUPP;
Sony Chacko79788452012-12-04 03:33:53 +00001182 if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001183 netdev_warn(dev, "LED test not supported for non "
1184 "privilege function\n");
1185 return -EOPNOTSUPP;
1186 }
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001187
stephen hemminger94469f72011-04-06 11:47:23 +00001188 switch (state) {
1189 case ETHTOOL_ID_ACTIVE:
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001190 if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
1191 return -EBUSY;
1192
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001193 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1194 break;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001195
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001196 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1197 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1198 break;
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001199 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001200 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001201
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001202 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
1203 err = 0;
1204 break;
1205 }
stephen hemminger94469f72011-04-06 11:47:23 +00001206
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001207 dev_err(&adapter->pdev->dev,
1208 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +00001209 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001210
stephen hemminger94469f72011-04-06 11:47:23 +00001211 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001212 active = 0;
1213
1214 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1215 break;
1216
1217 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1218 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1219 break;
1220 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
1221 }
1222
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001223 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
1224 dev_err(&adapter->pdev->dev,
1225 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001226
stephen hemminger94469f72011-04-06 11:47:23 +00001227 break;
1228
1229 default:
1230 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001231 }
1232
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001233 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001234 qlcnic_diag_free_res(dev, max_sds_rings);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001235
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001236 if (!active || err)
1237 clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001238
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001239 return err;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001240}
1241
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001242static void
1243qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1244{
1245 struct qlcnic_adapter *adapter = netdev_priv(dev);
1246 u32 wol_cfg;
1247
Sony Chacko7e38d042013-01-01 03:20:28 +00001248 if (qlcnic_83xx_check(adapter))
1249 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001250 wol->supported = 0;
1251 wol->wolopts = 0;
1252
1253 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1254 if (wol_cfg & (1UL << adapter->portnum))
1255 wol->supported |= WAKE_MAGIC;
1256
1257 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1258 if (wol_cfg & (1UL << adapter->portnum))
1259 wol->wolopts |= WAKE_MAGIC;
1260}
1261
1262static int
1263qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1264{
1265 struct qlcnic_adapter *adapter = netdev_priv(dev);
1266 u32 wol_cfg;
1267
Sony Chacko7e38d042013-01-01 03:20:28 +00001268 if (qlcnic_83xx_check(adapter))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001269 return -EOPNOTSUPP;
Sony Chacko7e38d042013-01-01 03:20:28 +00001270 if (wol->wolopts & ~WAKE_MAGIC)
1271 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001272
1273 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1274 if (!(wol_cfg & (1 << adapter->portnum)))
1275 return -EOPNOTSUPP;
1276
1277 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1278 if (wol->wolopts & WAKE_MAGIC)
1279 wol_cfg |= 1UL << adapter->portnum;
1280 else
1281 wol_cfg &= ~(1UL << adapter->portnum);
1282
1283 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1284
1285 return 0;
1286}
1287
1288/*
1289 * Set the coalescing parameters. Currently only normal is supported.
1290 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1291 * firmware coalescing to default.
1292 */
1293static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1294 struct ethtool_coalesce *ethcoal)
1295{
1296 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1297
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001298 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001299 return -EINVAL;
1300
1301 /*
1302 * Return Error if unsupported values or
1303 * unsupported parameters are set.
1304 */
1305 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1306 ethcoal->rx_max_coalesced_frames > 0xffff ||
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001307 ethcoal->tx_coalesce_usecs ||
1308 ethcoal->tx_max_coalesced_frames ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001309 ethcoal->rx_coalesce_usecs_irq ||
1310 ethcoal->rx_max_coalesced_frames_irq ||
1311 ethcoal->tx_coalesce_usecs_irq ||
1312 ethcoal->tx_max_coalesced_frames_irq ||
1313 ethcoal->stats_block_coalesce_usecs ||
1314 ethcoal->use_adaptive_rx_coalesce ||
1315 ethcoal->use_adaptive_tx_coalesce ||
1316 ethcoal->pkt_rate_low ||
1317 ethcoal->rx_coalesce_usecs_low ||
1318 ethcoal->rx_max_coalesced_frames_low ||
1319 ethcoal->tx_coalesce_usecs_low ||
1320 ethcoal->tx_max_coalesced_frames_low ||
1321 ethcoal->pkt_rate_high ||
1322 ethcoal->rx_coalesce_usecs_high ||
1323 ethcoal->rx_max_coalesced_frames_high ||
1324 ethcoal->tx_coalesce_usecs_high ||
1325 ethcoal->tx_max_coalesced_frames_high)
1326 return -EINVAL;
1327
1328 if (!ethcoal->rx_coalesce_usecs ||
1329 !ethcoal->rx_max_coalesced_frames) {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001330 adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
1331 adapter->ahw->coal.rx_time_us =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001332 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001333 adapter->ahw->coal.rx_packets =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001334 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1335 } else {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001336 adapter->ahw->coal.flag = 0;
1337 adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
1338 adapter->ahw->coal.rx_packets =
1339 ethcoal->rx_max_coalesced_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001340 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001341
1342 qlcnic_config_intr_coalesce(adapter);
1343
1344 return 0;
1345}
1346
1347static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1348 struct ethtool_coalesce *ethcoal)
1349{
1350 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1351
1352 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1353 return -EINVAL;
1354
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001355 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
1356 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001357
1358 return 0;
1359}
1360
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001361static u32 qlcnic_get_msglevel(struct net_device *netdev)
1362{
1363 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1364
Sony Chacko79788452012-12-04 03:33:53 +00001365 return adapter->ahw->msg_enable;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001366}
1367
1368static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1369{
1370 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1371
Sony Chacko79788452012-12-04 03:33:53 +00001372 adapter->ahw->msg_enable = msglvl;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001373}
1374
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001375static int
1376qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1377{
1378 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1379 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1380
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001381 if (!fw_dump->tmpl_hdr) {
1382 netdev_err(adapter->netdev, "FW Dump not supported\n");
1383 return -ENOTSUPP;
1384 }
1385
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001386 if (fw_dump->clr)
1387 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1388 else
1389 dump->len = 0;
Manish choprabcebe552012-05-15 01:13:39 +00001390
1391 if (!fw_dump->enable)
1392 dump->flag = ETH_FW_DUMP_DISABLE;
1393 else
1394 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1395
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001396 dump->version = adapter->fw_version;
1397 return 0;
1398}
1399
1400static int
1401qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1402 void *buffer)
1403{
1404 int i, copy_sz;
Shahed Shaikh63507592012-11-23 23:56:52 +00001405 u32 *hdr_ptr;
1406 __le32 *data;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001407 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1408 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1409
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001410 if (!fw_dump->tmpl_hdr) {
1411 netdev_err(netdev, "FW Dump not supported\n");
1412 return -ENOTSUPP;
1413 }
1414
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001415 if (!fw_dump->clr) {
1416 netdev_info(netdev, "Dump not available\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001417 return -EINVAL;
1418 }
1419 /* Copy template header first */
1420 copy_sz = fw_dump->tmpl_hdr->size;
1421 hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
Joe Perches43d620c2011-06-16 19:08:06 +00001422 data = buffer;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001423 for (i = 0; i < copy_sz/sizeof(u32); i++)
1424 *data++ = cpu_to_le32(*hdr_ptr++);
1425
1426 /* Copy captured dump data */
1427 memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1428 dump->len = copy_sz + fw_dump->size;
1429 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1430
1431 /* Free dump area once data has been captured */
1432 vfree(fw_dump->data);
1433 fw_dump->data = NULL;
1434 fw_dump->clr = 0;
Manish choprac47884e42012-02-03 13:45:44 +00001435 netdev_info(netdev, "extracted the FW dump Successfully\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001436 return 0;
1437}
1438
1439static int
1440qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1441{
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001442 int i;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001443 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1444 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001445 u32 state;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001446
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001447 switch (val->flag) {
1448 case QLCNIC_FORCE_FW_DUMP_KEY:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001449 if (!fw_dump->tmpl_hdr) {
1450 netdev_err(netdev, "FW dump not supported\n");
1451 return -ENOTSUPP;
1452 }
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001453 if (!fw_dump->enable) {
1454 netdev_info(netdev, "FW dump not enabled\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001455 return 0;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001456 }
1457 if (fw_dump->clr) {
Manish choprac47884e42012-02-03 13:45:44 +00001458 netdev_info(netdev,
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001459 "Previous dump not cleared, not forcing dump\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001460 return 0;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001461 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001462 netdev_info(netdev, "Forcing a FW dump\n");
Sony Chacko7e38d042013-01-01 03:20:28 +00001463 qlcnic_dev_request_reset(adapter, val->flag);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001464 break;
1465 case QLCNIC_DISABLE_FW_DUMP:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001466 if (fw_dump->enable && fw_dump->tmpl_hdr) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001467 netdev_info(netdev, "Disabling FW dump\n");
1468 fw_dump->enable = 0;
1469 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001470 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001471 case QLCNIC_ENABLE_FW_DUMP:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001472 if (!fw_dump->tmpl_hdr) {
1473 netdev_err(netdev, "FW dump not supported\n");
1474 return -ENOTSUPP;
1475 }
1476 if (!fw_dump->enable) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001477 netdev_info(netdev, "Enabling FW dump\n");
1478 fw_dump->enable = 1;
1479 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001480 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001481 case QLCNIC_FORCE_FW_RESET:
1482 netdev_info(netdev, "Forcing a FW reset\n");
Sony Chacko7e38d042013-01-01 03:20:28 +00001483 qlcnic_dev_request_reset(adapter, val->flag);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001484 adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001485 return 0;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001486 case QLCNIC_SET_QUIESCENT:
1487 case QLCNIC_RESET_QUIESCENT:
1488 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
1489 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
1490 netdev_info(netdev, "Device in FAILED state\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001491 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001492 default:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001493 if (!fw_dump->tmpl_hdr) {
1494 netdev_err(netdev, "FW dump not supported\n");
1495 return -ENOTSUPP;
1496 }
Sony Chacko7e38d042013-01-01 03:20:28 +00001497 for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
1498 if (val->flag == qlcnic_fw_dump_level[i]) {
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001499 fw_dump->tmpl_hdr->drv_cap_mask =
1500 val->flag;
1501 netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1502 fw_dump->tmpl_hdr->drv_cap_mask);
1503 return 0;
1504 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001505 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001506 netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag);
1507 return -EINVAL;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001508 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001509 return 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001510}
1511
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001512const struct ethtool_ops qlcnic_ethtool_ops = {
1513 .get_settings = qlcnic_get_settings,
1514 .set_settings = qlcnic_set_settings,
1515 .get_drvinfo = qlcnic_get_drvinfo,
1516 .get_regs_len = qlcnic_get_regs_len,
1517 .get_regs = qlcnic_get_regs,
1518 .get_link = ethtool_op_get_link,
1519 .get_eeprom_len = qlcnic_get_eeprom_len,
1520 .get_eeprom = qlcnic_get_eeprom,
1521 .get_ringparam = qlcnic_get_ringparam,
1522 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +00001523 .get_channels = qlcnic_get_channels,
1524 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001525 .get_pauseparam = qlcnic_get_pauseparam,
1526 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001527 .get_wol = qlcnic_get_wol,
1528 .set_wol = qlcnic_set_wol,
1529 .self_test = qlcnic_diag_test,
1530 .get_strings = qlcnic_get_strings,
1531 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1532 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001533 .get_coalesce = qlcnic_get_intr_coalesce,
1534 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +00001535 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001536 .set_msglevel = qlcnic_set_msglevel,
1537 .get_msglevel = qlcnic_get_msglevel,
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001538 .get_dump_flag = qlcnic_get_dump_flag,
1539 .get_dump_data = qlcnic_get_dump_data,
1540 .set_dump = qlcnic_set_dump,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001541};