blob: 2aa9d8b2bab3f766814b72e4b037040a0055aa40 [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",
Sucheta Chakraborty97319a272010-12-02 20:41:23 +0000104 "Interrupt_Test_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000105};
106
107#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
108
109#define QLCNIC_RING_REGS_COUNT 20
110#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
111#define QLCNIC_MAX_EEPROM_LEN 1024
112
113static const u32 diag_registers[] = {
114 CRB_CMDPEG_STATE,
115 CRB_RCVPEG_STATE,
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000116 CRB_XG_STATE_P3P,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000117 CRB_FW_CAPABILITIES_1,
118 ISR_INT_STATE_REG,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000119 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000120 QLCNIC_CRB_DEV_STATE,
121 QLCNIC_CRB_DRV_STATE,
122 QLCNIC_CRB_DRV_SCRATCH,
123 QLCNIC_CRB_DEV_PARTITION_INFO,
124 QLCNIC_CRB_DRV_IDC_VER,
125 QLCNIC_PEG_ALIVE_COUNTER,
126 QLCNIC_PEG_HALT_STATUS1,
127 QLCNIC_PEG_HALT_STATUS2,
128 QLCNIC_CRB_PEG_NET_0+0x3c,
129 QLCNIC_CRB_PEG_NET_1+0x3c,
130 QLCNIC_CRB_PEG_NET_2+0x3c,
131 QLCNIC_CRB_PEG_NET_4+0x3c,
132 -1
133};
134
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000135#define QLCNIC_MGMT_API_VERSION 2
136#define QLCNIC_DEV_INFO_SIZE 1
137#define QLCNIC_ETHTOOL_REGS_VER 2
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000138static int qlcnic_get_regs_len(struct net_device *dev)
139{
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000140 return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
141 QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000142}
143
144static int qlcnic_get_eeprom_len(struct net_device *dev)
145{
146 return QLCNIC_FLASH_TOTAL_SIZE;
147}
148
149static void
150qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
151{
152 struct qlcnic_adapter *adapter = netdev_priv(dev);
153 u32 fw_major, fw_minor, fw_build;
154
155 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
156 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
157 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
158 sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
159
160 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
161 strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
162 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
163}
164
165static int
166qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
167{
168 struct qlcnic_adapter *adapter = netdev_priv(dev);
169 int check_sfp_module = 0;
170 u16 pcifn = adapter->ahw.pci_func;
171
172 /* read which mode */
173 if (adapter->ahw.port_type == QLCNIC_GBE) {
174 ecmd->supported = (SUPPORTED_10baseT_Half |
175 SUPPORTED_10baseT_Full |
176 SUPPORTED_100baseT_Half |
177 SUPPORTED_100baseT_Full |
178 SUPPORTED_1000baseT_Half |
179 SUPPORTED_1000baseT_Full);
180
181 ecmd->advertising = (ADVERTISED_100baseT_Half |
182 ADVERTISED_100baseT_Full |
183 ADVERTISED_1000baseT_Half |
184 ADVERTISED_1000baseT_Full);
185
186 ecmd->speed = adapter->link_speed;
187 ecmd->duplex = adapter->link_duplex;
188 ecmd->autoneg = adapter->link_autoneg;
189
190 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
191 u32 val;
192
193 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
194 if (val == QLCNIC_PORT_MODE_802_3_AP) {
195 ecmd->supported = SUPPORTED_1000baseT_Full;
196 ecmd->advertising = ADVERTISED_1000baseT_Full;
197 } else {
198 ecmd->supported = SUPPORTED_10000baseT_Full;
199 ecmd->advertising = ADVERTISED_10000baseT_Full;
200 }
201
202 if (netif_running(dev) && adapter->has_link_events) {
203 ecmd->speed = adapter->link_speed;
204 ecmd->autoneg = adapter->link_autoneg;
205 ecmd->duplex = adapter->link_duplex;
206 goto skip;
207 }
208
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000209 val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
210 ecmd->speed = P3P_LINK_SPEED_MHZ *
211 P3P_LINK_SPEED_VAL(pcifn, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000212 ecmd->duplex = DUPLEX_FULL;
213 ecmd->autoneg = AUTONEG_DISABLE;
214 } else
215 return -EIO;
216
217skip:
218 ecmd->phy_address = adapter->physical_port;
219 ecmd->transceiver = XCVR_EXTERNAL;
220
221 switch (adapter->ahw.board_type) {
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000222 case QLCNIC_BRDTYPE_P3P_REF_QG:
223 case QLCNIC_BRDTYPE_P3P_4_GB:
224 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000225
226 ecmd->supported |= SUPPORTED_Autoneg;
227 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000228 case QLCNIC_BRDTYPE_P3P_10G_CX4:
229 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
230 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000231 ecmd->supported |= SUPPORTED_TP;
232 ecmd->advertising |= ADVERTISED_TP;
233 ecmd->port = PORT_TP;
234 ecmd->autoneg = adapter->link_autoneg;
235 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000236 case QLCNIC_BRDTYPE_P3P_IMEZ:
237 case QLCNIC_BRDTYPE_P3P_XG_LOM:
238 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000239 ecmd->supported |= SUPPORTED_MII;
240 ecmd->advertising |= ADVERTISED_MII;
241 ecmd->port = PORT_MII;
242 ecmd->autoneg = AUTONEG_DISABLE;
243 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000244 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
245 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
246 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000247 ecmd->advertising |= ADVERTISED_TP;
248 ecmd->supported |= SUPPORTED_TP;
249 check_sfp_module = netif_running(dev) &&
250 adapter->has_link_events;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000251 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000252 ecmd->supported |= SUPPORTED_FIBRE;
253 ecmd->advertising |= ADVERTISED_FIBRE;
254 ecmd->port = PORT_FIBRE;
255 ecmd->autoneg = AUTONEG_DISABLE;
256 break;
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000257 case QLCNIC_BRDTYPE_P3P_10G_TP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000258 if (adapter->ahw.port_type == QLCNIC_XGBE) {
259 ecmd->autoneg = AUTONEG_DISABLE;
260 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
261 ecmd->advertising |=
262 (ADVERTISED_FIBRE | ADVERTISED_TP);
263 ecmd->port = PORT_FIBRE;
264 check_sfp_module = netif_running(dev) &&
265 adapter->has_link_events;
266 } else {
267 ecmd->autoneg = AUTONEG_ENABLE;
268 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
269 ecmd->advertising |=
270 (ADVERTISED_TP | ADVERTISED_Autoneg);
271 ecmd->port = PORT_TP;
272 }
273 break;
274 default:
275 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
276 adapter->ahw.board_type);
277 return -EIO;
278 }
279
280 if (check_sfp_module) {
281 switch (adapter->module_type) {
282 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
283 case LINKEVENT_MODULE_OPTICAL_SRLR:
284 case LINKEVENT_MODULE_OPTICAL_LRM:
285 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
286 ecmd->port = PORT_FIBRE;
287 break;
288 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
289 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
290 case LINKEVENT_MODULE_TWINAX:
291 ecmd->port = PORT_TP;
292 break;
293 default:
294 ecmd->port = PORT_OTHER;
295 }
296 }
297
298 return 0;
299}
300
301static int
302qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
303{
304 struct qlcnic_adapter *adapter = netdev_priv(dev);
305 __u32 status;
306
307 /* read which mode */
308 if (adapter->ahw.port_type == QLCNIC_GBE) {
309 /* autonegotiation */
310 if (qlcnic_fw_cmd_set_phy(adapter,
311 QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG,
312 ecmd->autoneg) != 0)
313 return -EIO;
314 else
315 adapter->link_autoneg = ecmd->autoneg;
316
317 if (qlcnic_fw_cmd_query_phy(adapter,
318 QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
319 &status) != 0)
320 return -EIO;
321
322 switch (ecmd->speed) {
323 case SPEED_10:
324 qlcnic_set_phy_speed(status, 0);
325 break;
326 case SPEED_100:
327 qlcnic_set_phy_speed(status, 1);
328 break;
329 case SPEED_1000:
330 qlcnic_set_phy_speed(status, 2);
331 break;
332 }
333
334 if (ecmd->duplex == DUPLEX_HALF)
335 qlcnic_clear_phy_duplex(status);
336 if (ecmd->duplex == DUPLEX_FULL)
337 qlcnic_set_phy_duplex(status);
338 if (qlcnic_fw_cmd_set_phy(adapter,
339 QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
340 *((int *)&status)) != 0)
341 return -EIO;
342 else {
343 adapter->link_speed = ecmd->speed;
344 adapter->link_duplex = ecmd->duplex;
345 }
346 } else
347 return -EOPNOTSUPP;
348
349 if (!netif_running(dev))
350 return 0;
351
352 dev->netdev_ops->ndo_stop(dev);
353 return dev->netdev_ops->ndo_open(dev);
354}
355
356static void
357qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
358{
359 struct qlcnic_adapter *adapter = netdev_priv(dev);
360 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
361 struct qlcnic_host_sds_ring *sds_ring;
362 u32 *regs_buff = p;
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000363 int ring, i = 0, j = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000364
365 memset(p, 0, qlcnic_get_regs_len(dev));
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000366 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
367 (adapter->ahw.revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000368
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000369 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
370 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
371
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000372 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
373 regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000374
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000375 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000376 return;
377
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000378 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
379
380 regs_buff[i++] = 1; /* No. of tx ring */
381 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
382 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
383
384 regs_buff[i++] = 2; /* No. of rx ring */
385 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
386 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
387
388 regs_buff[i++] = adapter->max_sds_rings;
389
390 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
391 sds_ring = &(recv_ctx->sds_rings[ring]);
392 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
393 }
394}
395
396static u32 qlcnic_test_link(struct net_device *dev)
397{
398 struct qlcnic_adapter *adapter = netdev_priv(dev);
399 u32 val;
400
Sritej Velagaff1b1bf2010-10-07 23:46:10 +0000401 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
402 val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val);
403 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000404}
405
406static int
407qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
408 u8 *bytes)
409{
410 struct qlcnic_adapter *adapter = netdev_priv(dev);
411 int offset;
412 int ret;
413
414 if (eeprom->len == 0)
415 return -EINVAL;
416
417 eeprom->magic = (adapter->pdev)->vendor |
418 ((adapter->pdev)->device << 16);
419 offset = eeprom->offset;
420
421 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
422 eeprom->len);
423 if (ret < 0)
424 return ret;
425
426 return 0;
427}
428
429static void
430qlcnic_get_ringparam(struct net_device *dev,
431 struct ethtool_ringparam *ring)
432{
433 struct qlcnic_adapter *adapter = netdev_priv(dev);
434
435 ring->rx_pending = adapter->num_rxd;
436 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000437 ring->tx_pending = adapter->num_txd;
438
Sony Chacko90d19002010-10-26 17:53:08 +0000439 ring->rx_max_pending = adapter->max_rxd;
440 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000441 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
442
443 ring->rx_mini_max_pending = 0;
444 ring->rx_mini_pending = 0;
445}
446
447static u32
448qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
449{
450 u32 num_desc;
451 num_desc = max(val, min);
452 num_desc = min(num_desc, max);
453 num_desc = roundup_pow_of_two(num_desc);
454
455 if (val != num_desc) {
456 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
457 qlcnic_driver_name, r_name, num_desc, val);
458 }
459
460 return num_desc;
461}
462
463static int
464qlcnic_set_ringparam(struct net_device *dev,
465 struct ethtool_ringparam *ring)
466{
467 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000468 u16 num_rxd, num_jumbo_rxd, num_txd;
469
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000470 if (ring->rx_mini_pending)
471 return -EOPNOTSUPP;
472
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000473 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000474 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000475
476 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000477 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
478 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000479
480 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
481 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
482
483 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
484 num_jumbo_rxd == adapter->num_jumbo_rxd)
485 return 0;
486
487 adapter->num_rxd = num_rxd;
488 adapter->num_jumbo_rxd = num_jumbo_rxd;
489 adapter->num_txd = num_txd;
490
491 return qlcnic_reset_context(adapter);
492}
493
494static void
495qlcnic_get_pauseparam(struct net_device *netdev,
496 struct ethtool_pauseparam *pause)
497{
498 struct qlcnic_adapter *adapter = netdev_priv(netdev);
499 int port = adapter->physical_port;
500 __u32 val;
501
502 if (adapter->ahw.port_type == QLCNIC_GBE) {
503 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
504 return;
505 /* get flow control settings */
506 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
507 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
508 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
509 switch (port) {
510 case 0:
511 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
512 break;
513 case 1:
514 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
515 break;
516 case 2:
517 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
518 break;
519 case 3:
520 default:
521 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
522 break;
523 }
524 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
525 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
526 return;
527 pause->rx_pause = 1;
528 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
529 if (port == 0)
530 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
531 else
532 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
533 } else {
534 dev_err(&netdev->dev, "Unknown board type: %x\n",
535 adapter->ahw.port_type);
536 }
537}
538
539static int
540qlcnic_set_pauseparam(struct net_device *netdev,
541 struct ethtool_pauseparam *pause)
542{
543 struct qlcnic_adapter *adapter = netdev_priv(netdev);
544 int port = adapter->physical_port;
545 __u32 val;
546
547 /* read mode */
548 if (adapter->ahw.port_type == QLCNIC_GBE) {
549 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
550 return -EIO;
551 /* set flow control */
552 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
553
554 if (pause->rx_pause)
555 qlcnic_gb_rx_flowctl(val);
556 else
557 qlcnic_gb_unset_rx_flowctl(val);
558
559 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
560 val);
561 /* set autoneg */
562 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
563 switch (port) {
564 case 0:
565 if (pause->tx_pause)
566 qlcnic_gb_unset_gb0_mask(val);
567 else
568 qlcnic_gb_set_gb0_mask(val);
569 break;
570 case 1:
571 if (pause->tx_pause)
572 qlcnic_gb_unset_gb1_mask(val);
573 else
574 qlcnic_gb_set_gb1_mask(val);
575 break;
576 case 2:
577 if (pause->tx_pause)
578 qlcnic_gb_unset_gb2_mask(val);
579 else
580 qlcnic_gb_set_gb2_mask(val);
581 break;
582 case 3:
583 default:
584 if (pause->tx_pause)
585 qlcnic_gb_unset_gb3_mask(val);
586 else
587 qlcnic_gb_set_gb3_mask(val);
588 break;
589 }
590 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
591 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000592 if (!pause->rx_pause || pause->autoneg)
593 return -EOPNOTSUPP;
594
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000595 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
596 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000597
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000598 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
599 if (port == 0) {
600 if (pause->tx_pause)
601 qlcnic_xg_unset_xg0_mask(val);
602 else
603 qlcnic_xg_set_xg0_mask(val);
604 } else {
605 if (pause->tx_pause)
606 qlcnic_xg_unset_xg1_mask(val);
607 else
608 qlcnic_xg_set_xg1_mask(val);
609 }
610 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
611 } else {
612 dev_err(&netdev->dev, "Unknown board type: %x\n",
613 adapter->ahw.port_type);
614 }
615 return 0;
616}
617
618static int qlcnic_reg_test(struct net_device *dev)
619{
620 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000621 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000622
623 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
624 if ((data_read & 0xffff) != adapter->pdev->vendor)
625 return 1;
626
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000627 return 0;
628}
629
630static int qlcnic_get_sset_count(struct net_device *dev, int sset)
631{
amit salecha3666e0b2010-10-18 01:47:48 +0000632 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000633 switch (sset) {
634 case ETH_SS_TEST:
635 return QLCNIC_TEST_LEN;
636 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000637 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
638 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000639 return QLCNIC_STATS_LEN;
640 default:
641 return -EOPNOTSUPP;
642 }
643}
644
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000645static int qlcnic_irq_test(struct net_device *netdev)
646{
647 struct qlcnic_adapter *adapter = netdev_priv(netdev);
648 int max_sds_rings = adapter->max_sds_rings;
649 int ret;
650
651 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
652 return -EIO;
653
654 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
655 if (ret)
656 goto clear_it;
657
658 adapter->diag_cnt = 0;
659 ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000660 adapter->fw_hal_version, adapter->portnum,
661 0, 0, 0x00000011);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000662 if (ret)
663 goto done;
664
665 msleep(10);
666
667 ret = !adapter->diag_cnt;
668
669done:
670 qlcnic_diag_free_res(netdev, max_sds_rings);
671
672clear_it:
673 adapter->max_sds_rings = max_sds_rings;
674 clear_bit(__QLCNIC_RESETTING, &adapter->state);
675 return ret;
676}
677
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000678static void
679qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
680 u64 *data)
681{
682 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000683
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000684 data[0] = qlcnic_reg_test(dev);
685 if (data[0])
686 eth_test->flags |= ETH_TEST_FL_FAILED;
687
688 data[1] = (u64) qlcnic_test_link(dev);
689 if (data[1])
690 eth_test->flags |= ETH_TEST_FL_FAILED;
691
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000692 if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
693 data[2] = qlcnic_irq_test(dev);
694 if (data[2])
695 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000696
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000697
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000698 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000699}
700
701static void
702qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
703{
amit salecha3666e0b2010-10-18 01:47:48 +0000704 struct qlcnic_adapter *adapter = netdev_priv(dev);
705 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000706
707 switch (stringset) {
708 case ETH_SS_TEST:
709 memcpy(data, *qlcnic_gstrings_test,
710 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
711 break;
712 case ETH_SS_STATS:
713 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
714 memcpy(data + index * ETH_GSTRING_LEN,
715 qlcnic_gstrings_stats[index].stat_string,
716 ETH_GSTRING_LEN);
717 }
amit salecha3666e0b2010-10-18 01:47:48 +0000718 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
719 return;
720 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
721 memcpy(data + index * ETH_GSTRING_LEN,
722 qlcnic_device_gstrings_stats[i],
723 ETH_GSTRING_LEN);
724 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000725 }
726}
727
amit salecha3666e0b2010-10-18 01:47:48 +0000728#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
729 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
730
731static void
732qlcnic_fill_device_stats(int *index, u64 *data,
733 struct __qlcnic_esw_statistics *stats)
734{
735 int ind = *index;
736
737 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
738 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
739 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
740 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
741 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
742 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
743 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
744
745 *index = ind;
746}
747
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000748static void
749qlcnic_get_ethtool_stats(struct net_device *dev,
750 struct ethtool_stats *stats, u64 * data)
751{
752 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000753 struct qlcnic_esw_statistics port_stats;
754 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000755
756 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
757 char *p =
758 (char *)adapter +
759 qlcnic_gstrings_stats[index].stat_offset;
760 data[index] =
761 (qlcnic_gstrings_stats[index].sizeof_stat ==
762 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
763 }
amit salecha3666e0b2010-10-18 01:47:48 +0000764
765 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
766 return;
767
768 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
769 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
770 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
771 if (ret)
772 return;
773
774 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
775
776 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
777 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
778 if (ret)
779 return;
780
781 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000782}
783
Rajesh Borundia0325d692010-08-19 05:08:26 +0000784static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
785{
786 struct qlcnic_adapter *adapter = netdev_priv(dev);
787
788 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
789 return -EOPNOTSUPP;
790 if (data)
791 dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
792 else
793 dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
794
795 return 0;
796
797}
Sucheta Chakraborty8bae5692010-03-08 00:14:45 +0000798static u32 qlcnic_get_tx_csum(struct net_device *dev)
799{
800 return dev->features & NETIF_F_IP_CSUM;
801}
802
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000803static u32 qlcnic_get_rx_csum(struct net_device *dev)
804{
805 struct qlcnic_adapter *adapter = netdev_priv(dev);
806 return adapter->rx_csum;
807}
808
809static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
810{
811 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000812
Rajesh Borundia0325d692010-08-19 05:08:26 +0000813 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
814 return -EOPNOTSUPP;
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000815 if (!!data) {
816 adapter->rx_csum = !!data;
817 return 0;
818 }
819
Amit Kumar Salechaa2152d02010-10-07 23:46:07 +0000820 if (dev->features & NETIF_F_LRO) {
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000821 if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED))
822 return -EIO;
823
824 dev->features &= ~NETIF_F_LRO;
825 qlcnic_send_lro_cleanup(adapter);
Sony Chacko706f23a2010-11-16 14:08:46 +0000826 dev_info(&adapter->pdev->dev,
827 "disabling LRO as rx_csum is off\n");
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000828 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000829 adapter->rx_csum = !!data;
830 return 0;
831}
832
833static u32 qlcnic_get_tso(struct net_device *dev)
834{
835 return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
836}
837
838static int qlcnic_set_tso(struct net_device *dev, u32 data)
839{
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +0000840 struct qlcnic_adapter *adapter = netdev_priv(dev);
841 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO))
842 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000843 if (data)
844 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
845 else
846 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
847
848 return 0;
849}
850
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000851static int qlcnic_blink_led(struct net_device *dev, u32 val)
852{
853 struct qlcnic_adapter *adapter = netdev_priv(dev);
854 int ret;
855
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000856 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
857 return -EIO;
858
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000859 ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000860 if (ret) {
861 dev_err(&adapter->pdev->dev,
862 "Failed to set LED blink state.\n");
863 return ret;
864 }
865
866 msleep_interruptible(val * 1000);
867
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000868 ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000869 if (ret) {
870 dev_err(&adapter->pdev->dev,
871 "Failed to reset LED blink state.\n");
872 return ret;
873 }
874
875 return 0;
876}
877
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000878static void
879qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
880{
881 struct qlcnic_adapter *adapter = netdev_priv(dev);
882 u32 wol_cfg;
883
884 wol->supported = 0;
885 wol->wolopts = 0;
886
887 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
888 if (wol_cfg & (1UL << adapter->portnum))
889 wol->supported |= WAKE_MAGIC;
890
891 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
892 if (wol_cfg & (1UL << adapter->portnum))
893 wol->wolopts |= WAKE_MAGIC;
894}
895
896static int
897qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
898{
899 struct qlcnic_adapter *adapter = netdev_priv(dev);
900 u32 wol_cfg;
901
902 if (wol->wolopts & ~WAKE_MAGIC)
903 return -EOPNOTSUPP;
904
905 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
906 if (!(wol_cfg & (1 << adapter->portnum)))
907 return -EOPNOTSUPP;
908
909 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
910 if (wol->wolopts & WAKE_MAGIC)
911 wol_cfg |= 1UL << adapter->portnum;
912 else
913 wol_cfg &= ~(1UL << adapter->portnum);
914
915 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
916
917 return 0;
918}
919
920/*
921 * Set the coalescing parameters. Currently only normal is supported.
922 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
923 * firmware coalescing to default.
924 */
925static int qlcnic_set_intr_coalesce(struct net_device *netdev,
926 struct ethtool_coalesce *ethcoal)
927{
928 struct qlcnic_adapter *adapter = netdev_priv(netdev);
929
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000930 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000931 return -EINVAL;
932
933 /*
934 * Return Error if unsupported values or
935 * unsupported parameters are set.
936 */
937 if (ethcoal->rx_coalesce_usecs > 0xffff ||
938 ethcoal->rx_max_coalesced_frames > 0xffff ||
939 ethcoal->tx_coalesce_usecs > 0xffff ||
940 ethcoal->tx_max_coalesced_frames > 0xffff ||
941 ethcoal->rx_coalesce_usecs_irq ||
942 ethcoal->rx_max_coalesced_frames_irq ||
943 ethcoal->tx_coalesce_usecs_irq ||
944 ethcoal->tx_max_coalesced_frames_irq ||
945 ethcoal->stats_block_coalesce_usecs ||
946 ethcoal->use_adaptive_rx_coalesce ||
947 ethcoal->use_adaptive_tx_coalesce ||
948 ethcoal->pkt_rate_low ||
949 ethcoal->rx_coalesce_usecs_low ||
950 ethcoal->rx_max_coalesced_frames_low ||
951 ethcoal->tx_coalesce_usecs_low ||
952 ethcoal->tx_max_coalesced_frames_low ||
953 ethcoal->pkt_rate_high ||
954 ethcoal->rx_coalesce_usecs_high ||
955 ethcoal->rx_max_coalesced_frames_high ||
956 ethcoal->tx_coalesce_usecs_high ||
957 ethcoal->tx_max_coalesced_frames_high)
958 return -EINVAL;
959
960 if (!ethcoal->rx_coalesce_usecs ||
961 !ethcoal->rx_max_coalesced_frames) {
962 adapter->coal.flags = QLCNIC_INTR_DEFAULT;
963 adapter->coal.normal.data.rx_time_us =
964 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
965 adapter->coal.normal.data.rx_packets =
966 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
967 } else {
968 adapter->coal.flags = 0;
969 adapter->coal.normal.data.rx_time_us =
970 ethcoal->rx_coalesce_usecs;
971 adapter->coal.normal.data.rx_packets =
972 ethcoal->rx_max_coalesced_frames;
973 }
974 adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs;
975 adapter->coal.normal.data.tx_packets =
976 ethcoal->tx_max_coalesced_frames;
977
978 qlcnic_config_intr_coalesce(adapter);
979
980 return 0;
981}
982
983static int qlcnic_get_intr_coalesce(struct net_device *netdev,
984 struct ethtool_coalesce *ethcoal)
985{
986 struct qlcnic_adapter *adapter = netdev_priv(netdev);
987
988 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
989 return -EINVAL;
990
991 ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us;
992 ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us;
993 ethcoal->rx_max_coalesced_frames =
994 adapter->coal.normal.data.rx_packets;
995 ethcoal->tx_max_coalesced_frames =
996 adapter->coal.normal.data.tx_packets;
997
998 return 0;
999}
1000
1001static int qlcnic_set_flags(struct net_device *netdev, u32 data)
1002{
1003 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1004 int hw_lro;
1005
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001006 if (data & ~ETH_FLAG_LRO)
Ben Hutchings97d19352010-06-30 02:46:56 +00001007 return -EINVAL;
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001008
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001009 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
1010 return -EINVAL;
1011
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001012 if (!adapter->rx_csum) {
1013 dev_info(&adapter->pdev->dev, "rx csum is off, "
1014 "cannot toggle lro\n");
1015 return -EINVAL;
1016 }
1017
Amit Kumar Salechaa2152d02010-10-07 23:46:07 +00001018 if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO))
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001019 return 0;
1020
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001021 if (data & ETH_FLAG_LRO) {
1022 hw_lro = QLCNIC_LRO_ENABLED;
1023 netdev->features |= NETIF_F_LRO;
1024 } else {
1025 hw_lro = 0;
1026 netdev->features &= ~NETIF_F_LRO;
1027 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001028
1029 if (qlcnic_config_hw_lro(adapter, hw_lro))
1030 return -EIO;
1031
1032 if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
1033 return -EIO;
1034
1035
1036 return 0;
1037}
1038
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001039static u32 qlcnic_get_msglevel(struct net_device *netdev)
1040{
1041 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1042
1043 return adapter->msg_enable;
1044}
1045
1046static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1047{
1048 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1049
1050 adapter->msg_enable = msglvl;
1051}
1052
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001053const struct ethtool_ops qlcnic_ethtool_ops = {
1054 .get_settings = qlcnic_get_settings,
1055 .set_settings = qlcnic_set_settings,
1056 .get_drvinfo = qlcnic_get_drvinfo,
1057 .get_regs_len = qlcnic_get_regs_len,
1058 .get_regs = qlcnic_get_regs,
1059 .get_link = ethtool_op_get_link,
1060 .get_eeprom_len = qlcnic_get_eeprom_len,
1061 .get_eeprom = qlcnic_get_eeprom,
1062 .get_ringparam = qlcnic_get_ringparam,
1063 .set_ringparam = qlcnic_set_ringparam,
1064 .get_pauseparam = qlcnic_get_pauseparam,
1065 .set_pauseparam = qlcnic_set_pauseparam,
Sucheta Chakraborty8bae5692010-03-08 00:14:45 +00001066 .get_tx_csum = qlcnic_get_tx_csum,
Rajesh Borundia0325d692010-08-19 05:08:26 +00001067 .set_tx_csum = qlcnic_set_tx_csum,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001068 .set_sg = ethtool_op_set_sg,
1069 .get_tso = qlcnic_get_tso,
1070 .set_tso = qlcnic_set_tso,
1071 .get_wol = qlcnic_get_wol,
1072 .set_wol = qlcnic_set_wol,
1073 .self_test = qlcnic_diag_test,
1074 .get_strings = qlcnic_get_strings,
1075 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1076 .get_sset_count = qlcnic_get_sset_count,
1077 .get_rx_csum = qlcnic_get_rx_csum,
1078 .set_rx_csum = qlcnic_set_rx_csum,
1079 .get_coalesce = qlcnic_get_intr_coalesce,
1080 .set_coalesce = qlcnic_set_intr_coalesce,
1081 .get_flags = ethtool_op_get_flags,
1082 .set_flags = qlcnic_set_flags,
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001083 .phys_id = qlcnic_blink_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001084 .set_msglevel = qlcnic_set_msglevel,
1085 .get_msglevel = qlcnic_get_msglevel,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001086};