blob: 743035e4538de7f6eb9a41f052d7e900e852a2ce [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
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000081#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
amit salecha3666e0b2010-10-18 01:47:48 +000082#define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000083
84static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
85 "Register_Test_on_offline",
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +000086 "Link_Test_on_offline",
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +000087 "Interrupt_Test_offline",
88 "Loopback_Test_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000089};
90
91#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
92
93#define QLCNIC_RING_REGS_COUNT 20
94#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
95#define QLCNIC_MAX_EEPROM_LEN 1024
96
97static const u32 diag_registers[] = {
98 CRB_CMDPEG_STATE,
99 CRB_RCVPEG_STATE,
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000100 CRB_XG_STATE_P3P,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000101 CRB_FW_CAPABILITIES_1,
102 ISR_INT_STATE_REG,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000103 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000104 QLCNIC_CRB_DEV_STATE,
105 QLCNIC_CRB_DRV_STATE,
106 QLCNIC_CRB_DRV_SCRATCH,
107 QLCNIC_CRB_DEV_PARTITION_INFO,
108 QLCNIC_CRB_DRV_IDC_VER,
109 QLCNIC_PEG_ALIVE_COUNTER,
110 QLCNIC_PEG_HALT_STATUS1,
111 QLCNIC_PEG_HALT_STATUS2,
112 QLCNIC_CRB_PEG_NET_0+0x3c,
113 QLCNIC_CRB_PEG_NET_1+0x3c,
114 QLCNIC_CRB_PEG_NET_2+0x3c,
115 QLCNIC_CRB_PEG_NET_4+0x3c,
116 -1
117};
118
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000119#define QLCNIC_MGMT_API_VERSION 2
120#define QLCNIC_DEV_INFO_SIZE 1
121#define QLCNIC_ETHTOOL_REGS_VER 2
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000122static int qlcnic_get_regs_len(struct net_device *dev)
123{
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000124 return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
125 QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000126}
127
128static int qlcnic_get_eeprom_len(struct net_device *dev)
129{
130 return QLCNIC_FLASH_TOTAL_SIZE;
131}
132
133static void
134qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
135{
136 struct qlcnic_adapter *adapter = netdev_priv(dev);
137 u32 fw_major, fw_minor, fw_build;
138
139 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
140 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
141 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
142 sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
143
144 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
145 strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
146 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
147}
148
149static int
150qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
151{
152 struct qlcnic_adapter *adapter = netdev_priv(dev);
153 int check_sfp_module = 0;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000154 u16 pcifn = adapter->ahw->pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000155
156 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000157 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000158 ecmd->supported = (SUPPORTED_10baseT_Half |
159 SUPPORTED_10baseT_Full |
160 SUPPORTED_100baseT_Half |
161 SUPPORTED_100baseT_Full |
162 SUPPORTED_1000baseT_Half |
163 SUPPORTED_1000baseT_Full);
164
165 ecmd->advertising = (ADVERTISED_100baseT_Half |
166 ADVERTISED_100baseT_Full |
167 ADVERTISED_1000baseT_Half |
168 ADVERTISED_1000baseT_Full);
169
David Decotigny70739492011-04-27 18:32:40 +0000170 ethtool_cmd_speed_set(ecmd, adapter->link_speed);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000171 ecmd->duplex = adapter->link_duplex;
172 ecmd->autoneg = adapter->link_autoneg;
173
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000174 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000175 u32 val;
176
177 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
178 if (val == QLCNIC_PORT_MODE_802_3_AP) {
179 ecmd->supported = SUPPORTED_1000baseT_Full;
180 ecmd->advertising = ADVERTISED_1000baseT_Full;
181 } else {
182 ecmd->supported = SUPPORTED_10000baseT_Full;
183 ecmd->advertising = ADVERTISED_10000baseT_Full;
184 }
185
186 if (netif_running(dev) && adapter->has_link_events) {
David Decotigny70739492011-04-27 18:32:40 +0000187 ethtool_cmd_speed_set(ecmd, adapter->link_speed);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000188 ecmd->autoneg = adapter->link_autoneg;
189 ecmd->duplex = adapter->link_duplex;
190 goto skip;
191 }
192
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000193 val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
David Decotigny70739492011-04-27 18:32:40 +0000194 ethtool_cmd_speed_set(ecmd, P3P_LINK_SPEED_MHZ *
195 P3P_LINK_SPEED_VAL(pcifn, val));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000196 ecmd->duplex = DUPLEX_FULL;
197 ecmd->autoneg = AUTONEG_DISABLE;
198 } else
199 return -EIO;
200
201skip:
202 ecmd->phy_address = adapter->physical_port;
203 ecmd->transceiver = XCVR_EXTERNAL;
204
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000205 switch (adapter->ahw->board_type) {
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000206 case QLCNIC_BRDTYPE_P3P_REF_QG:
207 case QLCNIC_BRDTYPE_P3P_4_GB:
208 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000209
210 ecmd->supported |= SUPPORTED_Autoneg;
211 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000212 case QLCNIC_BRDTYPE_P3P_10G_CX4:
213 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
214 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000215 ecmd->supported |= SUPPORTED_TP;
216 ecmd->advertising |= ADVERTISED_TP;
217 ecmd->port = PORT_TP;
218 ecmd->autoneg = adapter->link_autoneg;
219 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000220 case QLCNIC_BRDTYPE_P3P_IMEZ:
221 case QLCNIC_BRDTYPE_P3P_XG_LOM:
222 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000223 ecmd->supported |= SUPPORTED_MII;
224 ecmd->advertising |= ADVERTISED_MII;
225 ecmd->port = PORT_MII;
226 ecmd->autoneg = AUTONEG_DISABLE;
227 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000228 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
229 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
230 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000231 ecmd->advertising |= ADVERTISED_TP;
232 ecmd->supported |= SUPPORTED_TP;
233 check_sfp_module = netif_running(dev) &&
234 adapter->has_link_events;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000235 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000236 ecmd->supported |= SUPPORTED_FIBRE;
237 ecmd->advertising |= ADVERTISED_FIBRE;
238 ecmd->port = PORT_FIBRE;
239 ecmd->autoneg = AUTONEG_DISABLE;
240 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000241 case QLCNIC_BRDTYPE_P3P_10G_TP:
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000242 if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000243 ecmd->autoneg = AUTONEG_DISABLE;
244 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
245 ecmd->advertising |=
246 (ADVERTISED_FIBRE | ADVERTISED_TP);
247 ecmd->port = PORT_FIBRE;
248 check_sfp_module = netif_running(dev) &&
249 adapter->has_link_events;
250 } else {
251 ecmd->autoneg = AUTONEG_ENABLE;
252 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
253 ecmd->advertising |=
254 (ADVERTISED_TP | ADVERTISED_Autoneg);
255 ecmd->port = PORT_TP;
256 }
257 break;
258 default:
259 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000260 adapter->ahw->board_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000261 return -EIO;
262 }
263
264 if (check_sfp_module) {
265 switch (adapter->module_type) {
266 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
267 case LINKEVENT_MODULE_OPTICAL_SRLR:
268 case LINKEVENT_MODULE_OPTICAL_LRM:
269 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
270 ecmd->port = PORT_FIBRE;
271 break;
272 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
273 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
274 case LINKEVENT_MODULE_TWINAX:
275 ecmd->port = PORT_TP;
276 break;
277 default:
278 ecmd->port = PORT_OTHER;
279 }
280 }
281
282 return 0;
283}
284
285static int
286qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
287{
Sony Chacko7e610ca2011-04-28 11:48:19 +0000288 u32 config = 0;
289 u32 ret = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000290 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e610ca2011-04-28 11:48:19 +0000291
292 if (adapter->ahw->port_type != QLCNIC_GBE)
293 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000294
295 /* read which mode */
Sony Chacko7e610ca2011-04-28 11:48:19 +0000296 if (ecmd->duplex)
297 config |= 0x1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000298
Sony Chacko7e610ca2011-04-28 11:48:19 +0000299 if (ecmd->autoneg)
300 config |= 0x2;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000301
Sony Chacko7e610ca2011-04-28 11:48:19 +0000302 switch (ethtool_cmd_speed(ecmd)) {
303 case SPEED_10:
304 config |= (0 << 8);
305 break;
306 case SPEED_100:
307 config |= (1 << 8);
308 break;
309 case SPEED_1000:
310 config |= (10 << 8);
311 break;
312 default:
313 return -EIO;
314 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000315
Sony Chacko7e610ca2011-04-28 11:48:19 +0000316 ret = qlcnic_fw_cmd_set_port(adapter, config);
317
318 if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000319 return -EOPNOTSUPP;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000320 else if (ret)
321 return -EIO;
322
323 adapter->link_speed = ethtool_cmd_speed(ecmd);
324 adapter->link_duplex = ecmd->duplex;
325 adapter->link_autoneg = ecmd->autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000326
327 if (!netif_running(dev))
328 return 0;
329
330 dev->netdev_ops->ndo_stop(dev);
331 return dev->netdev_ops->ndo_open(dev);
332}
333
334static void
335qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
336{
337 struct qlcnic_adapter *adapter = netdev_priv(dev);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000338 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000339 struct qlcnic_host_sds_ring *sds_ring;
340 u32 *regs_buff = p;
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000341 int ring, i = 0, j = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000342
343 memset(p, 0, qlcnic_get_regs_len(dev));
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000344 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000345 (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000346
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000347 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
348 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
349
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000350 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
351 regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000352
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000353 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000354 return;
355
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000356 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
357
358 regs_buff[i++] = 1; /* No. of tx ring */
359 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
360 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
361
362 regs_buff[i++] = 2; /* No. of rx ring */
363 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
364 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
365
366 regs_buff[i++] = adapter->max_sds_rings;
367
368 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
369 sds_ring = &(recv_ctx->sds_rings[ring]);
370 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
371 }
372}
373
374static u32 qlcnic_test_link(struct net_device *dev)
375{
376 struct qlcnic_adapter *adapter = netdev_priv(dev);
377 u32 val;
378
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000379 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000380 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000381 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000382}
383
384static int
385qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
386 u8 *bytes)
387{
388 struct qlcnic_adapter *adapter = netdev_priv(dev);
389 int offset;
390 int ret;
391
392 if (eeprom->len == 0)
393 return -EINVAL;
394
395 eeprom->magic = (adapter->pdev)->vendor |
396 ((adapter->pdev)->device << 16);
397 offset = eeprom->offset;
398
399 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
400 eeprom->len);
401 if (ret < 0)
402 return ret;
403
404 return 0;
405}
406
407static void
408qlcnic_get_ringparam(struct net_device *dev,
409 struct ethtool_ringparam *ring)
410{
411 struct qlcnic_adapter *adapter = netdev_priv(dev);
412
413 ring->rx_pending = adapter->num_rxd;
414 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000415 ring->tx_pending = adapter->num_txd;
416
Sony Chacko90d19002010-10-26 17:53:08 +0000417 ring->rx_max_pending = adapter->max_rxd;
418 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000419 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
420
421 ring->rx_mini_max_pending = 0;
422 ring->rx_mini_pending = 0;
423}
424
425static u32
426qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
427{
428 u32 num_desc;
429 num_desc = max(val, min);
430 num_desc = min(num_desc, max);
431 num_desc = roundup_pow_of_two(num_desc);
432
433 if (val != num_desc) {
434 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
435 qlcnic_driver_name, r_name, num_desc, val);
436 }
437
438 return num_desc;
439}
440
441static int
442qlcnic_set_ringparam(struct net_device *dev,
443 struct ethtool_ringparam *ring)
444{
445 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000446 u16 num_rxd, num_jumbo_rxd, num_txd;
447
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000448 if (ring->rx_mini_pending)
449 return -EOPNOTSUPP;
450
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000451 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000452 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000453
454 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000455 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
456 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000457
458 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
459 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
460
461 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
462 num_jumbo_rxd == adapter->num_jumbo_rxd)
463 return 0;
464
465 adapter->num_rxd = num_rxd;
466 adapter->num_jumbo_rxd = num_jumbo_rxd;
467 adapter->num_txd = num_txd;
468
469 return qlcnic_reset_context(adapter);
470}
471
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000472static void qlcnic_get_channels(struct net_device *dev,
473 struct ethtool_channels *channel)
474{
475 struct qlcnic_adapter *adapter = netdev_priv(dev);
476
477 channel->max_rx = rounddown_pow_of_two(min_t(int,
478 adapter->max_rx_ques, num_online_cpus()));
479 channel->max_tx = adapter->max_tx_ques;
480
481 channel->rx_count = adapter->max_sds_rings;
482 channel->tx_count = adapter->max_tx_ques;
483}
484
485static int qlcnic_set_channels(struct net_device *dev,
486 struct ethtool_channels *channel)
487{
488 struct qlcnic_adapter *adapter = netdev_priv(dev);
489 int err;
490
491 if (channel->other_count || channel->combined_count ||
492 channel->tx_count != channel->max_tx)
493 return -EINVAL;
494
495 err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
496 if (err)
497 return err;
498
499 err = qlcnic_set_max_rss(adapter, channel->rx_count);
500 netdev_info(dev, "allocated 0x%x sds rings\n",
501 adapter->max_sds_rings);
502 return err;
503}
504
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000505static void
506qlcnic_get_pauseparam(struct net_device *netdev,
507 struct ethtool_pauseparam *pause)
508{
509 struct qlcnic_adapter *adapter = netdev_priv(netdev);
510 int port = adapter->physical_port;
511 __u32 val;
512
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000513 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000514 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
515 return;
516 /* get flow control settings */
517 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
518 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
519 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
520 switch (port) {
521 case 0:
522 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
523 break;
524 case 1:
525 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
526 break;
527 case 2:
528 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
529 break;
530 case 3:
531 default:
532 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
533 break;
534 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000535 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000536 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
537 return;
538 pause->rx_pause = 1;
539 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
540 if (port == 0)
541 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
542 else
543 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
544 } else {
545 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000546 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000547 }
548}
549
550static int
551qlcnic_set_pauseparam(struct net_device *netdev,
552 struct ethtool_pauseparam *pause)
553{
554 struct qlcnic_adapter *adapter = netdev_priv(netdev);
555 int port = adapter->physical_port;
556 __u32 val;
557
558 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000559 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000560 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
561 return -EIO;
562 /* set flow control */
563 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
564
565 if (pause->rx_pause)
566 qlcnic_gb_rx_flowctl(val);
567 else
568 qlcnic_gb_unset_rx_flowctl(val);
569
570 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
571 val);
572 /* set autoneg */
573 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
574 switch (port) {
575 case 0:
576 if (pause->tx_pause)
577 qlcnic_gb_unset_gb0_mask(val);
578 else
579 qlcnic_gb_set_gb0_mask(val);
580 break;
581 case 1:
582 if (pause->tx_pause)
583 qlcnic_gb_unset_gb1_mask(val);
584 else
585 qlcnic_gb_set_gb1_mask(val);
586 break;
587 case 2:
588 if (pause->tx_pause)
589 qlcnic_gb_unset_gb2_mask(val);
590 else
591 qlcnic_gb_set_gb2_mask(val);
592 break;
593 case 3:
594 default:
595 if (pause->tx_pause)
596 qlcnic_gb_unset_gb3_mask(val);
597 else
598 qlcnic_gb_set_gb3_mask(val);
599 break;
600 }
601 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000602 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000603 if (!pause->rx_pause || pause->autoneg)
604 return -EOPNOTSUPP;
605
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000606 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
607 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000608
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000609 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
610 if (port == 0) {
611 if (pause->tx_pause)
612 qlcnic_xg_unset_xg0_mask(val);
613 else
614 qlcnic_xg_set_xg0_mask(val);
615 } else {
616 if (pause->tx_pause)
617 qlcnic_xg_unset_xg1_mask(val);
618 else
619 qlcnic_xg_set_xg1_mask(val);
620 }
621 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
622 } else {
623 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000624 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000625 }
626 return 0;
627}
628
629static int qlcnic_reg_test(struct net_device *dev)
630{
631 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000632 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000633
634 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
635 if ((data_read & 0xffff) != adapter->pdev->vendor)
636 return 1;
637
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000638 return 0;
639}
640
641static int qlcnic_get_sset_count(struct net_device *dev, int sset)
642{
amit salecha3666e0b2010-10-18 01:47:48 +0000643 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000644 switch (sset) {
645 case ETH_SS_TEST:
646 return QLCNIC_TEST_LEN;
647 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000648 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
649 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000650 return QLCNIC_STATS_LEN;
651 default:
652 return -EOPNOTSUPP;
653 }
654}
655
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000656static int qlcnic_irq_test(struct net_device *netdev)
657{
658 struct qlcnic_adapter *adapter = netdev_priv(netdev);
659 int max_sds_rings = adapter->max_sds_rings;
660 int ret;
661
662 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
663 return -EIO;
664
665 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
666 if (ret)
667 goto clear_it;
668
669 adapter->diag_cnt = 0;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000670 ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func,
671 adapter->fw_hal_version, adapter->ahw->pci_func,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000672 0, 0, 0x00000011);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000673 if (ret)
674 goto done;
675
676 msleep(10);
677
678 ret = !adapter->diag_cnt;
679
680done:
681 qlcnic_diag_free_res(netdev, max_sds_rings);
682
683clear_it:
684 adapter->max_sds_rings = max_sds_rings;
685 clear_bit(__QLCNIC_RESETTING, &adapter->state);
686 return ret;
687}
688
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000689#define QLCNIC_ILB_PKT_SIZE 64
690#define QLCNIC_NUM_ILB_PKT 16
691#define QLCNIC_ILB_MAX_RCV_LOOP 10
692
693static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
694{
695 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
696
697 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
698
699 memcpy(data, mac, ETH_ALEN);
700 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
701
702 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
703}
704
705int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
706{
707 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
708 qlcnic_create_loopback_buff(buff, mac);
709 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
710}
711
712static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
713{
714 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
715 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
716 struct sk_buff *skb;
717 int i, loop, cnt = 0;
718
719 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
720 skb = dev_alloc_skb(QLCNIC_ILB_PKT_SIZE);
721 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
722 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
723
724 adapter->diag_cnt = 0;
725 qlcnic_xmit_frame(skb, adapter->netdev);
726
727 loop = 0;
728 do {
729 msleep(1);
730 qlcnic_process_rcv_ring_diag(sds_ring);
731 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
732 break;
733 } while (!adapter->diag_cnt);
734
735 dev_kfree_skb_any(skb);
736
737 if (!adapter->diag_cnt)
738 dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
739 " not recevied\n", i + 1);
740 else
741 cnt++;
742 }
743 if (cnt != i) {
744 dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
745 return -1;
746 }
747 return 0;
748}
749
750static int qlcnic_iloopback_test(struct net_device *netdev)
751{
752 struct qlcnic_adapter *adapter = netdev_priv(netdev);
753 int max_sds_rings = adapter->max_sds_rings;
754 struct qlcnic_host_sds_ring *sds_ring;
755 int loop = 0;
756 int ret;
757
758 netdev_info(netdev, "%s: in progress\n", __func__);
759 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
760 netdev_warn(netdev, "Loopback test not supported for non "
761 "privilege function\n");
762 return 0;
763 }
764
765 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
766 return -EIO;
767
768
769 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
770 if (ret)
771 goto clear_it;
772
773 sds_ring = &adapter->recv_ctx->sds_rings[0];
774
775 ret = qlcnic_set_lb_mode(adapter, QLCNIC_ILB_MODE);
776 if (ret)
777 goto free_res;
778
779 do {
780 msleep(500);
781 qlcnic_process_rcv_ring_diag(sds_ring);
782 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
783 break;
784 } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
785
786 if (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state)) {
787 netdev_info(netdev, "firmware didnt respond to loopback "
788 "configure request\n");
789 ret = adapter->ahw->loopback_state;
790 goto free_res;
791 }
792
793 ret = qlcnic_do_ilb_test(adapter);
794
795 qlcnic_clear_lb_mode(adapter);
796
797 free_res:
798 qlcnic_diag_free_res(netdev, max_sds_rings);
799
800 clear_it:
801 adapter->max_sds_rings = max_sds_rings;
802 clear_bit(__QLCNIC_RESETTING, &adapter->state);
803 return ret;
804}
805
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000806static void
807qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
808 u64 *data)
809{
810 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000811
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000812 data[0] = qlcnic_reg_test(dev);
813 if (data[0])
814 eth_test->flags |= ETH_TEST_FL_FAILED;
815
816 data[1] = (u64) qlcnic_test_link(dev);
817 if (data[1])
818 eth_test->flags |= ETH_TEST_FL_FAILED;
819
Sony Chacko13b93ed2011-01-10 00:15:22 +0000820 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000821 data[2] = qlcnic_irq_test(dev);
822 if (data[2])
823 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000824
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000825 data[3] = qlcnic_iloopback_test(dev);
826 if (data[3])
827 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000828
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000829 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000830}
831
832static void
833qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
834{
amit salecha3666e0b2010-10-18 01:47:48 +0000835 struct qlcnic_adapter *adapter = netdev_priv(dev);
836 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000837
838 switch (stringset) {
839 case ETH_SS_TEST:
840 memcpy(data, *qlcnic_gstrings_test,
841 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
842 break;
843 case ETH_SS_STATS:
844 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
845 memcpy(data + index * ETH_GSTRING_LEN,
846 qlcnic_gstrings_stats[index].stat_string,
847 ETH_GSTRING_LEN);
848 }
amit salecha3666e0b2010-10-18 01:47:48 +0000849 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
850 return;
851 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
852 memcpy(data + index * ETH_GSTRING_LEN,
853 qlcnic_device_gstrings_stats[i],
854 ETH_GSTRING_LEN);
855 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000856 }
857}
858
amit salecha3666e0b2010-10-18 01:47:48 +0000859#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
860 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
861
862static void
863qlcnic_fill_device_stats(int *index, u64 *data,
864 struct __qlcnic_esw_statistics *stats)
865{
866 int ind = *index;
867
868 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
869 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
870 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
871 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
872 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
873 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
874 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
875
876 *index = ind;
877}
878
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000879static void
880qlcnic_get_ethtool_stats(struct net_device *dev,
881 struct ethtool_stats *stats, u64 * data)
882{
883 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000884 struct qlcnic_esw_statistics port_stats;
885 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000886
887 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
888 char *p =
889 (char *)adapter +
890 qlcnic_gstrings_stats[index].stat_offset;
891 data[index] =
892 (qlcnic_gstrings_stats[index].sizeof_stat ==
893 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
894 }
amit salecha3666e0b2010-10-18 01:47:48 +0000895
896 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
897 return;
898
899 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000900 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000901 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
902 if (ret)
903 return;
904
905 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
906
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000907 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000908 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
909 if (ret)
910 return;
911
912 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000913}
914
stephen hemminger94469f72011-04-06 11:47:23 +0000915static int qlcnic_set_led(struct net_device *dev,
916 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000917{
918 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000919 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000920
stephen hemminger94469f72011-04-06 11:47:23 +0000921 switch (state) {
922 case ETHTOOL_ID_ACTIVE:
stephen hemminger94469f72011-04-06 11:47:23 +0000923 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
924 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
925 return -EIO;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000926
stephen hemminger94469f72011-04-06 11:47:23 +0000927 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) {
928 clear_bit(__QLCNIC_RESETTING, &adapter->state);
929 return -EIO;
930 }
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000931 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000932 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000933
stephen hemminger94469f72011-04-06 11:47:23 +0000934 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0)
935 return 0;
936
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000937 dev_err(&adapter->pdev->dev,
938 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +0000939 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000940
stephen hemminger94469f72011-04-06 11:47:23 +0000941 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000942 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
943 dev_err(&adapter->pdev->dev,
944 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000945
stephen hemminger94469f72011-04-06 11:47:23 +0000946 break;
947
948 default:
949 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000950 }
951
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000952 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) {
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000953 qlcnic_diag_free_res(dev, max_sds_rings);
954 clear_bit(__QLCNIC_RESETTING, &adapter->state);
955 }
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000956
stephen hemminger94469f72011-04-06 11:47:23 +0000957 return -EIO;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000958}
959
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000960static void
961qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
962{
963 struct qlcnic_adapter *adapter = netdev_priv(dev);
964 u32 wol_cfg;
965
966 wol->supported = 0;
967 wol->wolopts = 0;
968
969 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
970 if (wol_cfg & (1UL << adapter->portnum))
971 wol->supported |= WAKE_MAGIC;
972
973 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
974 if (wol_cfg & (1UL << adapter->portnum))
975 wol->wolopts |= WAKE_MAGIC;
976}
977
978static int
979qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
980{
981 struct qlcnic_adapter *adapter = netdev_priv(dev);
982 u32 wol_cfg;
983
984 if (wol->wolopts & ~WAKE_MAGIC)
985 return -EOPNOTSUPP;
986
987 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
988 if (!(wol_cfg & (1 << adapter->portnum)))
989 return -EOPNOTSUPP;
990
991 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
992 if (wol->wolopts & WAKE_MAGIC)
993 wol_cfg |= 1UL << adapter->portnum;
994 else
995 wol_cfg &= ~(1UL << adapter->portnum);
996
997 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
998
999 return 0;
1000}
1001
1002/*
1003 * Set the coalescing parameters. Currently only normal is supported.
1004 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1005 * firmware coalescing to default.
1006 */
1007static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1008 struct ethtool_coalesce *ethcoal)
1009{
1010 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1011
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001012 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001013 return -EINVAL;
1014
1015 /*
1016 * Return Error if unsupported values or
1017 * unsupported parameters are set.
1018 */
1019 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1020 ethcoal->rx_max_coalesced_frames > 0xffff ||
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001021 ethcoal->tx_coalesce_usecs ||
1022 ethcoal->tx_max_coalesced_frames ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001023 ethcoal->rx_coalesce_usecs_irq ||
1024 ethcoal->rx_max_coalesced_frames_irq ||
1025 ethcoal->tx_coalesce_usecs_irq ||
1026 ethcoal->tx_max_coalesced_frames_irq ||
1027 ethcoal->stats_block_coalesce_usecs ||
1028 ethcoal->use_adaptive_rx_coalesce ||
1029 ethcoal->use_adaptive_tx_coalesce ||
1030 ethcoal->pkt_rate_low ||
1031 ethcoal->rx_coalesce_usecs_low ||
1032 ethcoal->rx_max_coalesced_frames_low ||
1033 ethcoal->tx_coalesce_usecs_low ||
1034 ethcoal->tx_max_coalesced_frames_low ||
1035 ethcoal->pkt_rate_high ||
1036 ethcoal->rx_coalesce_usecs_high ||
1037 ethcoal->rx_max_coalesced_frames_high ||
1038 ethcoal->tx_coalesce_usecs_high ||
1039 ethcoal->tx_max_coalesced_frames_high)
1040 return -EINVAL;
1041
1042 if (!ethcoal->rx_coalesce_usecs ||
1043 !ethcoal->rx_max_coalesced_frames) {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001044 adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
1045 adapter->ahw->coal.rx_time_us =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001046 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001047 adapter->ahw->coal.rx_packets =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001048 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1049 } else {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001050 adapter->ahw->coal.flag = 0;
1051 adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
1052 adapter->ahw->coal.rx_packets =
1053 ethcoal->rx_max_coalesced_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001054 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001055
1056 qlcnic_config_intr_coalesce(adapter);
1057
1058 return 0;
1059}
1060
1061static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1062 struct ethtool_coalesce *ethcoal)
1063{
1064 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1065
1066 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1067 return -EINVAL;
1068
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001069 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
1070 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001071
1072 return 0;
1073}
1074
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001075static u32 qlcnic_get_msglevel(struct net_device *netdev)
1076{
1077 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1078
1079 return adapter->msg_enable;
1080}
1081
1082static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1083{
1084 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1085
1086 adapter->msg_enable = msglvl;
1087}
1088
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001089static int
1090qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1091{
1092 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1093 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1094
1095 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1096 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1097 dump->version = adapter->fw_version;
1098 return 0;
1099}
1100
1101static int
1102qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1103 void *buffer)
1104{
1105 int i, copy_sz;
1106 u32 *hdr_ptr, *data;
1107 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1108 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1109
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001110 if (!fw_dump->clr) {
1111 netdev_info(netdev, "Dump not available\n");
1112 qlcnic_api_unlock(adapter);
1113 return -EINVAL;
1114 }
1115 /* Copy template header first */
1116 copy_sz = fw_dump->tmpl_hdr->size;
1117 hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
Joe Perches43d620c2011-06-16 19:08:06 +00001118 data = buffer;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001119 for (i = 0; i < copy_sz/sizeof(u32); i++)
1120 *data++ = cpu_to_le32(*hdr_ptr++);
1121
1122 /* Copy captured dump data */
1123 memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1124 dump->len = copy_sz + fw_dump->size;
1125 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1126
1127 /* Free dump area once data has been captured */
1128 vfree(fw_dump->data);
1129 fw_dump->data = NULL;
1130 fw_dump->clr = 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001131
1132 return 0;
1133}
1134
1135static int
1136qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1137{
1138 int ret = 0;
1139 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1140 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1141
1142 if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) {
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001143 if (!fw_dump->enable) {
1144 netdev_info(netdev, "FW dump not enabled\n");
1145 return ret;
1146 }
1147 if (fw_dump->clr) {
1148 dev_info(&adapter->pdev->dev,
1149 "Previous dump not cleared, not forcing dump\n");
1150 return ret;
1151 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001152 netdev_info(netdev, "Forcing a FW dump\n");
1153 qlcnic_dev_request_reset(adapter);
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001154 } else if (val->flag == QLCNIC_DISABLE_FW_DUMP) {
1155 if (fw_dump->enable) {
1156 netdev_info(netdev, "Disabling FW dump\n");
1157 fw_dump->enable = 0;
1158 }
1159 } else if (val->flag == QLCNIC_ENABLE_FW_DUMP) {
1160 if (!fw_dump->enable && fw_dump->tmpl_hdr) {
1161 netdev_info(netdev, "Enabling FW dump\n");
1162 fw_dump->enable = 1;
1163 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001164 } else {
1165 if (val->flag > QLCNIC_DUMP_MASK_MAX ||
1166 val->flag < QLCNIC_DUMP_MASK_MIN) {
1167 netdev_info(netdev,
1168 "Invalid dump level: 0x%x\n", val->flag);
1169 ret = -EINVAL;
1170 goto out;
1171 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001172 fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001173 netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1174 fw_dump->tmpl_hdr->drv_cap_mask);
1175 }
1176out:
1177 return ret;
1178}
1179
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001180const struct ethtool_ops qlcnic_ethtool_ops = {
1181 .get_settings = qlcnic_get_settings,
1182 .set_settings = qlcnic_set_settings,
1183 .get_drvinfo = qlcnic_get_drvinfo,
1184 .get_regs_len = qlcnic_get_regs_len,
1185 .get_regs = qlcnic_get_regs,
1186 .get_link = ethtool_op_get_link,
1187 .get_eeprom_len = qlcnic_get_eeprom_len,
1188 .get_eeprom = qlcnic_get_eeprom,
1189 .get_ringparam = qlcnic_get_ringparam,
1190 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +00001191 .get_channels = qlcnic_get_channels,
1192 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001193 .get_pauseparam = qlcnic_get_pauseparam,
1194 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001195 .get_wol = qlcnic_get_wol,
1196 .set_wol = qlcnic_set_wol,
1197 .self_test = qlcnic_diag_test,
1198 .get_strings = qlcnic_get_strings,
1199 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1200 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001201 .get_coalesce = qlcnic_get_intr_coalesce,
1202 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +00001203 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001204 .set_msglevel = qlcnic_set_msglevel,
1205 .get_msglevel = qlcnic_get_msglevel,
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001206 .get_dump_flag = qlcnic_get_dump_flag,
1207 .get_dump_data = qlcnic_get_dump_data,
1208 .set_dump = qlcnic_set_dump,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001209};