blob: 4c14510e2a87ef04a10b66021d9a5f4eebb0486a [file] [log] [blame]
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001/*
Sritej Velaga40839129f2010-12-02 20:41:56 +00002 * QLogic qlcnic NIC Driver
3 * Copyright (c) 2009-2010 QLogic Corporation
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004 *
Sritej Velaga40839129f2010-12-02 20:41:56 +00005 * See LICENSE.qlcnic for copyright and licensing details.
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00006 */
7
8#include <linux/types.h>
9#include <linux/delay.h>
10#include <linux/pci.h>
11#include <linux/io.h>
12#include <linux/netdevice.h>
13#include <linux/ethtool.h>
14
15#include "qlcnic.h"
16
17struct qlcnic_stats {
18 char stat_string[ETH_GSTRING_LEN];
19 int sizeof_stat;
20 int stat_offset;
21};
22
23#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
24#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
25
26static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
27 {"xmit_called",
28 QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
29 {"xmit_finished",
30 QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
31 {"rx_dropped",
32 QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
33 {"tx_dropped",
34 QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
35 {"csummed",
36 QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
37 {"rx_pkts",
38 QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
39 {"lro_pkts",
40 QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
41 {"rx_bytes",
42 QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
43 {"tx_bytes",
44 QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000045 {"lrobytes",
46 QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
47 {"lso_frames",
48 QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
49 {"xmit_on",
50 QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
51 {"xmit_off",
52 QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
53 {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
54 QLC_OFF(stats.skb_alloc_failure)},
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +000055 {"null rxbuf",
56 QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
57 {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
58 QLC_OFF(stats.rx_dma_map_error)},
59 {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
60 QLC_OFF(stats.tx_dma_map_error)},
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +000061
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000062};
63
amit salecha3666e0b2010-10-18 01:47:48 +000064static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
65 "rx unicast frames",
66 "rx multicast frames",
67 "rx broadcast frames",
68 "rx dropped frames",
69 "rx errors",
70 "rx local frames",
71 "rx numbytes",
72 "tx unicast frames",
73 "tx multicast frames",
74 "tx broadcast frames",
75 "tx dropped frames",
76 "tx errors",
77 "tx local frames",
78 "tx numbytes",
79};
80
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000081#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
amit salecha3666e0b2010-10-18 01:47:48 +000082#define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000083
84static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
85 "Register_Test_on_offline",
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +000086 "Link_Test_on_offline",
Sucheta Chakraborty97319a272010-12-02 20:41:23 +000087 "Interrupt_Test_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000088};
89
90#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
91
92#define QLCNIC_RING_REGS_COUNT 20
93#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
94#define QLCNIC_MAX_EEPROM_LEN 1024
95
96static const u32 diag_registers[] = {
97 CRB_CMDPEG_STATE,
98 CRB_RCVPEG_STATE,
Sritej Velagaff1b1bf82010-10-07 23:46:10 +000099 CRB_XG_STATE_P3P,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000100 CRB_FW_CAPABILITIES_1,
101 ISR_INT_STATE_REG,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000102 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000103 QLCNIC_CRB_DEV_STATE,
104 QLCNIC_CRB_DRV_STATE,
105 QLCNIC_CRB_DRV_SCRATCH,
106 QLCNIC_CRB_DEV_PARTITION_INFO,
107 QLCNIC_CRB_DRV_IDC_VER,
108 QLCNIC_PEG_ALIVE_COUNTER,
109 QLCNIC_PEG_HALT_STATUS1,
110 QLCNIC_PEG_HALT_STATUS2,
111 QLCNIC_CRB_PEG_NET_0+0x3c,
112 QLCNIC_CRB_PEG_NET_1+0x3c,
113 QLCNIC_CRB_PEG_NET_2+0x3c,
114 QLCNIC_CRB_PEG_NET_4+0x3c,
115 -1
116};
117
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000118#define QLCNIC_MGMT_API_VERSION 2
119#define QLCNIC_DEV_INFO_SIZE 1
120#define QLCNIC_ETHTOOL_REGS_VER 2
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000121static int qlcnic_get_regs_len(struct net_device *dev)
122{
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000123 return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
124 QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000125}
126
127static int qlcnic_get_eeprom_len(struct net_device *dev)
128{
129 return QLCNIC_FLASH_TOTAL_SIZE;
130}
131
132static void
133qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
134{
135 struct qlcnic_adapter *adapter = netdev_priv(dev);
136 u32 fw_major, fw_minor, fw_build;
137
138 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
139 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
140 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
141 sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
142
143 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
144 strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
145 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
146}
147
148static int
149qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
150{
151 struct qlcnic_adapter *adapter = netdev_priv(dev);
152 int check_sfp_module = 0;
153 u16 pcifn = adapter->ahw.pci_func;
154
155 /* read which mode */
156 if (adapter->ahw.port_type == QLCNIC_GBE) {
157 ecmd->supported = (SUPPORTED_10baseT_Half |
158 SUPPORTED_10baseT_Full |
159 SUPPORTED_100baseT_Half |
160 SUPPORTED_100baseT_Full |
161 SUPPORTED_1000baseT_Half |
162 SUPPORTED_1000baseT_Full);
163
164 ecmd->advertising = (ADVERTISED_100baseT_Half |
165 ADVERTISED_100baseT_Full |
166 ADVERTISED_1000baseT_Half |
167 ADVERTISED_1000baseT_Full);
168
169 ecmd->speed = adapter->link_speed;
170 ecmd->duplex = adapter->link_duplex;
171 ecmd->autoneg = adapter->link_autoneg;
172
173 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
174 u32 val;
175
176 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
177 if (val == QLCNIC_PORT_MODE_802_3_AP) {
178 ecmd->supported = SUPPORTED_1000baseT_Full;
179 ecmd->advertising = ADVERTISED_1000baseT_Full;
180 } else {
181 ecmd->supported = SUPPORTED_10000baseT_Full;
182 ecmd->advertising = ADVERTISED_10000baseT_Full;
183 }
184
185 if (netif_running(dev) && adapter->has_link_events) {
186 ecmd->speed = adapter->link_speed;
187 ecmd->autoneg = adapter->link_autoneg;
188 ecmd->duplex = adapter->link_duplex;
189 goto skip;
190 }
191
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000192 val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
193 ecmd->speed = P3P_LINK_SPEED_MHZ *
194 P3P_LINK_SPEED_VAL(pcifn, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000195 ecmd->duplex = DUPLEX_FULL;
196 ecmd->autoneg = AUTONEG_DISABLE;
197 } else
198 return -EIO;
199
200skip:
201 ecmd->phy_address = adapter->physical_port;
202 ecmd->transceiver = XCVR_EXTERNAL;
203
204 switch (adapter->ahw.board_type) {
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000205 case QLCNIC_BRDTYPE_P3P_REF_QG:
206 case QLCNIC_BRDTYPE_P3P_4_GB:
207 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000208
209 ecmd->supported |= SUPPORTED_Autoneg;
210 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000211 case QLCNIC_BRDTYPE_P3P_10G_CX4:
212 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
213 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000214 ecmd->supported |= SUPPORTED_TP;
215 ecmd->advertising |= ADVERTISED_TP;
216 ecmd->port = PORT_TP;
217 ecmd->autoneg = adapter->link_autoneg;
218 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000219 case QLCNIC_BRDTYPE_P3P_IMEZ:
220 case QLCNIC_BRDTYPE_P3P_XG_LOM:
221 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000222 ecmd->supported |= SUPPORTED_MII;
223 ecmd->advertising |= ADVERTISED_MII;
224 ecmd->port = PORT_MII;
225 ecmd->autoneg = AUTONEG_DISABLE;
226 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000227 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
228 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
229 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000230 ecmd->advertising |= ADVERTISED_TP;
231 ecmd->supported |= SUPPORTED_TP;
232 check_sfp_module = netif_running(dev) &&
233 adapter->has_link_events;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000234 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000235 ecmd->supported |= SUPPORTED_FIBRE;
236 ecmd->advertising |= ADVERTISED_FIBRE;
237 ecmd->port = PORT_FIBRE;
238 ecmd->autoneg = AUTONEG_DISABLE;
239 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000240 case QLCNIC_BRDTYPE_P3P_10G_TP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000241 if (adapter->ahw.port_type == QLCNIC_XGBE) {
242 ecmd->autoneg = AUTONEG_DISABLE;
243 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
244 ecmd->advertising |=
245 (ADVERTISED_FIBRE | ADVERTISED_TP);
246 ecmd->port = PORT_FIBRE;
247 check_sfp_module = netif_running(dev) &&
248 adapter->has_link_events;
249 } else {
250 ecmd->autoneg = AUTONEG_ENABLE;
251 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
252 ecmd->advertising |=
253 (ADVERTISED_TP | ADVERTISED_Autoneg);
254 ecmd->port = PORT_TP;
255 }
256 break;
257 default:
258 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
259 adapter->ahw.board_type);
260 return -EIO;
261 }
262
263 if (check_sfp_module) {
264 switch (adapter->module_type) {
265 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
266 case LINKEVENT_MODULE_OPTICAL_SRLR:
267 case LINKEVENT_MODULE_OPTICAL_LRM:
268 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
269 ecmd->port = PORT_FIBRE;
270 break;
271 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
272 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
273 case LINKEVENT_MODULE_TWINAX:
274 ecmd->port = PORT_TP;
275 break;
276 default:
277 ecmd->port = PORT_OTHER;
278 }
279 }
280
281 return 0;
282}
283
284static int
285qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
286{
287 struct qlcnic_adapter *adapter = netdev_priv(dev);
288 __u32 status;
289
290 /* read which mode */
291 if (adapter->ahw.port_type == QLCNIC_GBE) {
292 /* autonegotiation */
293 if (qlcnic_fw_cmd_set_phy(adapter,
294 QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG,
295 ecmd->autoneg) != 0)
296 return -EIO;
297 else
298 adapter->link_autoneg = ecmd->autoneg;
299
300 if (qlcnic_fw_cmd_query_phy(adapter,
301 QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
302 &status) != 0)
303 return -EIO;
304
305 switch (ecmd->speed) {
306 case SPEED_10:
307 qlcnic_set_phy_speed(status, 0);
308 break;
309 case SPEED_100:
310 qlcnic_set_phy_speed(status, 1);
311 break;
312 case SPEED_1000:
313 qlcnic_set_phy_speed(status, 2);
314 break;
315 }
316
317 if (ecmd->duplex == DUPLEX_HALF)
318 qlcnic_clear_phy_duplex(status);
319 if (ecmd->duplex == DUPLEX_FULL)
320 qlcnic_set_phy_duplex(status);
321 if (qlcnic_fw_cmd_set_phy(adapter,
322 QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
323 *((int *)&status)) != 0)
324 return -EIO;
325 else {
326 adapter->link_speed = ecmd->speed;
327 adapter->link_duplex = ecmd->duplex;
328 }
329 } else
330 return -EOPNOTSUPP;
331
332 if (!netif_running(dev))
333 return 0;
334
335 dev->netdev_ops->ndo_stop(dev);
336 return dev->netdev_ops->ndo_open(dev);
337}
338
339static void
340qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
341{
342 struct qlcnic_adapter *adapter = netdev_priv(dev);
343 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
344 struct qlcnic_host_sds_ring *sds_ring;
345 u32 *regs_buff = p;
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000346 int ring, i = 0, j = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000347
348 memset(p, 0, qlcnic_get_regs_len(dev));
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000349 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
350 (adapter->ahw.revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000351
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000352 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
353 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
354
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000355 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
356 regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000357
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000358 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000359 return;
360
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000361 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
362
363 regs_buff[i++] = 1; /* No. of tx ring */
364 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
365 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
366
367 regs_buff[i++] = 2; /* No. of rx ring */
368 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
369 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
370
371 regs_buff[i++] = adapter->max_sds_rings;
372
373 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
374 sds_ring = &(recv_ctx->sds_rings[ring]);
375 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
376 }
377}
378
379static u32 qlcnic_test_link(struct net_device *dev)
380{
381 struct qlcnic_adapter *adapter = netdev_priv(dev);
382 u32 val;
383
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000384 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
385 val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val);
386 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000387}
388
389static int
390qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
391 u8 *bytes)
392{
393 struct qlcnic_adapter *adapter = netdev_priv(dev);
394 int offset;
395 int ret;
396
397 if (eeprom->len == 0)
398 return -EINVAL;
399
400 eeprom->magic = (adapter->pdev)->vendor |
401 ((adapter->pdev)->device << 16);
402 offset = eeprom->offset;
403
404 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
405 eeprom->len);
406 if (ret < 0)
407 return ret;
408
409 return 0;
410}
411
412static void
413qlcnic_get_ringparam(struct net_device *dev,
414 struct ethtool_ringparam *ring)
415{
416 struct qlcnic_adapter *adapter = netdev_priv(dev);
417
418 ring->rx_pending = adapter->num_rxd;
419 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000420 ring->tx_pending = adapter->num_txd;
421
Sony Chacko90d19002010-10-26 17:53:08 +0000422 ring->rx_max_pending = adapter->max_rxd;
423 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000424 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
425
426 ring->rx_mini_max_pending = 0;
427 ring->rx_mini_pending = 0;
428}
429
430static u32
431qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
432{
433 u32 num_desc;
434 num_desc = max(val, min);
435 num_desc = min(num_desc, max);
436 num_desc = roundup_pow_of_two(num_desc);
437
438 if (val != num_desc) {
439 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
440 qlcnic_driver_name, r_name, num_desc, val);
441 }
442
443 return num_desc;
444}
445
446static int
447qlcnic_set_ringparam(struct net_device *dev,
448 struct ethtool_ringparam *ring)
449{
450 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000451 u16 num_rxd, num_jumbo_rxd, num_txd;
452
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000453 if (ring->rx_mini_pending)
454 return -EOPNOTSUPP;
455
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000456 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000457 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000458
459 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000460 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
461 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000462
463 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
464 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
465
466 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
467 num_jumbo_rxd == adapter->num_jumbo_rxd)
468 return 0;
469
470 adapter->num_rxd = num_rxd;
471 adapter->num_jumbo_rxd = num_jumbo_rxd;
472 adapter->num_txd = num_txd;
473
474 return qlcnic_reset_context(adapter);
475}
476
477static void
478qlcnic_get_pauseparam(struct net_device *netdev,
479 struct ethtool_pauseparam *pause)
480{
481 struct qlcnic_adapter *adapter = netdev_priv(netdev);
482 int port = adapter->physical_port;
483 __u32 val;
484
485 if (adapter->ahw.port_type == QLCNIC_GBE) {
486 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
487 return;
488 /* get flow control settings */
489 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
490 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
491 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
492 switch (port) {
493 case 0:
494 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
495 break;
496 case 1:
497 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
498 break;
499 case 2:
500 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
501 break;
502 case 3:
503 default:
504 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
505 break;
506 }
507 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
508 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
509 return;
510 pause->rx_pause = 1;
511 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
512 if (port == 0)
513 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
514 else
515 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
516 } else {
517 dev_err(&netdev->dev, "Unknown board type: %x\n",
518 adapter->ahw.port_type);
519 }
520}
521
522static int
523qlcnic_set_pauseparam(struct net_device *netdev,
524 struct ethtool_pauseparam *pause)
525{
526 struct qlcnic_adapter *adapter = netdev_priv(netdev);
527 int port = adapter->physical_port;
528 __u32 val;
529
530 /* read mode */
531 if (adapter->ahw.port_type == QLCNIC_GBE) {
532 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
533 return -EIO;
534 /* set flow control */
535 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
536
537 if (pause->rx_pause)
538 qlcnic_gb_rx_flowctl(val);
539 else
540 qlcnic_gb_unset_rx_flowctl(val);
541
542 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
543 val);
544 /* set autoneg */
545 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
546 switch (port) {
547 case 0:
548 if (pause->tx_pause)
549 qlcnic_gb_unset_gb0_mask(val);
550 else
551 qlcnic_gb_set_gb0_mask(val);
552 break;
553 case 1:
554 if (pause->tx_pause)
555 qlcnic_gb_unset_gb1_mask(val);
556 else
557 qlcnic_gb_set_gb1_mask(val);
558 break;
559 case 2:
560 if (pause->tx_pause)
561 qlcnic_gb_unset_gb2_mask(val);
562 else
563 qlcnic_gb_set_gb2_mask(val);
564 break;
565 case 3:
566 default:
567 if (pause->tx_pause)
568 qlcnic_gb_unset_gb3_mask(val);
569 else
570 qlcnic_gb_set_gb3_mask(val);
571 break;
572 }
573 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
574 } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000575 if (!pause->rx_pause || pause->autoneg)
576 return -EOPNOTSUPP;
577
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000578 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
579 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000580
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000581 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
582 if (port == 0) {
583 if (pause->tx_pause)
584 qlcnic_xg_unset_xg0_mask(val);
585 else
586 qlcnic_xg_set_xg0_mask(val);
587 } else {
588 if (pause->tx_pause)
589 qlcnic_xg_unset_xg1_mask(val);
590 else
591 qlcnic_xg_set_xg1_mask(val);
592 }
593 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
594 } else {
595 dev_err(&netdev->dev, "Unknown board type: %x\n",
596 adapter->ahw.port_type);
597 }
598 return 0;
599}
600
601static int qlcnic_reg_test(struct net_device *dev)
602{
603 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000604 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000605
606 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
607 if ((data_read & 0xffff) != adapter->pdev->vendor)
608 return 1;
609
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000610 return 0;
611}
612
613static int qlcnic_get_sset_count(struct net_device *dev, int sset)
614{
amit salecha3666e0b2010-10-18 01:47:48 +0000615 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000616 switch (sset) {
617 case ETH_SS_TEST:
618 return QLCNIC_TEST_LEN;
619 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000620 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
621 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000622 return QLCNIC_STATS_LEN;
623 default:
624 return -EOPNOTSUPP;
625 }
626}
627
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000628static int qlcnic_irq_test(struct net_device *netdev)
629{
630 struct qlcnic_adapter *adapter = netdev_priv(netdev);
631 int max_sds_rings = adapter->max_sds_rings;
632 int ret;
633
634 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
635 return -EIO;
636
637 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
638 if (ret)
639 goto clear_it;
640
641 adapter->diag_cnt = 0;
642 ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000643 adapter->fw_hal_version, adapter->portnum,
644 0, 0, 0x00000011);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000645 if (ret)
646 goto done;
647
648 msleep(10);
649
650 ret = !adapter->diag_cnt;
651
652done:
653 qlcnic_diag_free_res(netdev, max_sds_rings);
654
655clear_it:
656 adapter->max_sds_rings = max_sds_rings;
657 clear_bit(__QLCNIC_RESETTING, &adapter->state);
658 return ret;
659}
660
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000661static void
662qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
663 u64 *data)
664{
665 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000666
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000667 data[0] = qlcnic_reg_test(dev);
668 if (data[0])
669 eth_test->flags |= ETH_TEST_FL_FAILED;
670
671 data[1] = (u64) qlcnic_test_link(dev);
672 if (data[1])
673 eth_test->flags |= ETH_TEST_FL_FAILED;
674
Sony Chacko13b93ed2011-01-10 00:15:22 +0000675 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000676 data[2] = qlcnic_irq_test(dev);
677 if (data[2])
678 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000679
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000680
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000681 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000682}
683
684static void
685qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
686{
amit salecha3666e0b2010-10-18 01:47:48 +0000687 struct qlcnic_adapter *adapter = netdev_priv(dev);
688 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000689
690 switch (stringset) {
691 case ETH_SS_TEST:
692 memcpy(data, *qlcnic_gstrings_test,
693 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
694 break;
695 case ETH_SS_STATS:
696 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
697 memcpy(data + index * ETH_GSTRING_LEN,
698 qlcnic_gstrings_stats[index].stat_string,
699 ETH_GSTRING_LEN);
700 }
amit salecha3666e0b2010-10-18 01:47:48 +0000701 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
702 return;
703 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
704 memcpy(data + index * ETH_GSTRING_LEN,
705 qlcnic_device_gstrings_stats[i],
706 ETH_GSTRING_LEN);
707 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000708 }
709}
710
amit salecha3666e0b2010-10-18 01:47:48 +0000711#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
712 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
713
714static void
715qlcnic_fill_device_stats(int *index, u64 *data,
716 struct __qlcnic_esw_statistics *stats)
717{
718 int ind = *index;
719
720 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
721 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
722 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
723 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
724 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
725 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
726 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
727
728 *index = ind;
729}
730
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000731static void
732qlcnic_get_ethtool_stats(struct net_device *dev,
733 struct ethtool_stats *stats, u64 * data)
734{
735 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000736 struct qlcnic_esw_statistics port_stats;
737 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000738
739 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
740 char *p =
741 (char *)adapter +
742 qlcnic_gstrings_stats[index].stat_offset;
743 data[index] =
744 (qlcnic_gstrings_stats[index].sizeof_stat ==
745 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
746 }
amit salecha3666e0b2010-10-18 01:47:48 +0000747
748 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
749 return;
750
751 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
752 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
753 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
754 if (ret)
755 return;
756
757 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
758
759 ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
760 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
761 if (ret)
762 return;
763
764 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000765}
766
Rajesh Borundia0325d692010-08-19 05:08:26 +0000767static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
768{
769 struct qlcnic_adapter *adapter = netdev_priv(dev);
770
771 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
772 return -EOPNOTSUPP;
773 if (data)
774 dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
775 else
776 dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
777
778 return 0;
779
780}
Sucheta Chakraborty8bae5692010-03-08 00:14:45 +0000781static u32 qlcnic_get_tx_csum(struct net_device *dev)
782{
783 return dev->features & NETIF_F_IP_CSUM;
784}
785
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000786static u32 qlcnic_get_rx_csum(struct net_device *dev)
787{
788 struct qlcnic_adapter *adapter = netdev_priv(dev);
789 return adapter->rx_csum;
790}
791
792static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
793{
794 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000795
Rajesh Borundia0325d692010-08-19 05:08:26 +0000796 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
797 return -EOPNOTSUPP;
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000798 if (!!data) {
799 adapter->rx_csum = !!data;
800 return 0;
801 }
802
Amit Kumar Salechaa2152d02010-10-07 23:46:07 +0000803 if (dev->features & NETIF_F_LRO) {
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000804 if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED))
805 return -EIO;
806
807 dev->features &= ~NETIF_F_LRO;
808 qlcnic_send_lro_cleanup(adapter);
Sony Chacko706f23a2010-11-16 14:08:46 +0000809 dev_info(&adapter->pdev->dev,
810 "disabling LRO as rx_csum is off\n");
Sucheta Chakraborty24763d82010-08-17 00:34:25 +0000811 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000812 adapter->rx_csum = !!data;
813 return 0;
814}
815
816static u32 qlcnic_get_tso(struct net_device *dev)
817{
818 return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
819}
820
821static int qlcnic_set_tso(struct net_device *dev, u32 data)
822{
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +0000823 struct qlcnic_adapter *adapter = netdev_priv(dev);
824 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO))
825 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000826 if (data)
827 dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
828 else
829 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
830
831 return 0;
832}
833
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000834static int qlcnic_blink_led(struct net_device *dev, u32 val)
835{
836 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000837 int max_sds_rings = adapter->max_sds_rings;
838 int dev_down = 0;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000839 int ret;
840
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000841 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
842 dev_down = 1;
843 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
844 return -EIO;
845
846 ret = qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST);
847 if (ret) {
848 clear_bit(__QLCNIC_RESETTING, &adapter->state);
849 return ret;
850 }
851 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000852
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000853 ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000854 if (ret) {
855 dev_err(&adapter->pdev->dev,
856 "Failed to set LED blink state.\n");
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000857 goto done;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000858 }
859
860 msleep_interruptible(val * 1000);
861
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000862 ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000863 if (ret) {
864 dev_err(&adapter->pdev->dev,
865 "Failed to reset LED blink state.\n");
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000866 goto done;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000867 }
868
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000869done:
870 if (dev_down) {
871 qlcnic_diag_free_res(dev, max_sds_rings);
872 clear_bit(__QLCNIC_RESETTING, &adapter->state);
873 }
874 return ret;
875
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000876}
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};