blob: 25e93a53fca0954e41728e9c55e31305ee62cc53 [file] [log] [blame]
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001/*
2 * Copyright (C) 2009 - QLogic Corporation.
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 * MA 02111-1307, USA.
19 *
20 * The full GNU General Public License is included in this distribution
21 * in the file called "COPYING".
22 *
23 */
24
25#include <linux/types.h>
26#include <linux/delay.h>
27#include <linux/pci.h>
28#include <linux/io.h>
29#include <linux/netdevice.h>
30#include <linux/ethtool.h>
31
32#include "qlcnic.h"
33
34struct qlcnic_stats {
35 char stat_string[ETH_GSTRING_LEN];
36 int sizeof_stat;
37 int stat_offset;
38};
39
40#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
41#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
42
43static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
44 {"xmit_called",
45 QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
46 {"xmit_finished",
47 QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
48 {"rx_dropped",
49 QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
50 {"tx_dropped",
51 QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
52 {"csummed",
53 QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
54 {"rx_pkts",
55 QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
56 {"lro_pkts",
57 QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
58 {"rx_bytes",
59 QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
60 {"tx_bytes",
61 QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000062 {"lrobytes",
63 QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
64 {"lso_frames",
65 QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
66 {"xmit_on",
67 QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
68 {"xmit_off",
69 QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
70 {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
71 QLC_OFF(stats.skb_alloc_failure)},
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +000072 {"null rxbuf",
73 QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
74 {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
75 QLC_OFF(stats.rx_dma_map_error)},
76 {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
77 QLC_OFF(stats.tx_dma_map_error)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000078
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000079};
80
amit salecha3666e0b2010-10-18 01:47:48 +000081static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
82 "rx unicast frames",
83 "rx multicast frames",
84 "rx broadcast frames",
85 "rx dropped frames",
86 "rx errors",
87 "rx local frames",
88 "rx numbytes",
89 "tx unicast frames",
90 "tx multicast frames",
91 "tx broadcast frames",
92 "tx dropped frames",
93 "tx errors",
94 "tx local frames",
95 "tx numbytes",
96};
97
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000098#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
amit salecha3666e0b2010-10-18 01:47:48 +000099#define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000100
101static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
102 "Register_Test_on_offline",
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000103 "Link_Test_on_offline",
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000104 "Interrupt_Test_offline",
105 "Loopback_Test_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000106};
107
108#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
109
110#define QLCNIC_RING_REGS_COUNT 20
111#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
112#define QLCNIC_MAX_EEPROM_LEN 1024
113
114static const u32 diag_registers[] = {
115 CRB_CMDPEG_STATE,
116 CRB_RCVPEG_STATE,
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000117 CRB_XG_STATE_P3P,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000118 CRB_FW_CAPABILITIES_1,
119 ISR_INT_STATE_REG,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000120 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000121 QLCNIC_CRB_DEV_STATE,
122 QLCNIC_CRB_DRV_STATE,
123 QLCNIC_CRB_DRV_SCRATCH,
124 QLCNIC_CRB_DEV_PARTITION_INFO,
125 QLCNIC_CRB_DRV_IDC_VER,
126 QLCNIC_PEG_ALIVE_COUNTER,
127 QLCNIC_PEG_HALT_STATUS1,
128 QLCNIC_PEG_HALT_STATUS2,
129 QLCNIC_CRB_PEG_NET_0+0x3c,
130 QLCNIC_CRB_PEG_NET_1+0x3c,
131 QLCNIC_CRB_PEG_NET_2+0x3c,
132 QLCNIC_CRB_PEG_NET_4+0x3c,
133 -1
134};
135
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000136#define QLCNIC_MGMT_API_VERSION 2
137#define QLCNIC_DEV_INFO_SIZE 1
138#define QLCNIC_ETHTOOL_REGS_VER 2
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000139static int qlcnic_get_regs_len(struct net_device *dev)
140{
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000141 return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
142 QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000143}
144
145static int qlcnic_get_eeprom_len(struct net_device *dev)
146{
147 return QLCNIC_FLASH_TOTAL_SIZE;
148}
149
150static void
151qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
152{
153 struct qlcnic_adapter *adapter = netdev_priv(dev);
154 u32 fw_major, fw_minor, fw_build;
155
156 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
157 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
158 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
159 sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
160
161 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
162 strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
163 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
164}
165
166static int
167qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
168{
169 struct qlcnic_adapter *adapter = netdev_priv(dev);
170 int check_sfp_module = 0;
171 u16 pcifn = adapter->ahw.pci_func;
172
173 /* read which mode */
174 if (adapter->ahw.port_type == QLCNIC_GBE) {
175 ecmd->supported = (SUPPORTED_10baseT_Half |
176 SUPPORTED_10baseT_Full |
177 SUPPORTED_100baseT_Half |
178 SUPPORTED_100baseT_Full |
179 SUPPORTED_1000baseT_Half |
180 SUPPORTED_1000baseT_Full);
181
182 ecmd->advertising = (ADVERTISED_100baseT_Half |
183 ADVERTISED_100baseT_Full |
184 ADVERTISED_1000baseT_Half |
185 ADVERTISED_1000baseT_Full);
186
187 ecmd->speed = adapter->link_speed;
188 ecmd->duplex = adapter->link_duplex;
189 ecmd->autoneg = adapter->link_autoneg;
190
191 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
192 u32 val;
193
194 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
195 if (val == QLCNIC_PORT_MODE_802_3_AP) {
196 ecmd->supported = SUPPORTED_1000baseT_Full;
197 ecmd->advertising = ADVERTISED_1000baseT_Full;
198 } else {
199 ecmd->supported = SUPPORTED_10000baseT_Full;
200 ecmd->advertising = ADVERTISED_10000baseT_Full;
201 }
202
203 if (netif_running(dev) && adapter->has_link_events) {
204 ecmd->speed = adapter->link_speed;
205 ecmd->autoneg = adapter->link_autoneg;
206 ecmd->duplex = adapter->link_duplex;
207 goto skip;
208 }
209
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000210 val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
211 ecmd->speed = P3P_LINK_SPEED_MHZ *
212 P3P_LINK_SPEED_VAL(pcifn, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000213 ecmd->duplex = DUPLEX_FULL;
214 ecmd->autoneg = AUTONEG_DISABLE;
215 } else
216 return -EIO;
217
218skip:
219 ecmd->phy_address = adapter->physical_port;
220 ecmd->transceiver = XCVR_EXTERNAL;
221
222 switch (adapter->ahw.board_type) {
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000223 case QLCNIC_BRDTYPE_P3P_REF_QG:
224 case QLCNIC_BRDTYPE_P3P_4_GB:
225 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000226
227 ecmd->supported |= SUPPORTED_Autoneg;
228 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000229 case QLCNIC_BRDTYPE_P3P_10G_CX4:
230 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
231 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000232 ecmd->supported |= SUPPORTED_TP;
233 ecmd->advertising |= ADVERTISED_TP;
234 ecmd->port = PORT_TP;
235 ecmd->autoneg = adapter->link_autoneg;
236 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000237 case QLCNIC_BRDTYPE_P3P_IMEZ:
238 case QLCNIC_BRDTYPE_P3P_XG_LOM:
239 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000240 ecmd->supported |= SUPPORTED_MII;
241 ecmd->advertising |= ADVERTISED_MII;
242 ecmd->port = PORT_MII;
243 ecmd->autoneg = AUTONEG_DISABLE;
244 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000245 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
246 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
247 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000248 ecmd->advertising |= ADVERTISED_TP;
249 ecmd->supported |= SUPPORTED_TP;
250 check_sfp_module = netif_running(dev) &&
251 adapter->has_link_events;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000252 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000253 ecmd->supported |= SUPPORTED_FIBRE;
254 ecmd->advertising |= ADVERTISED_FIBRE;
255 ecmd->port = PORT_FIBRE;
256 ecmd->autoneg = AUTONEG_DISABLE;
257 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000258 case QLCNIC_BRDTYPE_P3P_10G_TP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000259 if (adapter->ahw.port_type == QLCNIC_XGBE) {
260 ecmd->autoneg = AUTONEG_DISABLE;
261 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
262 ecmd->advertising |=
263 (ADVERTISED_FIBRE | ADVERTISED_TP);
264 ecmd->port = PORT_FIBRE;
265 check_sfp_module = netif_running(dev) &&
266 adapter->has_link_events;
267 } else {
268 ecmd->autoneg = AUTONEG_ENABLE;
269 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
270 ecmd->advertising |=
271 (ADVERTISED_TP | ADVERTISED_Autoneg);
272 ecmd->port = PORT_TP;
273 }
274 break;
275 default:
276 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
277 adapter->ahw.board_type);
278 return -EIO;
279 }
280
281 if (check_sfp_module) {
282 switch (adapter->module_type) {
283 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
284 case LINKEVENT_MODULE_OPTICAL_SRLR:
285 case LINKEVENT_MODULE_OPTICAL_LRM:
286 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
287 ecmd->port = PORT_FIBRE;
288 break;
289 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
290 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
291 case LINKEVENT_MODULE_TWINAX:
292 ecmd->port = PORT_TP;
293 break;
294 default:
295 ecmd->port = PORT_OTHER;
296 }
297 }
298
299 return 0;
300}
301
302static int
303qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
304{
305 struct qlcnic_adapter *adapter = netdev_priv(dev);
306 __u32 status;
307
308 /* read which mode */
309 if (adapter->ahw.port_type == QLCNIC_GBE) {
310 /* autonegotiation */
311 if (qlcnic_fw_cmd_set_phy(adapter,
312 QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG,
313 ecmd->autoneg) != 0)
314 return -EIO;
315 else
316 adapter->link_autoneg = ecmd->autoneg;
317
318 if (qlcnic_fw_cmd_query_phy(adapter,
319 QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
320 &status) != 0)
321 return -EIO;
322
323 switch (ecmd->speed) {
324 case SPEED_10:
325 qlcnic_set_phy_speed(status, 0);
326 break;
327 case SPEED_100:
328 qlcnic_set_phy_speed(status, 1);
329 break;
330 case SPEED_1000:
331 qlcnic_set_phy_speed(status, 2);
332 break;
333 }
334
335 if (ecmd->duplex == DUPLEX_HALF)
336 qlcnic_clear_phy_duplex(status);
337 if (ecmd->duplex == DUPLEX_FULL)
338 qlcnic_set_phy_duplex(status);
339 if (qlcnic_fw_cmd_set_phy(adapter,
340 QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
341 *((int *)&status)) != 0)
342 return -EIO;
343 else {
344 adapter->link_speed = ecmd->speed;
345 adapter->link_duplex = ecmd->duplex;
346 }
347 } else
348 return -EOPNOTSUPP;
349
350 if (!netif_running(dev))
351 return 0;
352
353 dev->netdev_ops->ndo_stop(dev);
354 return dev->netdev_ops->ndo_open(dev);
355}
356
357static void
358qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
359{
360 struct qlcnic_adapter *adapter = netdev_priv(dev);
361 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
362 struct qlcnic_host_sds_ring *sds_ring;
363 u32 *regs_buff = p;
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000364 int ring, i = 0, j = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000365
366 memset(p, 0, qlcnic_get_regs_len(dev));
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000367 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
368 (adapter->ahw.revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000369
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000370 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
371 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
372
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000373 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
374 regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000375
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000376 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000377 return;
378
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000379 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
380
381 regs_buff[i++] = 1; /* No. of tx ring */
382 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
383 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
384
385 regs_buff[i++] = 2; /* No. of rx ring */
386 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
387 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
388
389 regs_buff[i++] = adapter->max_sds_rings;
390
391 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
392 sds_ring = &(recv_ctx->sds_rings[ring]);
393 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
394 }
395}
396
397static u32 qlcnic_test_link(struct net_device *dev)
398{
399 struct qlcnic_adapter *adapter = netdev_priv(dev);
400 u32 val;
401
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000402 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
403 val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val);
404 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000405}
406
407static int
408qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
409 u8 *bytes)
410{
411 struct qlcnic_adapter *adapter = netdev_priv(dev);
412 int offset;
413 int ret;
414
415 if (eeprom->len == 0)
416 return -EINVAL;
417
418 eeprom->magic = (adapter->pdev)->vendor |
419 ((adapter->pdev)->device << 16);
420 offset = eeprom->offset;
421
422 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
423 eeprom->len);
424 if (ret < 0)
425 return ret;
426
427 return 0;
428}
429
430static void
431qlcnic_get_ringparam(struct net_device *dev,
432 struct ethtool_ringparam *ring)
433{
434 struct qlcnic_adapter *adapter = netdev_priv(dev);
435
436 ring->rx_pending = adapter->num_rxd;
437 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000438 ring->tx_pending = adapter->num_txd;
439
440 if (adapter->ahw.port_type == QLCNIC_GBE) {
441 ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
442 ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
443 } else {
444 ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
445 ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
446 }
447
448 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
449
450 ring->rx_mini_max_pending = 0;
451 ring->rx_mini_pending = 0;
452}
453
454static u32
455qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
456{
457 u32 num_desc;
458 num_desc = max(val, min);
459 num_desc = min(num_desc, max);
460 num_desc = roundup_pow_of_two(num_desc);
461
462 if (val != num_desc) {
463 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
464 qlcnic_driver_name, r_name, num_desc, val);
465 }
466
467 return num_desc;
468}
469
470static int
471qlcnic_set_ringparam(struct net_device *dev,
472 struct ethtool_ringparam *ring)
473{
474 struct qlcnic_adapter *adapter = netdev_priv(dev);
475 u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
476 u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
477 u16 num_rxd, num_jumbo_rxd, num_txd;
478
479
480 if (ring->rx_mini_pending)
481 return -EOPNOTSUPP;
482
483 if (adapter->ahw.port_type == QLCNIC_GBE) {
484 max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
485 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
486 }
487
488 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
489 MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
490
491 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
492 MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
493
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
508static void
509qlcnic_get_pauseparam(struct net_device *netdev,
510 struct ethtool_pauseparam *pause)
511{
512 struct qlcnic_adapter *adapter = netdev_priv(netdev);
513 int port = adapter->physical_port;
514 __u32 val;
515
516 if (adapter->ahw.port_type == QLCNIC_GBE) {
517 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
518 return;
519 /* get flow control settings */
520 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
521 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
522 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
523 switch (port) {
524 case 0:
525 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
526 break;
527 case 1:
528 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
529 break;
530 case 2:
531 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
532 break;
533 case 3:
534 default:
535 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
536 break;
537 }
538 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
539 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
540 return;
541 pause->rx_pause = 1;
542 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
543 if (port == 0)
544 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
545 else
546 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
547 } else {
548 dev_err(&netdev->dev, "Unknown board type: %x\n",
549 adapter->ahw.port_type);
550 }
551}
552
553static int
554qlcnic_set_pauseparam(struct net_device *netdev,
555 struct ethtool_pauseparam *pause)
556{
557 struct qlcnic_adapter *adapter = netdev_priv(netdev);
558 int port = adapter->physical_port;
559 __u32 val;
560
561 /* read mode */
562 if (adapter->ahw.port_type == QLCNIC_GBE) {
563 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
564 return -EIO;
565 /* set flow control */
566 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
567
568 if (pause->rx_pause)
569 qlcnic_gb_rx_flowctl(val);
570 else
571 qlcnic_gb_unset_rx_flowctl(val);
572
573 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
574 val);
575 /* set autoneg */
576 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
577 switch (port) {
578 case 0:
579 if (pause->tx_pause)
580 qlcnic_gb_unset_gb0_mask(val);
581 else
582 qlcnic_gb_set_gb0_mask(val);
583 break;
584 case 1:
585 if (pause->tx_pause)
586 qlcnic_gb_unset_gb1_mask(val);
587 else
588 qlcnic_gb_set_gb1_mask(val);
589 break;
590 case 2:
591 if (pause->tx_pause)
592 qlcnic_gb_unset_gb2_mask(val);
593 else
594 qlcnic_gb_set_gb2_mask(val);
595 break;
596 case 3:
597 default:
598 if (pause->tx_pause)
599 qlcnic_gb_unset_gb3_mask(val);
600 else
601 qlcnic_gb_set_gb3_mask(val);
602 break;
603 }
604 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
605 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000606 if (!pause->rx_pause || pause->autoneg)
607 return -EOPNOTSUPP;
608
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000609 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
610 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000611
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000612 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
613 if (port == 0) {
614 if (pause->tx_pause)
615 qlcnic_xg_unset_xg0_mask(val);
616 else
617 qlcnic_xg_set_xg0_mask(val);
618 } else {
619 if (pause->tx_pause)
620 qlcnic_xg_unset_xg1_mask(val);
621 else
622 qlcnic_xg_set_xg1_mask(val);
623 }
624 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
625 } else {
626 dev_err(&netdev->dev, "Unknown board type: %x\n",
627 adapter->ahw.port_type);
628 }
629 return 0;
630}
631
632static int qlcnic_reg_test(struct net_device *dev)
633{
634 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000635 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000636
637 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
638 if ((data_read & 0xffff) != adapter->pdev->vendor)
639 return 1;
640
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000641 return 0;
642}
643
644static int qlcnic_get_sset_count(struct net_device *dev, int sset)
645{
amit salecha3666e0b2010-10-18 01:47:48 +0000646 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000647 switch (sset) {
648 case ETH_SS_TEST:
649 return QLCNIC_TEST_LEN;
650 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000651 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
652 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000653 return QLCNIC_STATS_LEN;
654 default:
655 return -EOPNOTSUPP;
656 }
657}
658
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000659#define QLC_ILB_PKT_SIZE 64
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000660#define QLC_NUM_ILB_PKT 16
661#define QLC_ILB_MAX_RCV_LOOP 10
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000662
663static void qlcnic_create_loopback_buff(unsigned char *data)
664{
665 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
666 memset(data, 0x4e, QLC_ILB_PKT_SIZE);
667 memset(data, 0xff, 12);
668 memcpy(data + 12, random_data, sizeof(random_data));
669}
670
671int qlcnic_check_loopback_buff(unsigned char *data)
672{
673 unsigned char buff[QLC_ILB_PKT_SIZE];
674 qlcnic_create_loopback_buff(buff);
675 return memcmp(data, buff, QLC_ILB_PKT_SIZE);
676}
677
678static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
679{
680 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
681 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
682 struct sk_buff *skb;
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000683 int i, loop, cnt = 0;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000684
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000685 for (i = 0; i < QLC_NUM_ILB_PKT; i++) {
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000686 skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
687 qlcnic_create_loopback_buff(skb->data);
688 skb_put(skb, QLC_ILB_PKT_SIZE);
689
690 adapter->diag_cnt = 0;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000691 qlcnic_xmit_frame(skb, adapter->netdev);
692
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000693 loop = 0;
694 do {
695 msleep(1);
696 qlcnic_process_rcv_ring_diag(sds_ring);
697 } while (loop++ < QLC_ILB_MAX_RCV_LOOP &&
698 !adapter->diag_cnt);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000699
700 dev_kfree_skb_any(skb);
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000701
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000702 if (!adapter->diag_cnt)
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000703 dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
704 " not recevied\n", i + 1);
705 else
706 cnt++;
707 }
708 if (cnt != i) {
709 dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
710 return -1;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000711 }
712 return 0;
713}
714
715static int qlcnic_loopback_test(struct net_device *netdev)
716{
717 struct qlcnic_adapter *adapter = netdev_priv(netdev);
718 int max_sds_rings = adapter->max_sds_rings;
719 int ret;
720
Amit Kumar Salecha36a18982010-07-24 18:32:17 +0000721 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
722 dev_warn(&adapter->pdev->dev, "Loopback test not supported"
723 "for non privilege function\n");
724 return 0;
725 }
726
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000727 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
728 return -EIO;
729
Amit Kumar Salechab8c17622010-10-07 23:46:06 +0000730 if (qlcnic_request_quiscent_mode(adapter)) {
731 clear_bit(__QLCNIC_RESETTING, &adapter->state);
732 return -EIO;
733 }
734
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000735 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
736 if (ret)
737 goto clear_it;
738
Amit Kumar Salecha36a18982010-07-24 18:32:17 +0000739 ret = qlcnic_set_ilb_mode(adapter);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000740 if (ret)
741 goto done;
742
743 ret = qlcnic_do_ilb_test(adapter);
744
Amit Kumar Salecha36a18982010-07-24 18:32:17 +0000745 qlcnic_clear_ilb_mode(adapter);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000746
747done:
748 qlcnic_diag_free_res(netdev, max_sds_rings);
749
750clear_it:
Amit Kumar Salechab8c17622010-10-07 23:46:06 +0000751 qlcnic_clear_quiscent_mode(adapter);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000752 adapter->max_sds_rings = max_sds_rings;
753 clear_bit(__QLCNIC_RESETTING, &adapter->state);
754 return ret;
755}
756
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000757static int qlcnic_irq_test(struct net_device *netdev)
758{
759 struct qlcnic_adapter *adapter = netdev_priv(netdev);
760 int max_sds_rings = adapter->max_sds_rings;
761 int ret;
762
763 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
764 return -EIO;
765
766 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
767 if (ret)
768 goto clear_it;
769
770 adapter->diag_cnt = 0;
771 ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000772 adapter->fw_hal_version, adapter->portnum,
773 0, 0, 0x00000011);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000774 if (ret)
775 goto done;
776
777 msleep(10);
778
779 ret = !adapter->diag_cnt;
780
781done:
782 qlcnic_diag_free_res(netdev, max_sds_rings);
783
784clear_it:
785 adapter->max_sds_rings = max_sds_rings;
786 clear_bit(__QLCNIC_RESETTING, &adapter->state);
787 return ret;
788}
789
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000790static void
791qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
792 u64 *data)
793{
794 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000795
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000796 data[0] = qlcnic_reg_test(dev);
797 if (data[0])
798 eth_test->flags |= ETH_TEST_FL_FAILED;
799
800 data[1] = (u64) qlcnic_test_link(dev);
801 if (data[1])
802 eth_test->flags |= ETH_TEST_FL_FAILED;
803
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000804 if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
805 data[2] = qlcnic_irq_test(dev);
806 if (data[2])
807 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000808
809 data[3] = qlcnic_loopback_test(dev);
810 if (data[3])
811 eth_test->flags |= ETH_TEST_FL_FAILED;
812
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000813 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000814}
815
816static void
817qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
818{
amit salecha3666e0b2010-10-18 01:47:48 +0000819 struct qlcnic_adapter *adapter = netdev_priv(dev);
820 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000821
822 switch (stringset) {
823 case ETH_SS_TEST:
824 memcpy(data, *qlcnic_gstrings_test,
825 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
826 break;
827 case ETH_SS_STATS:
828 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
829 memcpy(data + index * ETH_GSTRING_LEN,
830 qlcnic_gstrings_stats[index].stat_string,
831 ETH_GSTRING_LEN);
832 }
amit salecha3666e0b2010-10-18 01:47:48 +0000833 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
834 return;
835 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
836 memcpy(data + index * ETH_GSTRING_LEN,
837 qlcnic_device_gstrings_stats[i],
838 ETH_GSTRING_LEN);
839 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000840 }
841}
842
amit salecha3666e0b2010-10-18 01:47:48 +0000843#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
844 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
845
846static void
847qlcnic_fill_device_stats(int *index, u64 *data,
848 struct __qlcnic_esw_statistics *stats)
849{
850 int ind = *index;
851
852 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
853 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
854 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
855 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
856 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
857 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
858 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
859
860 *index = ind;
861}
862
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000863static void
864qlcnic_get_ethtool_stats(struct net_device *dev,
865 struct ethtool_stats *stats, u64 * data)
866{
867 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000868 struct qlcnic_esw_statistics port_stats;
869 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000870
871 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
872 char *p =
873 (char *)adapter +
874 qlcnic_gstrings_stats[index].stat_offset;
875 data[index] =
876 (qlcnic_gstrings_stats[index].sizeof_stat ==
877 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
878 }
amit salecha3666e0b2010-10-18 01:47:48 +0000879
880 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
881 return;
882
883 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
884 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
885 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
886 if (ret)
887 return;
888
889 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
890
891 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
892 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
893 if (ret)
894 return;
895
896 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000897}
898
Rajesh Borundia0325d692010-08-19 05:08:26 +0000899static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
900{
901 struct qlcnic_adapter *adapter = netdev_priv(dev);
902
903 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
904 return -EOPNOTSUPP;
905 if (data)
906 dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
907 else
908 dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
909
910 return 0;
911
912}
Sucheta Chakraborty8bae5692010-03-08 00:14:45 +0000913static u32 qlcnic_get_tx_csum(struct net_device *dev)
914{
915 return dev->features & NETIF_F_IP_CSUM;
916}
917
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000918static u32 qlcnic_get_rx_csum(struct net_device *dev)
919{
920 struct qlcnic_adapter *adapter = netdev_priv(dev);
921 return adapter->rx_csum;
922}
923
924static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
925{
926 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000927
Rajesh Borundia0325d692010-08-19 05:08:26 +0000928 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
929 return -EOPNOTSUPP;
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000930 if (!!data) {
931 adapter->rx_csum = !!data;
932 return 0;
933 }
934
Amit Kumar Salechaa2152d02010-10-07 23:46:07 +0000935 if (dev->features & NETIF_F_LRO) {
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000936 if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED))
937 return -EIO;
938
939 dev->features &= ~NETIF_F_LRO;
940 qlcnic_send_lro_cleanup(adapter);
941 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000942 adapter->rx_csum = !!data;
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000943 dev_info(&adapter->pdev->dev, "disabling LRO as rx_csum is off\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000944 return 0;
945}
946
947static u32 qlcnic_get_tso(struct net_device *dev)
948{
949 return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
950}
951
952static int qlcnic_set_tso(struct net_device *dev, u32 data)
953{
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +0000954 struct qlcnic_adapter *adapter = netdev_priv(dev);
955 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO))
956 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000957 if (data)
958 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
959 else
960 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
961
962 return 0;
963}
964
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000965static int qlcnic_blink_led(struct net_device *dev, u32 val)
966{
967 struct qlcnic_adapter *adapter = netdev_priv(dev);
968 int ret;
969
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000970 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
971 return -EIO;
972
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000973 ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000974 if (ret) {
975 dev_err(&adapter->pdev->dev,
976 "Failed to set LED blink state.\n");
977 return ret;
978 }
979
980 msleep_interruptible(val * 1000);
981
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000982 ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000983 if (ret) {
984 dev_err(&adapter->pdev->dev,
985 "Failed to reset LED blink state.\n");
986 return ret;
987 }
988
989 return 0;
990}
991
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000992static void
993qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
994{
995 struct qlcnic_adapter *adapter = netdev_priv(dev);
996 u32 wol_cfg;
997
998 wol->supported = 0;
999 wol->wolopts = 0;
1000
1001 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1002 if (wol_cfg & (1UL << adapter->portnum))
1003 wol->supported |= WAKE_MAGIC;
1004
1005 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1006 if (wol_cfg & (1UL << adapter->portnum))
1007 wol->wolopts |= WAKE_MAGIC;
1008}
1009
1010static int
1011qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1012{
1013 struct qlcnic_adapter *adapter = netdev_priv(dev);
1014 u32 wol_cfg;
1015
1016 if (wol->wolopts & ~WAKE_MAGIC)
1017 return -EOPNOTSUPP;
1018
1019 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1020 if (!(wol_cfg & (1 << adapter->portnum)))
1021 return -EOPNOTSUPP;
1022
1023 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1024 if (wol->wolopts & WAKE_MAGIC)
1025 wol_cfg |= 1UL << adapter->portnum;
1026 else
1027 wol_cfg &= ~(1UL << adapter->portnum);
1028
1029 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1030
1031 return 0;
1032}
1033
1034/*
1035 * Set the coalescing parameters. Currently only normal is supported.
1036 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1037 * firmware coalescing to default.
1038 */
1039static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1040 struct ethtool_coalesce *ethcoal)
1041{
1042 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1043
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001044 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001045 return -EINVAL;
1046
1047 /*
1048 * Return Error if unsupported values or
1049 * unsupported parameters are set.
1050 */
1051 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1052 ethcoal->rx_max_coalesced_frames > 0xffff ||
1053 ethcoal->tx_coalesce_usecs > 0xffff ||
1054 ethcoal->tx_max_coalesced_frames > 0xffff ||
1055 ethcoal->rx_coalesce_usecs_irq ||
1056 ethcoal->rx_max_coalesced_frames_irq ||
1057 ethcoal->tx_coalesce_usecs_irq ||
1058 ethcoal->tx_max_coalesced_frames_irq ||
1059 ethcoal->stats_block_coalesce_usecs ||
1060 ethcoal->use_adaptive_rx_coalesce ||
1061 ethcoal->use_adaptive_tx_coalesce ||
1062 ethcoal->pkt_rate_low ||
1063 ethcoal->rx_coalesce_usecs_low ||
1064 ethcoal->rx_max_coalesced_frames_low ||
1065 ethcoal->tx_coalesce_usecs_low ||
1066 ethcoal->tx_max_coalesced_frames_low ||
1067 ethcoal->pkt_rate_high ||
1068 ethcoal->rx_coalesce_usecs_high ||
1069 ethcoal->rx_max_coalesced_frames_high ||
1070 ethcoal->tx_coalesce_usecs_high ||
1071 ethcoal->tx_max_coalesced_frames_high)
1072 return -EINVAL;
1073
1074 if (!ethcoal->rx_coalesce_usecs ||
1075 !ethcoal->rx_max_coalesced_frames) {
1076 adapter->coal.flags = QLCNIC_INTR_DEFAULT;
1077 adapter->coal.normal.data.rx_time_us =
1078 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
1079 adapter->coal.normal.data.rx_packets =
1080 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1081 } else {
1082 adapter->coal.flags = 0;
1083 adapter->coal.normal.data.rx_time_us =
1084 ethcoal->rx_coalesce_usecs;
1085 adapter->coal.normal.data.rx_packets =
1086 ethcoal->rx_max_coalesced_frames;
1087 }
1088 adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs;
1089 adapter->coal.normal.data.tx_packets =
1090 ethcoal->tx_max_coalesced_frames;
1091
1092 qlcnic_config_intr_coalesce(adapter);
1093
1094 return 0;
1095}
1096
1097static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1098 struct ethtool_coalesce *ethcoal)
1099{
1100 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1101
1102 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1103 return -EINVAL;
1104
1105 ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us;
1106 ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us;
1107 ethcoal->rx_max_coalesced_frames =
1108 adapter->coal.normal.data.rx_packets;
1109 ethcoal->tx_max_coalesced_frames =
1110 adapter->coal.normal.data.tx_packets;
1111
1112 return 0;
1113}
1114
1115static int qlcnic_set_flags(struct net_device *netdev, u32 data)
1116{
1117 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1118 int hw_lro;
1119
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001120 if (data & ~ETH_FLAG_LRO)
Ben Hutchings97d19352010-06-30 02:46:56 +00001121 return -EINVAL;
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001122
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001123 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
1124 return -EINVAL;
1125
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001126 if (!adapter->rx_csum) {
1127 dev_info(&adapter->pdev->dev, "rx csum is off, "
1128 "cannot toggle lro\n");
1129 return -EINVAL;
1130 }
1131
Amit Kumar Salechaa2152d02010-10-07 23:46:07 +00001132 if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO))
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001133 return 0;
1134
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001135 if (data & ETH_FLAG_LRO) {
1136 hw_lro = QLCNIC_LRO_ENABLED;
1137 netdev->features |= NETIF_F_LRO;
1138 } else {
1139 hw_lro = 0;
1140 netdev->features &= ~NETIF_F_LRO;
1141 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001142
1143 if (qlcnic_config_hw_lro(adapter, hw_lro))
1144 return -EIO;
1145
1146 if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
1147 return -EIO;
1148
1149
1150 return 0;
1151}
1152
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001153static u32 qlcnic_get_msglevel(struct net_device *netdev)
1154{
1155 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1156
1157 return adapter->msg_enable;
1158}
1159
1160static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1161{
1162 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1163
1164 adapter->msg_enable = msglvl;
1165}
1166
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001167const struct ethtool_ops qlcnic_ethtool_ops = {
1168 .get_settings = qlcnic_get_settings,
1169 .set_settings = qlcnic_set_settings,
1170 .get_drvinfo = qlcnic_get_drvinfo,
1171 .get_regs_len = qlcnic_get_regs_len,
1172 .get_regs = qlcnic_get_regs,
1173 .get_link = ethtool_op_get_link,
1174 .get_eeprom_len = qlcnic_get_eeprom_len,
1175 .get_eeprom = qlcnic_get_eeprom,
1176 .get_ringparam = qlcnic_get_ringparam,
1177 .set_ringparam = qlcnic_set_ringparam,
1178 .get_pauseparam = qlcnic_get_pauseparam,
1179 .set_pauseparam = qlcnic_set_pauseparam,
Sucheta Chakraborty8bae5692010-03-08 00:14:45 +00001180 .get_tx_csum = qlcnic_get_tx_csum,
Rajesh Borundia0325d692010-08-19 05:08:26 +00001181 .set_tx_csum = qlcnic_set_tx_csum,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001182 .set_sg = ethtool_op_set_sg,
1183 .get_tso = qlcnic_get_tso,
1184 .set_tso = qlcnic_set_tso,
1185 .get_wol = qlcnic_get_wol,
1186 .set_wol = qlcnic_set_wol,
1187 .self_test = qlcnic_diag_test,
1188 .get_strings = qlcnic_get_strings,
1189 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1190 .get_sset_count = qlcnic_get_sset_count,
1191 .get_rx_csum = qlcnic_get_rx_csum,
1192 .set_rx_csum = qlcnic_set_rx_csum,
1193 .get_coalesce = qlcnic_get_intr_coalesce,
1194 .set_coalesce = qlcnic_set_intr_coalesce,
1195 .get_flags = ethtool_op_get_flags,
1196 .set_flags = qlcnic_set_flags,
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001197 .phys_id = qlcnic_blink_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001198 .set_msglevel = qlcnic_set_msglevel,
1199 .get_msglevel = qlcnic_get_msglevel,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001200};