blob: 27726ebfba2aeb26a05fd2db7435265707fccef4 [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;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000153 u16 pcifn = adapter->ahw->pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000154
155 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000156 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000157 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
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000173 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000174 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
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000204 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:
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000241 if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000242 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",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000259 adapter->ahw->board_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000260 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{
Sony Chacko7e610ca2011-04-28 11:48:19 +0000287 u32 config = 0;
288 u32 ret = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000289 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e610ca2011-04-28 11:48:19 +0000290
291 if (adapter->ahw->port_type != QLCNIC_GBE)
292 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000293
294 /* read which mode */
Sony Chacko7e610ca2011-04-28 11:48:19 +0000295 if (ecmd->duplex)
296 config |= 0x1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000297
Sony Chacko7e610ca2011-04-28 11:48:19 +0000298 if (ecmd->autoneg)
299 config |= 0x2;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000300
Sony Chacko7e610ca2011-04-28 11:48:19 +0000301 switch (ethtool_cmd_speed(ecmd)) {
302 case SPEED_10:
303 config |= (0 << 8);
304 break;
305 case SPEED_100:
306 config |= (1 << 8);
307 break;
308 case SPEED_1000:
309 config |= (10 << 8);
310 break;
311 default:
312 return -EIO;
313 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000314
Sony Chacko7e610ca2011-04-28 11:48:19 +0000315 ret = qlcnic_fw_cmd_set_port(adapter, config);
316
317 if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000318 return -EOPNOTSUPP;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000319 else if (ret)
320 return -EIO;
321
322 adapter->link_speed = ethtool_cmd_speed(ecmd);
323 adapter->link_duplex = ecmd->duplex;
324 adapter->link_autoneg = ecmd->autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000325
326 if (!netif_running(dev))
327 return 0;
328
329 dev->netdev_ops->ndo_stop(dev);
330 return dev->netdev_ops->ndo_open(dev);
331}
332
333static void
334qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
335{
336 struct qlcnic_adapter *adapter = netdev_priv(dev);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000337 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000338 struct qlcnic_host_sds_ring *sds_ring;
339 u32 *regs_buff = p;
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000340 int ring, i = 0, j = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000341
342 memset(p, 0, qlcnic_get_regs_len(dev));
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000343 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000344 (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000345
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000346 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
347 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
348
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000349 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
350 regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000351
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000352 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000353 return;
354
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000355 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
356
357 regs_buff[i++] = 1; /* No. of tx ring */
358 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
359 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
360
361 regs_buff[i++] = 2; /* No. of rx ring */
362 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
363 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
364
365 regs_buff[i++] = adapter->max_sds_rings;
366
367 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
368 sds_ring = &(recv_ctx->sds_rings[ring]);
369 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
370 }
371}
372
373static u32 qlcnic_test_link(struct net_device *dev)
374{
375 struct qlcnic_adapter *adapter = netdev_priv(dev);
376 u32 val;
377
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000378 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000379 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000380 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000381}
382
383static int
384qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
385 u8 *bytes)
386{
387 struct qlcnic_adapter *adapter = netdev_priv(dev);
388 int offset;
389 int ret;
390
391 if (eeprom->len == 0)
392 return -EINVAL;
393
394 eeprom->magic = (adapter->pdev)->vendor |
395 ((adapter->pdev)->device << 16);
396 offset = eeprom->offset;
397
398 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
399 eeprom->len);
400 if (ret < 0)
401 return ret;
402
403 return 0;
404}
405
406static void
407qlcnic_get_ringparam(struct net_device *dev,
408 struct ethtool_ringparam *ring)
409{
410 struct qlcnic_adapter *adapter = netdev_priv(dev);
411
412 ring->rx_pending = adapter->num_rxd;
413 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000414 ring->tx_pending = adapter->num_txd;
415
Sony Chacko90d19002010-10-26 17:53:08 +0000416 ring->rx_max_pending = adapter->max_rxd;
417 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000418 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
419
420 ring->rx_mini_max_pending = 0;
421 ring->rx_mini_pending = 0;
422}
423
424static u32
425qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
426{
427 u32 num_desc;
428 num_desc = max(val, min);
429 num_desc = min(num_desc, max);
430 num_desc = roundup_pow_of_two(num_desc);
431
432 if (val != num_desc) {
433 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
434 qlcnic_driver_name, r_name, num_desc, val);
435 }
436
437 return num_desc;
438}
439
440static int
441qlcnic_set_ringparam(struct net_device *dev,
442 struct ethtool_ringparam *ring)
443{
444 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000445 u16 num_rxd, num_jumbo_rxd, num_txd;
446
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000447 if (ring->rx_mini_pending)
448 return -EOPNOTSUPP;
449
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000450 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000451 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000452
453 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000454 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
455 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000456
457 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
458 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
459
460 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
461 num_jumbo_rxd == adapter->num_jumbo_rxd)
462 return 0;
463
464 adapter->num_rxd = num_rxd;
465 adapter->num_jumbo_rxd = num_jumbo_rxd;
466 adapter->num_txd = num_txd;
467
468 return qlcnic_reset_context(adapter);
469}
470
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000471static void qlcnic_get_channels(struct net_device *dev,
472 struct ethtool_channels *channel)
473{
474 struct qlcnic_adapter *adapter = netdev_priv(dev);
475
476 channel->max_rx = rounddown_pow_of_two(min_t(int,
477 adapter->max_rx_ques, num_online_cpus()));
478 channel->max_tx = adapter->max_tx_ques;
479
480 channel->rx_count = adapter->max_sds_rings;
481 channel->tx_count = adapter->max_tx_ques;
482}
483
484static int qlcnic_set_channels(struct net_device *dev,
485 struct ethtool_channels *channel)
486{
487 struct qlcnic_adapter *adapter = netdev_priv(dev);
488 int err;
489
490 if (channel->other_count || channel->combined_count ||
491 channel->tx_count != channel->max_tx)
492 return -EINVAL;
493
494 err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
495 if (err)
496 return err;
497
498 err = qlcnic_set_max_rss(adapter, channel->rx_count);
499 netdev_info(dev, "allocated 0x%x sds rings\n",
500 adapter->max_sds_rings);
501 return err;
502}
503
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000504static void
505qlcnic_get_pauseparam(struct net_device *netdev,
506 struct ethtool_pauseparam *pause)
507{
508 struct qlcnic_adapter *adapter = netdev_priv(netdev);
509 int port = adapter->physical_port;
510 __u32 val;
511
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000512 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000513 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
514 return;
515 /* get flow control settings */
516 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
517 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
518 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
519 switch (port) {
520 case 0:
521 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
522 break;
523 case 1:
524 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
525 break;
526 case 2:
527 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
528 break;
529 case 3:
530 default:
531 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
532 break;
533 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000534 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000535 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
536 return;
537 pause->rx_pause = 1;
538 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
539 if (port == 0)
540 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
541 else
542 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
543 } else {
544 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000545 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000546 }
547}
548
549static int
550qlcnic_set_pauseparam(struct net_device *netdev,
551 struct ethtool_pauseparam *pause)
552{
553 struct qlcnic_adapter *adapter = netdev_priv(netdev);
554 int port = adapter->physical_port;
555 __u32 val;
556
557 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000558 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000559 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
560 return -EIO;
561 /* set flow control */
562 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
563
564 if (pause->rx_pause)
565 qlcnic_gb_rx_flowctl(val);
566 else
567 qlcnic_gb_unset_rx_flowctl(val);
568
569 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
570 val);
571 /* set autoneg */
572 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
573 switch (port) {
574 case 0:
575 if (pause->tx_pause)
576 qlcnic_gb_unset_gb0_mask(val);
577 else
578 qlcnic_gb_set_gb0_mask(val);
579 break;
580 case 1:
581 if (pause->tx_pause)
582 qlcnic_gb_unset_gb1_mask(val);
583 else
584 qlcnic_gb_set_gb1_mask(val);
585 break;
586 case 2:
587 if (pause->tx_pause)
588 qlcnic_gb_unset_gb2_mask(val);
589 else
590 qlcnic_gb_set_gb2_mask(val);
591 break;
592 case 3:
593 default:
594 if (pause->tx_pause)
595 qlcnic_gb_unset_gb3_mask(val);
596 else
597 qlcnic_gb_set_gb3_mask(val);
598 break;
599 }
600 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000601 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000602 if (!pause->rx_pause || pause->autoneg)
603 return -EOPNOTSUPP;
604
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000605 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
606 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000607
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000608 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
609 if (port == 0) {
610 if (pause->tx_pause)
611 qlcnic_xg_unset_xg0_mask(val);
612 else
613 qlcnic_xg_set_xg0_mask(val);
614 } else {
615 if (pause->tx_pause)
616 qlcnic_xg_unset_xg1_mask(val);
617 else
618 qlcnic_xg_set_xg1_mask(val);
619 }
620 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
621 } else {
622 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000623 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000624 }
625 return 0;
626}
627
628static int qlcnic_reg_test(struct net_device *dev)
629{
630 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000631 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000632
633 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
634 if ((data_read & 0xffff) != adapter->pdev->vendor)
635 return 1;
636
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000637 return 0;
638}
639
640static int qlcnic_get_sset_count(struct net_device *dev, int sset)
641{
amit salecha3666e0b2010-10-18 01:47:48 +0000642 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000643 switch (sset) {
644 case ETH_SS_TEST:
645 return QLCNIC_TEST_LEN;
646 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000647 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
648 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000649 return QLCNIC_STATS_LEN;
650 default:
651 return -EOPNOTSUPP;
652 }
653}
654
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000655static int qlcnic_irq_test(struct net_device *netdev)
656{
657 struct qlcnic_adapter *adapter = netdev_priv(netdev);
658 int max_sds_rings = adapter->max_sds_rings;
659 int ret;
660
661 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
662 return -EIO;
663
664 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
665 if (ret)
666 goto clear_it;
667
668 adapter->diag_cnt = 0;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000669 ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func,
670 adapter->fw_hal_version, adapter->ahw->pci_func,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000671 0, 0, 0x00000011);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000672 if (ret)
673 goto done;
674
675 msleep(10);
676
677 ret = !adapter->diag_cnt;
678
679done:
680 qlcnic_diag_free_res(netdev, max_sds_rings);
681
682clear_it:
683 adapter->max_sds_rings = max_sds_rings;
684 clear_bit(__QLCNIC_RESETTING, &adapter->state);
685 return ret;
686}
687
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000688static void
689qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
690 u64 *data)
691{
692 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000693
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000694 data[0] = qlcnic_reg_test(dev);
695 if (data[0])
696 eth_test->flags |= ETH_TEST_FL_FAILED;
697
698 data[1] = (u64) qlcnic_test_link(dev);
699 if (data[1])
700 eth_test->flags |= ETH_TEST_FL_FAILED;
701
Sony Chacko13b93ed2011-01-10 00:15:22 +0000702 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000703 data[2] = qlcnic_irq_test(dev);
704 if (data[2])
705 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000706
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000707
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000708 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000709}
710
711static void
712qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
713{
amit salecha3666e0b2010-10-18 01:47:48 +0000714 struct qlcnic_adapter *adapter = netdev_priv(dev);
715 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000716
717 switch (stringset) {
718 case ETH_SS_TEST:
719 memcpy(data, *qlcnic_gstrings_test,
720 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
721 break;
722 case ETH_SS_STATS:
723 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
724 memcpy(data + index * ETH_GSTRING_LEN,
725 qlcnic_gstrings_stats[index].stat_string,
726 ETH_GSTRING_LEN);
727 }
amit salecha3666e0b2010-10-18 01:47:48 +0000728 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
729 return;
730 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
731 memcpy(data + index * ETH_GSTRING_LEN,
732 qlcnic_device_gstrings_stats[i],
733 ETH_GSTRING_LEN);
734 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000735 }
736}
737
amit salecha3666e0b2010-10-18 01:47:48 +0000738#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
739 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
740
741static void
742qlcnic_fill_device_stats(int *index, u64 *data,
743 struct __qlcnic_esw_statistics *stats)
744{
745 int ind = *index;
746
747 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
748 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
749 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
750 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
751 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
752 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
753 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
754
755 *index = ind;
756}
757
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000758static void
759qlcnic_get_ethtool_stats(struct net_device *dev,
760 struct ethtool_stats *stats, u64 * data)
761{
762 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000763 struct qlcnic_esw_statistics port_stats;
764 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000765
766 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
767 char *p =
768 (char *)adapter +
769 qlcnic_gstrings_stats[index].stat_offset;
770 data[index] =
771 (qlcnic_gstrings_stats[index].sizeof_stat ==
772 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
773 }
amit salecha3666e0b2010-10-18 01:47:48 +0000774
775 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
776 return;
777
778 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000779 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000780 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
781 if (ret)
782 return;
783
784 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
785
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000786 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000787 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
788 if (ret)
789 return;
790
791 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000792}
793
stephen hemminger94469f72011-04-06 11:47:23 +0000794static int qlcnic_set_led(struct net_device *dev,
795 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000796{
797 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000798 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000799
stephen hemminger94469f72011-04-06 11:47:23 +0000800 switch (state) {
801 case ETHTOOL_ID_ACTIVE:
stephen hemminger94469f72011-04-06 11:47:23 +0000802 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
803 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
804 return -EIO;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000805
stephen hemminger94469f72011-04-06 11:47:23 +0000806 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) {
807 clear_bit(__QLCNIC_RESETTING, &adapter->state);
808 return -EIO;
809 }
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000810 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000811 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000812
stephen hemminger94469f72011-04-06 11:47:23 +0000813 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0)
814 return 0;
815
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000816 dev_err(&adapter->pdev->dev,
817 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +0000818 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000819
stephen hemminger94469f72011-04-06 11:47:23 +0000820 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000821 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
822 dev_err(&adapter->pdev->dev,
823 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000824
stephen hemminger94469f72011-04-06 11:47:23 +0000825 break;
826
827 default:
828 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000829 }
830
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000831 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) {
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000832 qlcnic_diag_free_res(dev, max_sds_rings);
833 clear_bit(__QLCNIC_RESETTING, &adapter->state);
834 }
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000835
stephen hemminger94469f72011-04-06 11:47:23 +0000836 return -EIO;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000837}
838
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000839static void
840qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
841{
842 struct qlcnic_adapter *adapter = netdev_priv(dev);
843 u32 wol_cfg;
844
845 wol->supported = 0;
846 wol->wolopts = 0;
847
848 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
849 if (wol_cfg & (1UL << adapter->portnum))
850 wol->supported |= WAKE_MAGIC;
851
852 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
853 if (wol_cfg & (1UL << adapter->portnum))
854 wol->wolopts |= WAKE_MAGIC;
855}
856
857static int
858qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
859{
860 struct qlcnic_adapter *adapter = netdev_priv(dev);
861 u32 wol_cfg;
862
863 if (wol->wolopts & ~WAKE_MAGIC)
864 return -EOPNOTSUPP;
865
866 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
867 if (!(wol_cfg & (1 << adapter->portnum)))
868 return -EOPNOTSUPP;
869
870 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
871 if (wol->wolopts & WAKE_MAGIC)
872 wol_cfg |= 1UL << adapter->portnum;
873 else
874 wol_cfg &= ~(1UL << adapter->portnum);
875
876 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
877
878 return 0;
879}
880
881/*
882 * Set the coalescing parameters. Currently only normal is supported.
883 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
884 * firmware coalescing to default.
885 */
886static int qlcnic_set_intr_coalesce(struct net_device *netdev,
887 struct ethtool_coalesce *ethcoal)
888{
889 struct qlcnic_adapter *adapter = netdev_priv(netdev);
890
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000891 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000892 return -EINVAL;
893
894 /*
895 * Return Error if unsupported values or
896 * unsupported parameters are set.
897 */
898 if (ethcoal->rx_coalesce_usecs > 0xffff ||
899 ethcoal->rx_max_coalesced_frames > 0xffff ||
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000900 ethcoal->tx_coalesce_usecs ||
901 ethcoal->tx_max_coalesced_frames ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000902 ethcoal->rx_coalesce_usecs_irq ||
903 ethcoal->rx_max_coalesced_frames_irq ||
904 ethcoal->tx_coalesce_usecs_irq ||
905 ethcoal->tx_max_coalesced_frames_irq ||
906 ethcoal->stats_block_coalesce_usecs ||
907 ethcoal->use_adaptive_rx_coalesce ||
908 ethcoal->use_adaptive_tx_coalesce ||
909 ethcoal->pkt_rate_low ||
910 ethcoal->rx_coalesce_usecs_low ||
911 ethcoal->rx_max_coalesced_frames_low ||
912 ethcoal->tx_coalesce_usecs_low ||
913 ethcoal->tx_max_coalesced_frames_low ||
914 ethcoal->pkt_rate_high ||
915 ethcoal->rx_coalesce_usecs_high ||
916 ethcoal->rx_max_coalesced_frames_high ||
917 ethcoal->tx_coalesce_usecs_high ||
918 ethcoal->tx_max_coalesced_frames_high)
919 return -EINVAL;
920
921 if (!ethcoal->rx_coalesce_usecs ||
922 !ethcoal->rx_max_coalesced_frames) {
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000923 adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
924 adapter->ahw->coal.rx_time_us =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000925 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000926 adapter->ahw->coal.rx_packets =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000927 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
928 } else {
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000929 adapter->ahw->coal.flag = 0;
930 adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
931 adapter->ahw->coal.rx_packets =
932 ethcoal->rx_max_coalesced_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000933 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000934
935 qlcnic_config_intr_coalesce(adapter);
936
937 return 0;
938}
939
940static int qlcnic_get_intr_coalesce(struct net_device *netdev,
941 struct ethtool_coalesce *ethcoal)
942{
943 struct qlcnic_adapter *adapter = netdev_priv(netdev);
944
945 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
946 return -EINVAL;
947
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000948 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
949 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000950
951 return 0;
952}
953
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +0000954static u32 qlcnic_get_msglevel(struct net_device *netdev)
955{
956 struct qlcnic_adapter *adapter = netdev_priv(netdev);
957
958 return adapter->msg_enable;
959}
960
961static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
962{
963 struct qlcnic_adapter *adapter = netdev_priv(netdev);
964
965 adapter->msg_enable = msglvl;
966}
967
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000968const struct ethtool_ops qlcnic_ethtool_ops = {
969 .get_settings = qlcnic_get_settings,
970 .set_settings = qlcnic_set_settings,
971 .get_drvinfo = qlcnic_get_drvinfo,
972 .get_regs_len = qlcnic_get_regs_len,
973 .get_regs = qlcnic_get_regs,
974 .get_link = ethtool_op_get_link,
975 .get_eeprom_len = qlcnic_get_eeprom_len,
976 .get_eeprom = qlcnic_get_eeprom,
977 .get_ringparam = qlcnic_get_ringparam,
978 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000979 .get_channels = qlcnic_get_channels,
980 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000981 .get_pauseparam = qlcnic_get_pauseparam,
982 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000983 .get_wol = qlcnic_get_wol,
984 .set_wol = qlcnic_set_wol,
985 .self_test = qlcnic_diag_test,
986 .get_strings = qlcnic_get_strings,
987 .get_ethtool_stats = qlcnic_get_ethtool_stats,
988 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000989 .get_coalesce = qlcnic_get_intr_coalesce,
990 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +0000991 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +0000992 .set_msglevel = qlcnic_set_msglevel,
993 .get_msglevel = qlcnic_get_msglevel,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000994};