blob: 064f36b66b3e3988cfa723f226e71ef75a81b160 [file] [log] [blame]
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001/*
Sritej Velaga40839129f2010-12-02 20:41:56 +00002 * QLogic qlcnic NIC Driver
3 * Copyright (c) 2009-2010 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)
25
26static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
27 {"xmit_called",
28 QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
29 {"xmit_finished",
30 QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
31 {"rx_dropped",
32 QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
33 {"tx_dropped",
34 QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
35 {"csummed",
36 QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
37 {"rx_pkts",
38 QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
39 {"lro_pkts",
40 QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
41 {"rx_bytes",
42 QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
43 {"tx_bytes",
44 QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000045 {"lrobytes",
46 QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
47 {"lso_frames",
48 QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
49 {"xmit_on",
50 QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
51 {"xmit_off",
52 QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
53 {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
54 QLC_OFF(stats.skb_alloc_failure)},
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +000055 {"null rxbuf",
56 QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
57 {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
58 QLC_OFF(stats.rx_dma_map_error)},
59 {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
60 QLC_OFF(stats.tx_dma_map_error)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000061
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000062};
63
amit salecha3666e0b2010-10-18 01:47:48 +000064static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
65 "rx unicast frames",
66 "rx multicast frames",
67 "rx broadcast frames",
68 "rx dropped frames",
69 "rx errors",
70 "rx local frames",
71 "rx numbytes",
72 "tx unicast frames",
73 "tx multicast frames",
74 "tx broadcast frames",
75 "tx dropped frames",
76 "tx errors",
77 "tx local frames",
78 "tx numbytes",
79};
80
Jitendra Kalsaria54a89972012-04-26 10:31:30 +000081static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
82 "mac_tx_frames",
83 "mac_tx_bytes",
84 "mac_tx_mcast_pkts",
85 "mac_tx_bcast_pkts",
86 "mac_tx_pause_cnt",
87 "mac_tx_ctrl_pkt",
88 "mac_tx_lt_64b_pkts",
89 "mac_tx_lt_127b_pkts",
90 "mac_tx_lt_255b_pkts",
91 "mac_tx_lt_511b_pkts",
92 "mac_tx_lt_1023b_pkts",
93 "mac_tx_lt_1518b_pkts",
94 "mac_tx_gt_1518b_pkts",
95 "mac_rx_frames",
96 "mac_rx_bytes",
97 "mac_rx_mcast_pkts",
98 "mac_rx_bcast_pkts",
99 "mac_rx_pause_cnt",
100 "mac_rx_ctrl_pkt",
101 "mac_rx_lt_64b_pkts",
102 "mac_rx_lt_127b_pkts",
103 "mac_rx_lt_255b_pkts",
104 "mac_rx_lt_511b_pkts",
105 "mac_rx_lt_1023b_pkts",
106 "mac_rx_lt_1518b_pkts",
107 "mac_rx_gt_1518b_pkts",
108 "mac_rx_length_error",
109 "mac_rx_length_small",
110 "mac_rx_length_large",
111 "mac_rx_jabber",
112 "mac_rx_dropped",
113 "mac_rx_crc_error",
114 "mac_align_error",
115};
116
117#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
118#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)
amit salecha3666e0b2010-10-18 01:47:48 +0000119#define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats)
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000120#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000121
122static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
123 "Register_Test_on_offline",
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000124 "Link_Test_on_offline",
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000125 "Interrupt_Test_offline",
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000126 "Internal_Loopback_offline",
127 "External_Loopback_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000128};
129
130#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
131
132#define QLCNIC_RING_REGS_COUNT 20
133#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
134#define QLCNIC_MAX_EEPROM_LEN 1024
135
136static const u32 diag_registers[] = {
137 CRB_CMDPEG_STATE,
138 CRB_RCVPEG_STATE,
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000139 CRB_XG_STATE_P3P,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000140 CRB_FW_CAPABILITIES_1,
141 ISR_INT_STATE_REG,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000142 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000143 QLCNIC_CRB_DEV_STATE,
144 QLCNIC_CRB_DRV_STATE,
145 QLCNIC_CRB_DRV_SCRATCH,
146 QLCNIC_CRB_DEV_PARTITION_INFO,
147 QLCNIC_CRB_DRV_IDC_VER,
148 QLCNIC_PEG_ALIVE_COUNTER,
149 QLCNIC_PEG_HALT_STATUS1,
150 QLCNIC_PEG_HALT_STATUS2,
151 QLCNIC_CRB_PEG_NET_0+0x3c,
152 QLCNIC_CRB_PEG_NET_1+0x3c,
153 QLCNIC_CRB_PEG_NET_2+0x3c,
154 QLCNIC_CRB_PEG_NET_4+0x3c,
155 -1
156};
157
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000158#define QLCNIC_MGMT_API_VERSION 2
159#define QLCNIC_DEV_INFO_SIZE 1
160#define QLCNIC_ETHTOOL_REGS_VER 2
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000161static int qlcnic_get_regs_len(struct net_device *dev)
162{
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000163 return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
164 QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000165}
166
167static int qlcnic_get_eeprom_len(struct net_device *dev)
168{
169 return QLCNIC_FLASH_TOTAL_SIZE;
170}
171
172static void
173qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
174{
175 struct qlcnic_adapter *adapter = netdev_priv(dev);
176 u32 fw_major, fw_minor, fw_build;
177
178 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
179 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
180 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
Rick Jones68aad782011-11-07 13:29:27 +0000181 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
182 "%d.%d.%d", fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000183
Rick Jones68aad782011-11-07 13:29:27 +0000184 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
185 sizeof(drvinfo->bus_info));
186 strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
187 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
188 sizeof(drvinfo->version));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000189}
190
191static int
192qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
193{
194 struct qlcnic_adapter *adapter = netdev_priv(dev);
195 int check_sfp_module = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000196
197 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000198 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000199 ecmd->supported = (SUPPORTED_10baseT_Half |
200 SUPPORTED_10baseT_Full |
201 SUPPORTED_100baseT_Half |
202 SUPPORTED_100baseT_Full |
203 SUPPORTED_1000baseT_Half |
204 SUPPORTED_1000baseT_Full);
205
206 ecmd->advertising = (ADVERTISED_100baseT_Half |
207 ADVERTISED_100baseT_Full |
208 ADVERTISED_1000baseT_Half |
209 ADVERTISED_1000baseT_Full);
210
Sony Chacko79788452012-12-04 03:33:53 +0000211 ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
212 ecmd->duplex = adapter->ahw->link_duplex;
213 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000214
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000215 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000216 u32 val;
217
218 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
219 if (val == QLCNIC_PORT_MODE_802_3_AP) {
220 ecmd->supported = SUPPORTED_1000baseT_Full;
221 ecmd->advertising = ADVERTISED_1000baseT_Full;
222 } else {
223 ecmd->supported = SUPPORTED_10000baseT_Full;
224 ecmd->advertising = ADVERTISED_10000baseT_Full;
225 }
226
Sony Chacko79788452012-12-04 03:33:53 +0000227 if (netif_running(dev) && adapter->ahw->has_link_events) {
228 ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
229 ecmd->autoneg = adapter->ahw->link_autoneg;
230 ecmd->duplex = adapter->ahw->link_duplex;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000231 goto skip;
232 }
233
Sony Chacko476a4b62012-02-03 13:45:42 +0000234 ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
235 ecmd->duplex = DUPLEX_UNKNOWN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000236 ecmd->autoneg = AUTONEG_DISABLE;
237 } else
238 return -EIO;
239
240skip:
Sony Chacko79788452012-12-04 03:33:53 +0000241 ecmd->phy_address = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000242 ecmd->transceiver = XCVR_EXTERNAL;
243
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000244 switch (adapter->ahw->board_type) {
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000245 case QLCNIC_BRDTYPE_P3P_REF_QG:
246 case QLCNIC_BRDTYPE_P3P_4_GB:
247 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000248
249 ecmd->supported |= SUPPORTED_Autoneg;
250 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000251 case QLCNIC_BRDTYPE_P3P_10G_CX4:
252 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
253 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000254 ecmd->supported |= SUPPORTED_TP;
255 ecmd->advertising |= ADVERTISED_TP;
256 ecmd->port = PORT_TP;
Sony Chacko79788452012-12-04 03:33:53 +0000257 ecmd->autoneg = adapter->ahw->link_autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000258 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000259 case QLCNIC_BRDTYPE_P3P_IMEZ:
260 case QLCNIC_BRDTYPE_P3P_XG_LOM:
261 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000262 ecmd->supported |= SUPPORTED_MII;
263 ecmd->advertising |= ADVERTISED_MII;
264 ecmd->port = PORT_MII;
265 ecmd->autoneg = AUTONEG_DISABLE;
266 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000267 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
268 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
269 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000270 ecmd->advertising |= ADVERTISED_TP;
271 ecmd->supported |= SUPPORTED_TP;
272 check_sfp_module = netif_running(dev) &&
Sony Chacko79788452012-12-04 03:33:53 +0000273 adapter->ahw->has_link_events;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000274 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000275 ecmd->supported |= SUPPORTED_FIBRE;
276 ecmd->advertising |= ADVERTISED_FIBRE;
277 ecmd->port = PORT_FIBRE;
278 ecmd->autoneg = AUTONEG_DISABLE;
279 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000280 case QLCNIC_BRDTYPE_P3P_10G_TP:
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000281 if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000282 ecmd->autoneg = AUTONEG_DISABLE;
283 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
284 ecmd->advertising |=
285 (ADVERTISED_FIBRE | ADVERTISED_TP);
286 ecmd->port = PORT_FIBRE;
287 check_sfp_module = netif_running(dev) &&
Sony Chacko79788452012-12-04 03:33:53 +0000288 adapter->ahw->has_link_events;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000289 } else {
290 ecmd->autoneg = AUTONEG_ENABLE;
291 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
292 ecmd->advertising |=
293 (ADVERTISED_TP | ADVERTISED_Autoneg);
294 ecmd->port = PORT_TP;
295 }
296 break;
297 default:
298 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000299 adapter->ahw->board_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000300 return -EIO;
301 }
302
303 if (check_sfp_module) {
Sony Chacko79788452012-12-04 03:33:53 +0000304 switch (adapter->ahw->module_type) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000305 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
306 case LINKEVENT_MODULE_OPTICAL_SRLR:
307 case LINKEVENT_MODULE_OPTICAL_LRM:
308 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
309 ecmd->port = PORT_FIBRE;
310 break;
311 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
312 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
313 case LINKEVENT_MODULE_TWINAX:
314 ecmd->port = PORT_TP;
315 break;
316 default:
317 ecmd->port = PORT_OTHER;
318 }
319 }
320
321 return 0;
322}
323
324static int
325qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
326{
Sony Chacko7e610ca2011-04-28 11:48:19 +0000327 u32 config = 0;
328 u32 ret = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000329 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e610ca2011-04-28 11:48:19 +0000330
331 if (adapter->ahw->port_type != QLCNIC_GBE)
332 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000333
334 /* read which mode */
Sony Chacko7e610ca2011-04-28 11:48:19 +0000335 if (ecmd->duplex)
336 config |= 0x1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000337
Sony Chacko7e610ca2011-04-28 11:48:19 +0000338 if (ecmd->autoneg)
339 config |= 0x2;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000340
Sony Chacko7e610ca2011-04-28 11:48:19 +0000341 switch (ethtool_cmd_speed(ecmd)) {
342 case SPEED_10:
343 config |= (0 << 8);
344 break;
345 case SPEED_100:
346 config |= (1 << 8);
347 break;
348 case SPEED_1000:
349 config |= (10 << 8);
350 break;
351 default:
352 return -EIO;
353 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000354
Sony Chacko7e610ca2011-04-28 11:48:19 +0000355 ret = qlcnic_fw_cmd_set_port(adapter, config);
356
357 if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000358 return -EOPNOTSUPP;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000359 else if (ret)
360 return -EIO;
361
Sony Chacko79788452012-12-04 03:33:53 +0000362 adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
363 adapter->ahw->link_duplex = ecmd->duplex;
364 adapter->ahw->link_autoneg = ecmd->autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000365
366 if (!netif_running(dev))
367 return 0;
368
369 dev->netdev_ops->ndo_stop(dev);
370 return dev->netdev_ops->ndo_open(dev);
371}
372
373static void
374qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
375{
376 struct qlcnic_adapter *adapter = netdev_priv(dev);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000377 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000378 struct qlcnic_host_sds_ring *sds_ring;
379 u32 *regs_buff = p;
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000380 int ring, i = 0, j = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000381
382 memset(p, 0, qlcnic_get_regs_len(dev));
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000383 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000384 (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000385
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000386 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
387 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
388
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000389 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
390 regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000391
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000392 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000393 return;
394
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000395 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
396
397 regs_buff[i++] = 1; /* No. of tx ring */
398 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
399 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
400
401 regs_buff[i++] = 2; /* No. of rx ring */
402 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
403 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
404
405 regs_buff[i++] = adapter->max_sds_rings;
406
407 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
408 sds_ring = &(recv_ctx->sds_rings[ring]);
409 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
410 }
411}
412
413static u32 qlcnic_test_link(struct net_device *dev)
414{
415 struct qlcnic_adapter *adapter = netdev_priv(dev);
416 u32 val;
417
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000418 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000419 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000420 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000421}
422
423static int
424qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
425 u8 *bytes)
426{
427 struct qlcnic_adapter *adapter = netdev_priv(dev);
428 int offset;
429 int ret;
430
431 if (eeprom->len == 0)
432 return -EINVAL;
433
434 eeprom->magic = (adapter->pdev)->vendor |
435 ((adapter->pdev)->device << 16);
436 offset = eeprom->offset;
437
438 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
439 eeprom->len);
440 if (ret < 0)
441 return ret;
442
443 return 0;
444}
445
446static void
447qlcnic_get_ringparam(struct net_device *dev,
448 struct ethtool_ringparam *ring)
449{
450 struct qlcnic_adapter *adapter = netdev_priv(dev);
451
452 ring->rx_pending = adapter->num_rxd;
453 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000454 ring->tx_pending = adapter->num_txd;
455
Sony Chacko90d19002010-10-26 17:53:08 +0000456 ring->rx_max_pending = adapter->max_rxd;
457 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000458 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000459}
460
461static u32
462qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
463{
464 u32 num_desc;
465 num_desc = max(val, min);
466 num_desc = min(num_desc, max);
467 num_desc = roundup_pow_of_two(num_desc);
468
469 if (val != num_desc) {
470 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
471 qlcnic_driver_name, r_name, num_desc, val);
472 }
473
474 return num_desc;
475}
476
477static int
478qlcnic_set_ringparam(struct net_device *dev,
479 struct ethtool_ringparam *ring)
480{
481 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000482 u16 num_rxd, num_jumbo_rxd, num_txd;
483
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000484 if (ring->rx_mini_pending)
485 return -EOPNOTSUPP;
486
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000487 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000488 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000489
490 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000491 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
492 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000493
494 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
495 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
496
497 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
498 num_jumbo_rxd == adapter->num_jumbo_rxd)
499 return 0;
500
501 adapter->num_rxd = num_rxd;
502 adapter->num_jumbo_rxd = num_jumbo_rxd;
503 adapter->num_txd = num_txd;
504
505 return qlcnic_reset_context(adapter);
506}
507
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000508static void qlcnic_get_channels(struct net_device *dev,
509 struct ethtool_channels *channel)
510{
Sony Chacko79788452012-12-04 03:33:53 +0000511 int min;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000512 struct qlcnic_adapter *adapter = netdev_priv(dev);
513
Sony Chacko79788452012-12-04 03:33:53 +0000514 min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus());
515 channel->max_rx = rounddown_pow_of_two(min);
516 channel->max_tx = adapter->ahw->max_tx_ques;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000517
518 channel->rx_count = adapter->max_sds_rings;
Sony Chacko79788452012-12-04 03:33:53 +0000519 channel->tx_count = adapter->ahw->max_tx_ques;
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000520}
521
522static int qlcnic_set_channels(struct net_device *dev,
523 struct ethtool_channels *channel)
524{
525 struct qlcnic_adapter *adapter = netdev_priv(dev);
526 int err;
527
528 if (channel->other_count || channel->combined_count ||
529 channel->tx_count != channel->max_tx)
530 return -EINVAL;
531
532 err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
533 if (err)
534 return err;
535
536 err = qlcnic_set_max_rss(adapter, channel->rx_count);
537 netdev_info(dev, "allocated 0x%x sds rings\n",
538 adapter->max_sds_rings);
539 return err;
540}
541
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000542static void
543qlcnic_get_pauseparam(struct net_device *netdev,
544 struct ethtool_pauseparam *pause)
545{
546 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000547 int port = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000548 __u32 val;
549
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000550 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000551 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
552 return;
553 /* get flow control settings */
554 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
555 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
556 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
557 switch (port) {
558 case 0:
559 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
560 break;
561 case 1:
562 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
563 break;
564 case 2:
565 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
566 break;
567 case 3:
568 default:
569 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
570 break;
571 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000572 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000573 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
574 return;
575 pause->rx_pause = 1;
576 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
577 if (port == 0)
578 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
579 else
580 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
581 } else {
582 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000583 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000584 }
585}
586
587static int
588qlcnic_set_pauseparam(struct net_device *netdev,
589 struct ethtool_pauseparam *pause)
590{
591 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Sony Chacko79788452012-12-04 03:33:53 +0000592 int port = adapter->ahw->physical_port;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000593 __u32 val;
594
595 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000596 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000597 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
598 return -EIO;
599 /* set flow control */
600 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
601
602 if (pause->rx_pause)
603 qlcnic_gb_rx_flowctl(val);
604 else
605 qlcnic_gb_unset_rx_flowctl(val);
606
607 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
608 val);
609 /* set autoneg */
610 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
611 switch (port) {
612 case 0:
613 if (pause->tx_pause)
614 qlcnic_gb_unset_gb0_mask(val);
615 else
616 qlcnic_gb_set_gb0_mask(val);
617 break;
618 case 1:
619 if (pause->tx_pause)
620 qlcnic_gb_unset_gb1_mask(val);
621 else
622 qlcnic_gb_set_gb1_mask(val);
623 break;
624 case 2:
625 if (pause->tx_pause)
626 qlcnic_gb_unset_gb2_mask(val);
627 else
628 qlcnic_gb_set_gb2_mask(val);
629 break;
630 case 3:
631 default:
632 if (pause->tx_pause)
633 qlcnic_gb_unset_gb3_mask(val);
634 else
635 qlcnic_gb_set_gb3_mask(val);
636 break;
637 }
638 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000639 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000640 if (!pause->rx_pause || pause->autoneg)
641 return -EOPNOTSUPP;
642
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000643 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
644 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000645
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000646 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
647 if (port == 0) {
648 if (pause->tx_pause)
649 qlcnic_xg_unset_xg0_mask(val);
650 else
651 qlcnic_xg_set_xg0_mask(val);
652 } else {
653 if (pause->tx_pause)
654 qlcnic_xg_unset_xg1_mask(val);
655 else
656 qlcnic_xg_set_xg1_mask(val);
657 }
658 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
659 } else {
660 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000661 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000662 }
663 return 0;
664}
665
666static int qlcnic_reg_test(struct net_device *dev)
667{
668 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000669 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000670
671 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
672 if ((data_read & 0xffff) != adapter->pdev->vendor)
673 return 1;
674
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000675 return 0;
676}
677
678static int qlcnic_get_sset_count(struct net_device *dev, int sset)
679{
amit salecha3666e0b2010-10-18 01:47:48 +0000680 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000681 switch (sset) {
682 case ETH_SS_TEST:
683 return QLCNIC_TEST_LEN;
684 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000685 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000686 return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
687 return QLCNIC_TOTAL_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000688 default:
689 return -EOPNOTSUPP;
690 }
691}
692
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000693static int qlcnic_irq_test(struct net_device *netdev)
694{
695 struct qlcnic_adapter *adapter = netdev_priv(netdev);
696 int max_sds_rings = adapter->max_sds_rings;
697 int ret;
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000698 struct qlcnic_cmd_args cmd;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000699
700 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
701 return -EIO;
702
703 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
704 if (ret)
705 goto clear_it;
706
Sony Chacko79788452012-12-04 03:33:53 +0000707 adapter->ahw->diag_cnt = 0;
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000708 qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
709
710 cmd.req.arg[1] = adapter->ahw->pci_func;
711 ret = qlcnic_issue_cmd(adapter, &cmd);
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000712
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000713 if (ret)
714 goto done;
715
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000716 usleep_range(1000, 12000);
Sony Chacko79788452012-12-04 03:33:53 +0000717 ret = !adapter->ahw->diag_cnt;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000718
719done:
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000720 qlcnic_free_mbx_args(&cmd);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000721 qlcnic_diag_free_res(netdev, max_sds_rings);
722
723clear_it:
724 adapter->max_sds_rings = max_sds_rings;
725 clear_bit(__QLCNIC_RESETTING, &adapter->state);
726 return ret;
727}
728
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000729#define QLCNIC_ILB_PKT_SIZE 64
730#define QLCNIC_NUM_ILB_PKT 16
731#define QLCNIC_ILB_MAX_RCV_LOOP 10
732
733static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
734{
735 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
736
737 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
738
739 memcpy(data, mac, ETH_ALEN);
740 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
741
742 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
743}
744
745int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
746{
747 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
748 qlcnic_create_loopback_buff(buff, mac);
749 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
750}
751
Manish chopradf3cfbe2011-08-29 12:50:27 +0000752static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000753{
754 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
755 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
756 struct sk_buff *skb;
757 int i, loop, cnt = 0;
758
759 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
Pradeep A. Dalvidae2e9f2012-02-06 11:16:13 +0000760 skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000761 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
762 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
763
Sony Chacko79788452012-12-04 03:33:53 +0000764 adapter->ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000765 qlcnic_xmit_frame(skb, adapter->netdev);
766
767 loop = 0;
768 do {
769 msleep(1);
770 qlcnic_process_rcv_ring_diag(sds_ring);
771 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
772 break;
Sony Chacko79788452012-12-04 03:33:53 +0000773 } while (!adapter->ahw->diag_cnt);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000774
775 dev_kfree_skb_any(skb);
776
Sony Chacko79788452012-12-04 03:33:53 +0000777 if (!adapter->ahw->diag_cnt)
Manish chopradf3cfbe2011-08-29 12:50:27 +0000778 QLCDB(adapter, DRV,
779 "LB Test: packet #%d was not received\n", i + 1);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000780 else
781 cnt++;
782 }
783 if (cnt != i) {
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000784 dev_warn(&adapter->pdev->dev, "LB Test failed\n");
Manish chopradf3cfbe2011-08-29 12:50:27 +0000785 if (mode != QLCNIC_ILB_MODE) {
786 dev_warn(&adapter->pdev->dev,
787 "WARNING: Please make sure external"
788 "loopback connector is plugged in\n");
789 }
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000790 return -1;
791 }
792 return 0;
793}
794
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000795static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000796{
797 struct qlcnic_adapter *adapter = netdev_priv(netdev);
798 int max_sds_rings = adapter->max_sds_rings;
799 struct qlcnic_host_sds_ring *sds_ring;
800 int loop = 0;
801 int ret;
802
Sony Chacko79788452012-12-04 03:33:53 +0000803 if (!(adapter->ahw->capabilities &
804 QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000805 netdev_info(netdev, "Firmware is not loopback test capable\n");
806 return -EOPNOTSUPP;
807 }
808
Manish chopradf3cfbe2011-08-29 12:50:27 +0000809 QLCDB(adapter, DRV, "%s loopback test in progress\n",
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000810 mode == QLCNIC_ILB_MODE ? "internal" : "external");
Sony Chacko79788452012-12-04 03:33:53 +0000811 if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000812 netdev_warn(netdev, "Loopback test not supported for non "
813 "privilege function\n");
814 return 0;
815 }
816
817 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000818 return -EBUSY;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000819
820 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
821 if (ret)
822 goto clear_it;
823
824 sds_ring = &adapter->recv_ctx->sds_rings[0];
825
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000826 ret = qlcnic_set_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000827 if (ret)
828 goto free_res;
829
Sony Chacko79788452012-12-04 03:33:53 +0000830 adapter->ahw->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000831 do {
832 msleep(500);
833 qlcnic_process_rcv_ring_diag(sds_ring);
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000834 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
835 netdev_info(netdev, "firmware didnt respond to loopback"
836 " configure request\n");
837 ret = -QLCNIC_FW_NOT_RESPOND;
838 goto free_res;
Sony Chacko79788452012-12-04 03:33:53 +0000839 } else if (adapter->ahw->diag_cnt) {
840 ret = adapter->ahw->diag_cnt;
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000841 goto free_res;
842 }
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000843 } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
844
Manish chopradf3cfbe2011-08-29 12:50:27 +0000845 ret = qlcnic_do_lb_test(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000846
Sony Chacko7e2cf4f2013-01-01 03:20:17 +0000847 qlcnic_clear_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000848
849 free_res:
850 qlcnic_diag_free_res(netdev, max_sds_rings);
851
852 clear_it:
853 adapter->max_sds_rings = max_sds_rings;
854 clear_bit(__QLCNIC_RESETTING, &adapter->state);
855 return ret;
856}
857
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000858static void
859qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
860 u64 *data)
861{
862 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000863
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000864 data[0] = qlcnic_reg_test(dev);
865 if (data[0])
866 eth_test->flags |= ETH_TEST_FL_FAILED;
867
868 data[1] = (u64) qlcnic_test_link(dev);
869 if (data[1])
870 eth_test->flags |= ETH_TEST_FL_FAILED;
871
Sony Chacko13b93ed2011-01-10 00:15:22 +0000872 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000873 data[2] = qlcnic_irq_test(dev);
874 if (data[2])
875 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000876
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000877 data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000878 if (data[3])
879 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000880 if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
881 data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
882 if (data[4])
883 eth_test->flags |= ETH_TEST_FL_FAILED;
884 eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
885 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000886 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000887}
888
889static void
890qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
891{
amit salecha3666e0b2010-10-18 01:47:48 +0000892 struct qlcnic_adapter *adapter = netdev_priv(dev);
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000893 int index, i, j;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000894
895 switch (stringset) {
896 case ETH_SS_TEST:
897 memcpy(data, *qlcnic_gstrings_test,
898 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
899 break;
900 case ETH_SS_STATS:
901 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
902 memcpy(data + index * ETH_GSTRING_LEN,
903 qlcnic_gstrings_stats[index].stat_string,
904 ETH_GSTRING_LEN);
905 }
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000906 for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) {
907 memcpy(data + index * ETH_GSTRING_LEN,
908 qlcnic_mac_stats_strings[j],
909 ETH_GSTRING_LEN);
910 }
amit salecha3666e0b2010-10-18 01:47:48 +0000911 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
912 return;
913 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
914 memcpy(data + index * ETH_GSTRING_LEN,
915 qlcnic_device_gstrings_stats[i],
916 ETH_GSTRING_LEN);
917 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000918 }
919}
920
amit salecha3666e0b2010-10-18 01:47:48 +0000921static void
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000922qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
amit salecha3666e0b2010-10-18 01:47:48 +0000923{
924 int ind = *index;
925
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000926 if (type == QLCNIC_MAC_STATS) {
927 struct qlcnic_mac_statistics *mac_stats =
928 (struct qlcnic_mac_statistics *)stats;
929 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
930 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
931 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
932 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
933 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
934 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
935 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
936 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
937 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
938 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
939 data[ind++] =
940 QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
941 data[ind++] =
942 QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
943 data[ind++] =
944 QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
945 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
946 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
947 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
948 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
949 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
950 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
951 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
952 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
953 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
954 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
955 data[ind++] =
956 QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
957 data[ind++] =
958 QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
959 data[ind++] =
960 QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
961 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
962 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
963 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
964 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
965 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
966 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
967 data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
968 } else if (type == QLCNIC_ESW_STATS) {
969 struct __qlcnic_esw_statistics *esw_stats =
970 (struct __qlcnic_esw_statistics *)stats;
971 data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
972 data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
973 data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
974 data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
975 data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors);
976 data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames);
977 data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes);
978 }
amit salecha3666e0b2010-10-18 01:47:48 +0000979
980 *index = ind;
981}
982
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000983static void
984qlcnic_get_ethtool_stats(struct net_device *dev,
985 struct ethtool_stats *stats, u64 * data)
986{
987 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000988 struct qlcnic_esw_statistics port_stats;
Jitendra Kalsaria54a89972012-04-26 10:31:30 +0000989 struct qlcnic_mac_statistics mac_stats;
amit salecha3666e0b2010-10-18 01:47:48 +0000990 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000991
992 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
993 char *p =
994 (char *)adapter +
995 qlcnic_gstrings_stats[index].stat_offset;
996 data[index] =
997 (qlcnic_gstrings_stats[index].sizeof_stat ==
998 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
999 }
amit salecha3666e0b2010-10-18 01:47:48 +00001000
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001001 /* Retrieve MAC statistics from firmware */
1002 memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
1003 qlcnic_get_mac_stats(adapter, &mac_stats);
1004 qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS);
1005
amit salecha3666e0b2010-10-18 01:47:48 +00001006 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
1007 return;
1008
1009 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001010 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001011 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
1012 if (ret)
1013 return;
1014
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001015 qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);
amit salecha3666e0b2010-10-18 01:47:48 +00001016
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +00001017 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +00001018 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
1019 if (ret)
1020 return;
1021
Jitendra Kalsaria54a89972012-04-26 10:31:30 +00001022 qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001023}
1024
stephen hemminger94469f72011-04-06 11:47:23 +00001025static int qlcnic_set_led(struct net_device *dev,
1026 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001027{
1028 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001029 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001030 int err = -EIO, active = 1;
1031
Sony Chacko79788452012-12-04 03:33:53 +00001032 if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001033 netdev_warn(dev, "LED test not supported for non "
1034 "privilege function\n");
1035 return -EOPNOTSUPP;
1036 }
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001037
stephen hemminger94469f72011-04-06 11:47:23 +00001038 switch (state) {
1039 case ETHTOOL_ID_ACTIVE:
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001040 if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
1041 return -EBUSY;
1042
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001043 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1044 break;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001045
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001046 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1047 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1048 break;
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001049 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001050 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001051
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001052 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
1053 err = 0;
1054 break;
1055 }
stephen hemminger94469f72011-04-06 11:47:23 +00001056
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001057 dev_err(&adapter->pdev->dev,
1058 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +00001059 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001060
stephen hemminger94469f72011-04-06 11:47:23 +00001061 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001062 active = 0;
1063
1064 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1065 break;
1066
1067 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1068 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
1069 break;
1070 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
1071 }
1072
Sucheta Chakraborty89b42082011-04-27 14:43:44 +00001073 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
1074 dev_err(&adapter->pdev->dev,
1075 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001076
stephen hemminger94469f72011-04-06 11:47:23 +00001077 break;
1078
1079 default:
1080 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001081 }
1082
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001083 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001084 qlcnic_diag_free_res(dev, max_sds_rings);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +00001085
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001086 if (!active || err)
1087 clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +00001088
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +00001089 return err;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001090}
1091
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001092static void
1093qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1094{
1095 struct qlcnic_adapter *adapter = netdev_priv(dev);
1096 u32 wol_cfg;
1097
1098 wol->supported = 0;
1099 wol->wolopts = 0;
1100
1101 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1102 if (wol_cfg & (1UL << adapter->portnum))
1103 wol->supported |= WAKE_MAGIC;
1104
1105 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1106 if (wol_cfg & (1UL << adapter->portnum))
1107 wol->wolopts |= WAKE_MAGIC;
1108}
1109
1110static int
1111qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1112{
1113 struct qlcnic_adapter *adapter = netdev_priv(dev);
1114 u32 wol_cfg;
1115
1116 if (wol->wolopts & ~WAKE_MAGIC)
1117 return -EOPNOTSUPP;
1118
1119 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1120 if (!(wol_cfg & (1 << adapter->portnum)))
1121 return -EOPNOTSUPP;
1122
1123 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1124 if (wol->wolopts & WAKE_MAGIC)
1125 wol_cfg |= 1UL << adapter->portnum;
1126 else
1127 wol_cfg &= ~(1UL << adapter->portnum);
1128
1129 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1130
1131 return 0;
1132}
1133
1134/*
1135 * Set the coalescing parameters. Currently only normal is supported.
1136 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1137 * firmware coalescing to default.
1138 */
1139static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1140 struct ethtool_coalesce *ethcoal)
1141{
1142 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1143
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001144 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001145 return -EINVAL;
1146
1147 /*
1148 * Return Error if unsupported values or
1149 * unsupported parameters are set.
1150 */
1151 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1152 ethcoal->rx_max_coalesced_frames > 0xffff ||
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001153 ethcoal->tx_coalesce_usecs ||
1154 ethcoal->tx_max_coalesced_frames ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001155 ethcoal->rx_coalesce_usecs_irq ||
1156 ethcoal->rx_max_coalesced_frames_irq ||
1157 ethcoal->tx_coalesce_usecs_irq ||
1158 ethcoal->tx_max_coalesced_frames_irq ||
1159 ethcoal->stats_block_coalesce_usecs ||
1160 ethcoal->use_adaptive_rx_coalesce ||
1161 ethcoal->use_adaptive_tx_coalesce ||
1162 ethcoal->pkt_rate_low ||
1163 ethcoal->rx_coalesce_usecs_low ||
1164 ethcoal->rx_max_coalesced_frames_low ||
1165 ethcoal->tx_coalesce_usecs_low ||
1166 ethcoal->tx_max_coalesced_frames_low ||
1167 ethcoal->pkt_rate_high ||
1168 ethcoal->rx_coalesce_usecs_high ||
1169 ethcoal->rx_max_coalesced_frames_high ||
1170 ethcoal->tx_coalesce_usecs_high ||
1171 ethcoal->tx_max_coalesced_frames_high)
1172 return -EINVAL;
1173
1174 if (!ethcoal->rx_coalesce_usecs ||
1175 !ethcoal->rx_max_coalesced_frames) {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001176 adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
1177 adapter->ahw->coal.rx_time_us =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001178 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001179 adapter->ahw->coal.rx_packets =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001180 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1181 } else {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001182 adapter->ahw->coal.flag = 0;
1183 adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
1184 adapter->ahw->coal.rx_packets =
1185 ethcoal->rx_max_coalesced_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001186 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001187
1188 qlcnic_config_intr_coalesce(adapter);
1189
1190 return 0;
1191}
1192
1193static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1194 struct ethtool_coalesce *ethcoal)
1195{
1196 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1197
1198 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1199 return -EINVAL;
1200
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001201 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
1202 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001203
1204 return 0;
1205}
1206
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001207static u32 qlcnic_get_msglevel(struct net_device *netdev)
1208{
1209 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1210
Sony Chacko79788452012-12-04 03:33:53 +00001211 return adapter->ahw->msg_enable;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001212}
1213
1214static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1215{
1216 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1217
Sony Chacko79788452012-12-04 03:33:53 +00001218 adapter->ahw->msg_enable = msglvl;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001219}
1220
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001221static int
1222qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1223{
1224 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1225 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1226
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001227 if (!fw_dump->tmpl_hdr) {
1228 netdev_err(adapter->netdev, "FW Dump not supported\n");
1229 return -ENOTSUPP;
1230 }
1231
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001232 if (fw_dump->clr)
1233 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1234 else
1235 dump->len = 0;
Manish choprabcebe552012-05-15 01:13:39 +00001236
1237 if (!fw_dump->enable)
1238 dump->flag = ETH_FW_DUMP_DISABLE;
1239 else
1240 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1241
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001242 dump->version = adapter->fw_version;
1243 return 0;
1244}
1245
1246static int
1247qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1248 void *buffer)
1249{
1250 int i, copy_sz;
Shahed Shaikh63507592012-11-23 23:56:52 +00001251 u32 *hdr_ptr;
1252 __le32 *data;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001253 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1254 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1255
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001256 if (!fw_dump->tmpl_hdr) {
1257 netdev_err(netdev, "FW Dump not supported\n");
1258 return -ENOTSUPP;
1259 }
1260
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001261 if (!fw_dump->clr) {
1262 netdev_info(netdev, "Dump not available\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001263 return -EINVAL;
1264 }
1265 /* Copy template header first */
1266 copy_sz = fw_dump->tmpl_hdr->size;
1267 hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
Joe Perches43d620c2011-06-16 19:08:06 +00001268 data = buffer;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001269 for (i = 0; i < copy_sz/sizeof(u32); i++)
1270 *data++ = cpu_to_le32(*hdr_ptr++);
1271
1272 /* Copy captured dump data */
1273 memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1274 dump->len = copy_sz + fw_dump->size;
1275 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1276
1277 /* Free dump area once data has been captured */
1278 vfree(fw_dump->data);
1279 fw_dump->data = NULL;
1280 fw_dump->clr = 0;
Manish choprac47884e42012-02-03 13:45:44 +00001281 netdev_info(netdev, "extracted the FW dump Successfully\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001282 return 0;
1283}
1284
1285static int
1286qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1287{
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001288 int i;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001289 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1290 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001291 u32 state;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001292
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001293 switch (val->flag) {
1294 case QLCNIC_FORCE_FW_DUMP_KEY:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001295 if (!fw_dump->tmpl_hdr) {
1296 netdev_err(netdev, "FW dump not supported\n");
1297 return -ENOTSUPP;
1298 }
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001299 if (!fw_dump->enable) {
1300 netdev_info(netdev, "FW dump not enabled\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001301 return 0;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001302 }
1303 if (fw_dump->clr) {
Manish choprac47884e42012-02-03 13:45:44 +00001304 netdev_info(netdev,
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001305 "Previous dump not cleared, not forcing dump\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001306 return 0;
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001307 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001308 netdev_info(netdev, "Forcing a FW dump\n");
Sony Chacko7e2cf4f2013-01-01 03:20:17 +00001309 qlcnic_dev_request_reset(adapter, 0);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001310 break;
1311 case QLCNIC_DISABLE_FW_DUMP:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001312 if (fw_dump->enable && fw_dump->tmpl_hdr) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001313 netdev_info(netdev, "Disabling FW dump\n");
1314 fw_dump->enable = 0;
1315 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001316 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001317 case QLCNIC_ENABLE_FW_DUMP:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001318 if (!fw_dump->tmpl_hdr) {
1319 netdev_err(netdev, "FW dump not supported\n");
1320 return -ENOTSUPP;
1321 }
1322 if (!fw_dump->enable) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001323 netdev_info(netdev, "Enabling FW dump\n");
1324 fw_dump->enable = 1;
1325 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001326 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001327 case QLCNIC_FORCE_FW_RESET:
1328 netdev_info(netdev, "Forcing a FW reset\n");
Sony Chacko7e2cf4f2013-01-01 03:20:17 +00001329 qlcnic_dev_request_reset(adapter, 0);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001330 adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001331 return 0;
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001332 case QLCNIC_SET_QUIESCENT:
1333 case QLCNIC_RESET_QUIESCENT:
1334 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
1335 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
1336 netdev_info(netdev, "Device in FAILED state\n");
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001337 return 0;
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001338 default:
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001339 if (!fw_dump->tmpl_hdr) {
1340 netdev_err(netdev, "FW dump not supported\n");
1341 return -ENOTSUPP;
1342 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001343 for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
1344 if (val->flag == FW_DUMP_LEVELS[i]) {
1345 fw_dump->tmpl_hdr->drv_cap_mask =
1346 val->flag;
1347 netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1348 fw_dump->tmpl_hdr->drv_cap_mask);
1349 return 0;
1350 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001351 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001352 netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag);
1353 return -EINVAL;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001354 }
Manish Chopra4fbec4d2012-04-26 10:31:31 +00001355 return 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001356}
1357
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001358const struct ethtool_ops qlcnic_ethtool_ops = {
1359 .get_settings = qlcnic_get_settings,
1360 .set_settings = qlcnic_set_settings,
1361 .get_drvinfo = qlcnic_get_drvinfo,
1362 .get_regs_len = qlcnic_get_regs_len,
1363 .get_regs = qlcnic_get_regs,
1364 .get_link = ethtool_op_get_link,
1365 .get_eeprom_len = qlcnic_get_eeprom_len,
1366 .get_eeprom = qlcnic_get_eeprom,
1367 .get_ringparam = qlcnic_get_ringparam,
1368 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +00001369 .get_channels = qlcnic_get_channels,
1370 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001371 .get_pauseparam = qlcnic_get_pauseparam,
1372 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001373 .get_wol = qlcnic_get_wol,
1374 .set_wol = qlcnic_set_wol,
1375 .self_test = qlcnic_diag_test,
1376 .get_strings = qlcnic_get_strings,
1377 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1378 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001379 .get_coalesce = qlcnic_get_intr_coalesce,
1380 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +00001381 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001382 .set_msglevel = qlcnic_set_msglevel,
1383 .get_msglevel = qlcnic_get_msglevel,
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001384 .get_dump_flag = qlcnic_get_dump_flag,
1385 .get_dump_data = qlcnic_get_dump_data,
1386 .set_dump = qlcnic_set_dump,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001387};
Sucheta Chakrabortyb43e5ee2012-04-26 10:31:29 +00001388
1389const struct ethtool_ops qlcnic_ethtool_failed_ops = {
1390 .get_settings = qlcnic_get_settings,
1391 .get_drvinfo = qlcnic_get_drvinfo,
1392 .set_msglevel = qlcnic_set_msglevel,
1393 .get_msglevel = qlcnic_get_msglevel,
1394};