blob: ec21d24015c485a7153e4262026f89d1c73af6c3 [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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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 Velagaff1b1bf82010-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
Sony Chacko90d19002010-10-26 17:53:08 +0000440 ring->rx_max_pending = adapter->max_rxd;
441 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000442 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
443
444 ring->rx_mini_max_pending = 0;
445 ring->rx_mini_pending = 0;
446}
447
448static u32
449qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
450{
451 u32 num_desc;
452 num_desc = max(val, min);
453 num_desc = min(num_desc, max);
454 num_desc = roundup_pow_of_two(num_desc);
455
456 if (val != num_desc) {
457 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
458 qlcnic_driver_name, r_name, num_desc, val);
459 }
460
461 return num_desc;
462}
463
464static int
465qlcnic_set_ringparam(struct net_device *dev,
466 struct ethtool_ringparam *ring)
467{
468 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000469 u16 num_rxd, num_jumbo_rxd, num_txd;
470
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000471 if (ring->rx_mini_pending)
472 return -EOPNOTSUPP;
473
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000474 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000475 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000476
477 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000478 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
479 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000480
481 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
482 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
483
484 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
485 num_jumbo_rxd == adapter->num_jumbo_rxd)
486 return 0;
487
488 adapter->num_rxd = num_rxd;
489 adapter->num_jumbo_rxd = num_jumbo_rxd;
490 adapter->num_txd = num_txd;
491
492 return qlcnic_reset_context(adapter);
493}
494
495static void
496qlcnic_get_pauseparam(struct net_device *netdev,
497 struct ethtool_pauseparam *pause)
498{
499 struct qlcnic_adapter *adapter = netdev_priv(netdev);
500 int port = adapter->physical_port;
501 __u32 val;
502
503 if (adapter->ahw.port_type == QLCNIC_GBE) {
504 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
505 return;
506 /* get flow control settings */
507 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
508 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
509 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
510 switch (port) {
511 case 0:
512 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
513 break;
514 case 1:
515 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
516 break;
517 case 2:
518 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
519 break;
520 case 3:
521 default:
522 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
523 break;
524 }
525 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
526 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
527 return;
528 pause->rx_pause = 1;
529 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
530 if (port == 0)
531 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
532 else
533 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
534 } else {
535 dev_err(&netdev->dev, "Unknown board type: %x\n",
536 adapter->ahw.port_type);
537 }
538}
539
540static int
541qlcnic_set_pauseparam(struct net_device *netdev,
542 struct ethtool_pauseparam *pause)
543{
544 struct qlcnic_adapter *adapter = netdev_priv(netdev);
545 int port = adapter->physical_port;
546 __u32 val;
547
548 /* read mode */
549 if (adapter->ahw.port_type == QLCNIC_GBE) {
550 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
551 return -EIO;
552 /* set flow control */
553 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
554
555 if (pause->rx_pause)
556 qlcnic_gb_rx_flowctl(val);
557 else
558 qlcnic_gb_unset_rx_flowctl(val);
559
560 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
561 val);
562 /* set autoneg */
563 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
564 switch (port) {
565 case 0:
566 if (pause->tx_pause)
567 qlcnic_gb_unset_gb0_mask(val);
568 else
569 qlcnic_gb_set_gb0_mask(val);
570 break;
571 case 1:
572 if (pause->tx_pause)
573 qlcnic_gb_unset_gb1_mask(val);
574 else
575 qlcnic_gb_set_gb1_mask(val);
576 break;
577 case 2:
578 if (pause->tx_pause)
579 qlcnic_gb_unset_gb2_mask(val);
580 else
581 qlcnic_gb_set_gb2_mask(val);
582 break;
583 case 3:
584 default:
585 if (pause->tx_pause)
586 qlcnic_gb_unset_gb3_mask(val);
587 else
588 qlcnic_gb_set_gb3_mask(val);
589 break;
590 }
591 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
592 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000593 if (!pause->rx_pause || pause->autoneg)
594 return -EOPNOTSUPP;
595
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000596 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
597 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000598
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000599 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
600 if (port == 0) {
601 if (pause->tx_pause)
602 qlcnic_xg_unset_xg0_mask(val);
603 else
604 qlcnic_xg_set_xg0_mask(val);
605 } else {
606 if (pause->tx_pause)
607 qlcnic_xg_unset_xg1_mask(val);
608 else
609 qlcnic_xg_set_xg1_mask(val);
610 }
611 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
612 } else {
613 dev_err(&netdev->dev, "Unknown board type: %x\n",
614 adapter->ahw.port_type);
615 }
616 return 0;
617}
618
619static int qlcnic_reg_test(struct net_device *dev)
620{
621 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000622 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000623
624 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
625 if ((data_read & 0xffff) != adapter->pdev->vendor)
626 return 1;
627
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000628 return 0;
629}
630
631static int qlcnic_get_sset_count(struct net_device *dev, int sset)
632{
amit salecha3666e0b2010-10-18 01:47:48 +0000633 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000634 switch (sset) {
635 case ETH_SS_TEST:
636 return QLCNIC_TEST_LEN;
637 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000638 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
639 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000640 return QLCNIC_STATS_LEN;
641 default:
642 return -EOPNOTSUPP;
643 }
644}
645
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000646#define QLC_ILB_PKT_SIZE 64
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000647#define QLC_NUM_ILB_PKT 16
648#define QLC_ILB_MAX_RCV_LOOP 10
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000649
650static void qlcnic_create_loopback_buff(unsigned char *data)
651{
652 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
653 memset(data, 0x4e, QLC_ILB_PKT_SIZE);
654 memset(data, 0xff, 12);
655 memcpy(data + 12, random_data, sizeof(random_data));
656}
657
658int qlcnic_check_loopback_buff(unsigned char *data)
659{
660 unsigned char buff[QLC_ILB_PKT_SIZE];
661 qlcnic_create_loopback_buff(buff);
662 return memcmp(data, buff, QLC_ILB_PKT_SIZE);
663}
664
665static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
666{
667 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
668 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
669 struct sk_buff *skb;
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000670 int i, loop, cnt = 0;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000671
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000672 for (i = 0; i < QLC_NUM_ILB_PKT; i++) {
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000673 skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
674 qlcnic_create_loopback_buff(skb->data);
675 skb_put(skb, QLC_ILB_PKT_SIZE);
676
677 adapter->diag_cnt = 0;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000678 qlcnic_xmit_frame(skb, adapter->netdev);
679
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000680 loop = 0;
681 do {
682 msleep(1);
683 qlcnic_process_rcv_ring_diag(sds_ring);
684 } while (loop++ < QLC_ILB_MAX_RCV_LOOP &&
685 !adapter->diag_cnt);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000686
687 dev_kfree_skb_any(skb);
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000688
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000689 if (!adapter->diag_cnt)
Amit Kumar Salecha31dee692010-10-04 04:20:09 +0000690 dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
691 " not recevied\n", i + 1);
692 else
693 cnt++;
694 }
695 if (cnt != i) {
696 dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
697 return -1;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000698 }
699 return 0;
700}
701
702static int qlcnic_loopback_test(struct net_device *netdev)
703{
704 struct qlcnic_adapter *adapter = netdev_priv(netdev);
705 int max_sds_rings = adapter->max_sds_rings;
706 int ret;
707
Amit Kumar Salecha36a18982010-07-24 18:32:17 +0000708 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
709 dev_warn(&adapter->pdev->dev, "Loopback test not supported"
710 "for non privilege function\n");
711 return 0;
712 }
713
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000714 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
715 return -EIO;
716
Amit Kumar Salechab8c17622010-10-07 23:46:06 +0000717 if (qlcnic_request_quiscent_mode(adapter)) {
718 clear_bit(__QLCNIC_RESETTING, &adapter->state);
719 return -EIO;
720 }
721
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000722 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
723 if (ret)
724 goto clear_it;
725
Amit Kumar Salecha36a18982010-07-24 18:32:17 +0000726 ret = qlcnic_set_ilb_mode(adapter);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000727 if (ret)
728 goto done;
729
730 ret = qlcnic_do_ilb_test(adapter);
731
Amit Kumar Salecha36a18982010-07-24 18:32:17 +0000732 qlcnic_clear_ilb_mode(adapter);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000733
734done:
735 qlcnic_diag_free_res(netdev, max_sds_rings);
736
737clear_it:
Amit Kumar Salechab8c17622010-10-07 23:46:06 +0000738 qlcnic_clear_quiscent_mode(adapter);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000739 adapter->max_sds_rings = max_sds_rings;
740 clear_bit(__QLCNIC_RESETTING, &adapter->state);
741 return ret;
742}
743
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000744static int qlcnic_irq_test(struct net_device *netdev)
745{
746 struct qlcnic_adapter *adapter = netdev_priv(netdev);
747 int max_sds_rings = adapter->max_sds_rings;
748 int ret;
749
750 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
751 return -EIO;
752
753 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
754 if (ret)
755 goto clear_it;
756
757 adapter->diag_cnt = 0;
758 ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000759 adapter->fw_hal_version, adapter->portnum,
760 0, 0, 0x00000011);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000761 if (ret)
762 goto done;
763
764 msleep(10);
765
766 ret = !adapter->diag_cnt;
767
768done:
769 qlcnic_diag_free_res(netdev, max_sds_rings);
770
771clear_it:
772 adapter->max_sds_rings = max_sds_rings;
773 clear_bit(__QLCNIC_RESETTING, &adapter->state);
774 return ret;
775}
776
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000777static void
778qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
779 u64 *data)
780{
781 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000782
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000783 data[0] = qlcnic_reg_test(dev);
784 if (data[0])
785 eth_test->flags |= ETH_TEST_FL_FAILED;
786
787 data[1] = (u64) qlcnic_test_link(dev);
788 if (data[1])
789 eth_test->flags |= ETH_TEST_FL_FAILED;
790
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000791 if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
792 data[2] = qlcnic_irq_test(dev);
793 if (data[2])
794 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000795
796 data[3] = qlcnic_loopback_test(dev);
797 if (data[3])
798 eth_test->flags |= ETH_TEST_FL_FAILED;
799
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000800 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000801}
802
803static void
804qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
805{
amit salecha3666e0b2010-10-18 01:47:48 +0000806 struct qlcnic_adapter *adapter = netdev_priv(dev);
807 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000808
809 switch (stringset) {
810 case ETH_SS_TEST:
811 memcpy(data, *qlcnic_gstrings_test,
812 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
813 break;
814 case ETH_SS_STATS:
815 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
816 memcpy(data + index * ETH_GSTRING_LEN,
817 qlcnic_gstrings_stats[index].stat_string,
818 ETH_GSTRING_LEN);
819 }
amit salecha3666e0b2010-10-18 01:47:48 +0000820 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
821 return;
822 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
823 memcpy(data + index * ETH_GSTRING_LEN,
824 qlcnic_device_gstrings_stats[i],
825 ETH_GSTRING_LEN);
826 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000827 }
828}
829
amit salecha3666e0b2010-10-18 01:47:48 +0000830#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
831 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
832
833static void
834qlcnic_fill_device_stats(int *index, u64 *data,
835 struct __qlcnic_esw_statistics *stats)
836{
837 int ind = *index;
838
839 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
840 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
841 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
842 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
843 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
844 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
845 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
846
847 *index = ind;
848}
849
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000850static void
851qlcnic_get_ethtool_stats(struct net_device *dev,
852 struct ethtool_stats *stats, u64 * data)
853{
854 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000855 struct qlcnic_esw_statistics port_stats;
856 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000857
858 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
859 char *p =
860 (char *)adapter +
861 qlcnic_gstrings_stats[index].stat_offset;
862 data[index] =
863 (qlcnic_gstrings_stats[index].sizeof_stat ==
864 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
865 }
amit salecha3666e0b2010-10-18 01:47:48 +0000866
867 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
868 return;
869
870 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
871 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
872 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
873 if (ret)
874 return;
875
876 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
877
878 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
879 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
880 if (ret)
881 return;
882
883 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000884}
885
Rajesh Borundia0325d692010-08-19 05:08:26 +0000886static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
887{
888 struct qlcnic_adapter *adapter = netdev_priv(dev);
889
890 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
891 return -EOPNOTSUPP;
892 if (data)
893 dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
894 else
895 dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
896
897 return 0;
898
899}
Sucheta Chakraborty8bae5692010-03-08 00:14:45 +0000900static u32 qlcnic_get_tx_csum(struct net_device *dev)
901{
902 return dev->features & NETIF_F_IP_CSUM;
903}
904
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000905static u32 qlcnic_get_rx_csum(struct net_device *dev)
906{
907 struct qlcnic_adapter *adapter = netdev_priv(dev);
908 return adapter->rx_csum;
909}
910
911static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
912{
913 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000914
Rajesh Borundia0325d692010-08-19 05:08:26 +0000915 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
916 return -EOPNOTSUPP;
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000917 if (!!data) {
918 adapter->rx_csum = !!data;
919 return 0;
920 }
921
Amit Kumar Salechaa2152d02010-10-07 23:46:07 +0000922 if (dev->features & NETIF_F_LRO) {
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000923 if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED))
924 return -EIO;
925
926 dev->features &= ~NETIF_F_LRO;
927 qlcnic_send_lro_cleanup(adapter);
928 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000929 adapter->rx_csum = !!data;
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000930 dev_info(&adapter->pdev->dev, "disabling LRO as rx_csum is off\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000931 return 0;
932}
933
934static u32 qlcnic_get_tso(struct net_device *dev)
935{
936 return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
937}
938
939static int qlcnic_set_tso(struct net_device *dev, u32 data)
940{
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +0000941 struct qlcnic_adapter *adapter = netdev_priv(dev);
942 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO))
943 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000944 if (data)
945 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
946 else
947 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
948
949 return 0;
950}
951
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000952static int qlcnic_blink_led(struct net_device *dev, u32 val)
953{
954 struct qlcnic_adapter *adapter = netdev_priv(dev);
955 int ret;
956
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000957 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
958 return -EIO;
959
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000960 ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000961 if (ret) {
962 dev_err(&adapter->pdev->dev,
963 "Failed to set LED blink state.\n");
964 return ret;
965 }
966
967 msleep_interruptible(val * 1000);
968
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000969 ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000970 if (ret) {
971 dev_err(&adapter->pdev->dev,
972 "Failed to reset LED blink state.\n");
973 return ret;
974 }
975
976 return 0;
977}
978
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000979static void
980qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
981{
982 struct qlcnic_adapter *adapter = netdev_priv(dev);
983 u32 wol_cfg;
984
985 wol->supported = 0;
986 wol->wolopts = 0;
987
988 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
989 if (wol_cfg & (1UL << adapter->portnum))
990 wol->supported |= WAKE_MAGIC;
991
992 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
993 if (wol_cfg & (1UL << adapter->portnum))
994 wol->wolopts |= WAKE_MAGIC;
995}
996
997static int
998qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
999{
1000 struct qlcnic_adapter *adapter = netdev_priv(dev);
1001 u32 wol_cfg;
1002
1003 if (wol->wolopts & ~WAKE_MAGIC)
1004 return -EOPNOTSUPP;
1005
1006 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1007 if (!(wol_cfg & (1 << adapter->portnum)))
1008 return -EOPNOTSUPP;
1009
1010 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1011 if (wol->wolopts & WAKE_MAGIC)
1012 wol_cfg |= 1UL << adapter->portnum;
1013 else
1014 wol_cfg &= ~(1UL << adapter->portnum);
1015
1016 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1017
1018 return 0;
1019}
1020
1021/*
1022 * Set the coalescing parameters. Currently only normal is supported.
1023 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1024 * firmware coalescing to default.
1025 */
1026static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1027 struct ethtool_coalesce *ethcoal)
1028{
1029 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1030
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001031 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001032 return -EINVAL;
1033
1034 /*
1035 * Return Error if unsupported values or
1036 * unsupported parameters are set.
1037 */
1038 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1039 ethcoal->rx_max_coalesced_frames > 0xffff ||
1040 ethcoal->tx_coalesce_usecs > 0xffff ||
1041 ethcoal->tx_max_coalesced_frames > 0xffff ||
1042 ethcoal->rx_coalesce_usecs_irq ||
1043 ethcoal->rx_max_coalesced_frames_irq ||
1044 ethcoal->tx_coalesce_usecs_irq ||
1045 ethcoal->tx_max_coalesced_frames_irq ||
1046 ethcoal->stats_block_coalesce_usecs ||
1047 ethcoal->use_adaptive_rx_coalesce ||
1048 ethcoal->use_adaptive_tx_coalesce ||
1049 ethcoal->pkt_rate_low ||
1050 ethcoal->rx_coalesce_usecs_low ||
1051 ethcoal->rx_max_coalesced_frames_low ||
1052 ethcoal->tx_coalesce_usecs_low ||
1053 ethcoal->tx_max_coalesced_frames_low ||
1054 ethcoal->pkt_rate_high ||
1055 ethcoal->rx_coalesce_usecs_high ||
1056 ethcoal->rx_max_coalesced_frames_high ||
1057 ethcoal->tx_coalesce_usecs_high ||
1058 ethcoal->tx_max_coalesced_frames_high)
1059 return -EINVAL;
1060
1061 if (!ethcoal->rx_coalesce_usecs ||
1062 !ethcoal->rx_max_coalesced_frames) {
1063 adapter->coal.flags = QLCNIC_INTR_DEFAULT;
1064 adapter->coal.normal.data.rx_time_us =
1065 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
1066 adapter->coal.normal.data.rx_packets =
1067 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1068 } else {
1069 adapter->coal.flags = 0;
1070 adapter->coal.normal.data.rx_time_us =
1071 ethcoal->rx_coalesce_usecs;
1072 adapter->coal.normal.data.rx_packets =
1073 ethcoal->rx_max_coalesced_frames;
1074 }
1075 adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs;
1076 adapter->coal.normal.data.tx_packets =
1077 ethcoal->tx_max_coalesced_frames;
1078
1079 qlcnic_config_intr_coalesce(adapter);
1080
1081 return 0;
1082}
1083
1084static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1085 struct ethtool_coalesce *ethcoal)
1086{
1087 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1088
1089 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1090 return -EINVAL;
1091
1092 ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us;
1093 ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us;
1094 ethcoal->rx_max_coalesced_frames =
1095 adapter->coal.normal.data.rx_packets;
1096 ethcoal->tx_max_coalesced_frames =
1097 adapter->coal.normal.data.tx_packets;
1098
1099 return 0;
1100}
1101
1102static int qlcnic_set_flags(struct net_device *netdev, u32 data)
1103{
1104 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1105 int hw_lro;
1106
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001107 if (data & ~ETH_FLAG_LRO)
Ben Hutchings97d19352010-06-30 02:46:56 +00001108 return -EINVAL;
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001109
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001110 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
1111 return -EINVAL;
1112
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001113 if (!adapter->rx_csum) {
1114 dev_info(&adapter->pdev->dev, "rx csum is off, "
1115 "cannot toggle lro\n");
1116 return -EINVAL;
1117 }
1118
Amit Kumar Salechaa2152d02010-10-07 23:46:07 +00001119 if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO))
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001120 return 0;
1121
Stanislaw Gruszkadeaec0f2010-06-27 23:31:34 +00001122 if (data & ETH_FLAG_LRO) {
1123 hw_lro = QLCNIC_LRO_ENABLED;
1124 netdev->features |= NETIF_F_LRO;
1125 } else {
1126 hw_lro = 0;
1127 netdev->features &= ~NETIF_F_LRO;
1128 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001129
1130 if (qlcnic_config_hw_lro(adapter, hw_lro))
1131 return -EIO;
1132
1133 if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
1134 return -EIO;
1135
1136
1137 return 0;
1138}
1139
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001140static u32 qlcnic_get_msglevel(struct net_device *netdev)
1141{
1142 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1143
1144 return adapter->msg_enable;
1145}
1146
1147static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1148{
1149 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1150
1151 adapter->msg_enable = msglvl;
1152}
1153
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001154const struct ethtool_ops qlcnic_ethtool_ops = {
1155 .get_settings = qlcnic_get_settings,
1156 .set_settings = qlcnic_set_settings,
1157 .get_drvinfo = qlcnic_get_drvinfo,
1158 .get_regs_len = qlcnic_get_regs_len,
1159 .get_regs = qlcnic_get_regs,
1160 .get_link = ethtool_op_get_link,
1161 .get_eeprom_len = qlcnic_get_eeprom_len,
1162 .get_eeprom = qlcnic_get_eeprom,
1163 .get_ringparam = qlcnic_get_ringparam,
1164 .set_ringparam = qlcnic_set_ringparam,
1165 .get_pauseparam = qlcnic_get_pauseparam,
1166 .set_pauseparam = qlcnic_set_pauseparam,
Sucheta Chakraborty8bae5692010-03-08 00:14:45 +00001167 .get_tx_csum = qlcnic_get_tx_csum,
Rajesh Borundia0325d692010-08-19 05:08:26 +00001168 .set_tx_csum = qlcnic_set_tx_csum,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001169 .set_sg = ethtool_op_set_sg,
1170 .get_tso = qlcnic_get_tso,
1171 .set_tso = qlcnic_set_tso,
1172 .get_wol = qlcnic_get_wol,
1173 .set_wol = qlcnic_set_wol,
1174 .self_test = qlcnic_diag_test,
1175 .get_strings = qlcnic_get_strings,
1176 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1177 .get_sset_count = qlcnic_get_sset_count,
1178 .get_rx_csum = qlcnic_get_rx_csum,
1179 .set_rx_csum = qlcnic_set_rx_csum,
1180 .get_coalesce = qlcnic_get_intr_coalesce,
1181 .set_coalesce = qlcnic_set_intr_coalesce,
1182 .get_flags = ethtool_op_get_flags,
1183 .set_flags = qlcnic_set_flags,
Sucheta Chakraborty897d3592010-02-01 05:24:58 +00001184 .phys_id = qlcnic_blink_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001185 .set_msglevel = qlcnic_set_msglevel,
1186 .get_msglevel = qlcnic_get_msglevel,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001187};