blob: 8db1d1983cfe3f6fae7f305850128bea39d66b81 [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{
287 struct qlcnic_adapter *adapter = netdev_priv(dev);
288 __u32 status;
289
290 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000291 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000292 /* 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);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000343 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000344 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) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000350 (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);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000385 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000386 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
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000477static void qlcnic_get_channels(struct net_device *dev,
478 struct ethtool_channels *channel)
479{
480 struct qlcnic_adapter *adapter = netdev_priv(dev);
481
482 channel->max_rx = rounddown_pow_of_two(min_t(int,
483 adapter->max_rx_ques, num_online_cpus()));
484 channel->max_tx = adapter->max_tx_ques;
485
486 channel->rx_count = adapter->max_sds_rings;
487 channel->tx_count = adapter->max_tx_ques;
488}
489
490static int qlcnic_set_channels(struct net_device *dev,
491 struct ethtool_channels *channel)
492{
493 struct qlcnic_adapter *adapter = netdev_priv(dev);
494 int err;
495
496 if (channel->other_count || channel->combined_count ||
497 channel->tx_count != channel->max_tx)
498 return -EINVAL;
499
500 err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
501 if (err)
502 return err;
503
504 err = qlcnic_set_max_rss(adapter, channel->rx_count);
505 netdev_info(dev, "allocated 0x%x sds rings\n",
506 adapter->max_sds_rings);
507 return err;
508}
509
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000510static void
511qlcnic_get_pauseparam(struct net_device *netdev,
512 struct ethtool_pauseparam *pause)
513{
514 struct qlcnic_adapter *adapter = netdev_priv(netdev);
515 int port = adapter->physical_port;
516 __u32 val;
517
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000518 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000519 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
520 return;
521 /* get flow control settings */
522 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
523 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
524 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
525 switch (port) {
526 case 0:
527 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
528 break;
529 case 1:
530 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
531 break;
532 case 2:
533 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
534 break;
535 case 3:
536 default:
537 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
538 break;
539 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000540 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000541 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
542 return;
543 pause->rx_pause = 1;
544 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
545 if (port == 0)
546 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
547 else
548 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
549 } else {
550 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000551 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000552 }
553}
554
555static int
556qlcnic_set_pauseparam(struct net_device *netdev,
557 struct ethtool_pauseparam *pause)
558{
559 struct qlcnic_adapter *adapter = netdev_priv(netdev);
560 int port = adapter->physical_port;
561 __u32 val;
562
563 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000564 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000565 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
566 return -EIO;
567 /* set flow control */
568 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
569
570 if (pause->rx_pause)
571 qlcnic_gb_rx_flowctl(val);
572 else
573 qlcnic_gb_unset_rx_flowctl(val);
574
575 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
576 val);
577 /* set autoneg */
578 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
579 switch (port) {
580 case 0:
581 if (pause->tx_pause)
582 qlcnic_gb_unset_gb0_mask(val);
583 else
584 qlcnic_gb_set_gb0_mask(val);
585 break;
586 case 1:
587 if (pause->tx_pause)
588 qlcnic_gb_unset_gb1_mask(val);
589 else
590 qlcnic_gb_set_gb1_mask(val);
591 break;
592 case 2:
593 if (pause->tx_pause)
594 qlcnic_gb_unset_gb2_mask(val);
595 else
596 qlcnic_gb_set_gb2_mask(val);
597 break;
598 case 3:
599 default:
600 if (pause->tx_pause)
601 qlcnic_gb_unset_gb3_mask(val);
602 else
603 qlcnic_gb_set_gb3_mask(val);
604 break;
605 }
606 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000607 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000608 if (!pause->rx_pause || pause->autoneg)
609 return -EOPNOTSUPP;
610
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000611 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
612 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000613
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000614 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
615 if (port == 0) {
616 if (pause->tx_pause)
617 qlcnic_xg_unset_xg0_mask(val);
618 else
619 qlcnic_xg_set_xg0_mask(val);
620 } else {
621 if (pause->tx_pause)
622 qlcnic_xg_unset_xg1_mask(val);
623 else
624 qlcnic_xg_set_xg1_mask(val);
625 }
626 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
627 } else {
628 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000629 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000630 }
631 return 0;
632}
633
634static int qlcnic_reg_test(struct net_device *dev)
635{
636 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000637 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000638
639 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
640 if ((data_read & 0xffff) != adapter->pdev->vendor)
641 return 1;
642
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000643 return 0;
644}
645
646static int qlcnic_get_sset_count(struct net_device *dev, int sset)
647{
amit salecha3666e0b2010-10-18 01:47:48 +0000648 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000649 switch (sset) {
650 case ETH_SS_TEST:
651 return QLCNIC_TEST_LEN;
652 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000653 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
654 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000655 return QLCNIC_STATS_LEN;
656 default:
657 return -EOPNOTSUPP;
658 }
659}
660
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000661static int qlcnic_irq_test(struct net_device *netdev)
662{
663 struct qlcnic_adapter *adapter = netdev_priv(netdev);
664 int max_sds_rings = adapter->max_sds_rings;
665 int ret;
666
667 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
668 return -EIO;
669
670 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
671 if (ret)
672 goto clear_it;
673
674 adapter->diag_cnt = 0;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000675 ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func,
676 adapter->fw_hal_version, adapter->ahw->pci_func,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000677 0, 0, 0x00000011);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000678 if (ret)
679 goto done;
680
681 msleep(10);
682
683 ret = !adapter->diag_cnt;
684
685done:
686 qlcnic_diag_free_res(netdev, max_sds_rings);
687
688clear_it:
689 adapter->max_sds_rings = max_sds_rings;
690 clear_bit(__QLCNIC_RESETTING, &adapter->state);
691 return ret;
692}
693
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000694static void
695qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
696 u64 *data)
697{
698 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000699
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000700 data[0] = qlcnic_reg_test(dev);
701 if (data[0])
702 eth_test->flags |= ETH_TEST_FL_FAILED;
703
704 data[1] = (u64) qlcnic_test_link(dev);
705 if (data[1])
706 eth_test->flags |= ETH_TEST_FL_FAILED;
707
Sony Chacko13b93ed2011-01-10 00:15:22 +0000708 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000709 data[2] = qlcnic_irq_test(dev);
710 if (data[2])
711 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000712
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000713
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000714 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000715}
716
717static void
718qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
719{
amit salecha3666e0b2010-10-18 01:47:48 +0000720 struct qlcnic_adapter *adapter = netdev_priv(dev);
721 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000722
723 switch (stringset) {
724 case ETH_SS_TEST:
725 memcpy(data, *qlcnic_gstrings_test,
726 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
727 break;
728 case ETH_SS_STATS:
729 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
730 memcpy(data + index * ETH_GSTRING_LEN,
731 qlcnic_gstrings_stats[index].stat_string,
732 ETH_GSTRING_LEN);
733 }
amit salecha3666e0b2010-10-18 01:47:48 +0000734 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
735 return;
736 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
737 memcpy(data + index * ETH_GSTRING_LEN,
738 qlcnic_device_gstrings_stats[i],
739 ETH_GSTRING_LEN);
740 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000741 }
742}
743
amit salecha3666e0b2010-10-18 01:47:48 +0000744#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
745 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
746
747static void
748qlcnic_fill_device_stats(int *index, u64 *data,
749 struct __qlcnic_esw_statistics *stats)
750{
751 int ind = *index;
752
753 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
754 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
755 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
756 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
757 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
758 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
759 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
760
761 *index = ind;
762}
763
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000764static void
765qlcnic_get_ethtool_stats(struct net_device *dev,
766 struct ethtool_stats *stats, u64 * data)
767{
768 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000769 struct qlcnic_esw_statistics port_stats;
770 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000771
772 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
773 char *p =
774 (char *)adapter +
775 qlcnic_gstrings_stats[index].stat_offset;
776 data[index] =
777 (qlcnic_gstrings_stats[index].sizeof_stat ==
778 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
779 }
amit salecha3666e0b2010-10-18 01:47:48 +0000780
781 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
782 return;
783
784 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000785 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000786 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
787 if (ret)
788 return;
789
790 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
791
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000792 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000793 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
794 if (ret)
795 return;
796
797 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000798}
799
stephen hemminger94469f72011-04-06 11:47:23 +0000800static int qlcnic_set_led(struct net_device *dev,
801 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000802{
803 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000804 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000805
stephen hemminger94469f72011-04-06 11:47:23 +0000806 switch (state) {
807 case ETHTOOL_ID_ACTIVE:
stephen hemminger94469f72011-04-06 11:47:23 +0000808 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
809 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
810 return -EIO;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000811
stephen hemminger94469f72011-04-06 11:47:23 +0000812 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) {
813 clear_bit(__QLCNIC_RESETTING, &adapter->state);
814 return -EIO;
815 }
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000816 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000817 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000818
stephen hemminger94469f72011-04-06 11:47:23 +0000819 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0)
820 return 0;
821
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000822 dev_err(&adapter->pdev->dev,
823 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +0000824 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000825
stephen hemminger94469f72011-04-06 11:47:23 +0000826 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000827 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
828 dev_err(&adapter->pdev->dev,
829 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000830
stephen hemminger94469f72011-04-06 11:47:23 +0000831 break;
832
833 default:
834 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000835 }
836
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000837 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) {
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000838 qlcnic_diag_free_res(dev, max_sds_rings);
839 clear_bit(__QLCNIC_RESETTING, &adapter->state);
840 }
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000841
stephen hemminger94469f72011-04-06 11:47:23 +0000842 return -EIO;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000843}
844
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000845static void
846qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
847{
848 struct qlcnic_adapter *adapter = netdev_priv(dev);
849 u32 wol_cfg;
850
851 wol->supported = 0;
852 wol->wolopts = 0;
853
854 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
855 if (wol_cfg & (1UL << adapter->portnum))
856 wol->supported |= WAKE_MAGIC;
857
858 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
859 if (wol_cfg & (1UL << adapter->portnum))
860 wol->wolopts |= WAKE_MAGIC;
861}
862
863static int
864qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
865{
866 struct qlcnic_adapter *adapter = netdev_priv(dev);
867 u32 wol_cfg;
868
869 if (wol->wolopts & ~WAKE_MAGIC)
870 return -EOPNOTSUPP;
871
872 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
873 if (!(wol_cfg & (1 << adapter->portnum)))
874 return -EOPNOTSUPP;
875
876 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
877 if (wol->wolopts & WAKE_MAGIC)
878 wol_cfg |= 1UL << adapter->portnum;
879 else
880 wol_cfg &= ~(1UL << adapter->portnum);
881
882 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
883
884 return 0;
885}
886
887/*
888 * Set the coalescing parameters. Currently only normal is supported.
889 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
890 * firmware coalescing to default.
891 */
892static int qlcnic_set_intr_coalesce(struct net_device *netdev,
893 struct ethtool_coalesce *ethcoal)
894{
895 struct qlcnic_adapter *adapter = netdev_priv(netdev);
896
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000897 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000898 return -EINVAL;
899
900 /*
901 * Return Error if unsupported values or
902 * unsupported parameters are set.
903 */
904 if (ethcoal->rx_coalesce_usecs > 0xffff ||
905 ethcoal->rx_max_coalesced_frames > 0xffff ||
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000906 ethcoal->tx_coalesce_usecs ||
907 ethcoal->tx_max_coalesced_frames ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000908 ethcoal->rx_coalesce_usecs_irq ||
909 ethcoal->rx_max_coalesced_frames_irq ||
910 ethcoal->tx_coalesce_usecs_irq ||
911 ethcoal->tx_max_coalesced_frames_irq ||
912 ethcoal->stats_block_coalesce_usecs ||
913 ethcoal->use_adaptive_rx_coalesce ||
914 ethcoal->use_adaptive_tx_coalesce ||
915 ethcoal->pkt_rate_low ||
916 ethcoal->rx_coalesce_usecs_low ||
917 ethcoal->rx_max_coalesced_frames_low ||
918 ethcoal->tx_coalesce_usecs_low ||
919 ethcoal->tx_max_coalesced_frames_low ||
920 ethcoal->pkt_rate_high ||
921 ethcoal->rx_coalesce_usecs_high ||
922 ethcoal->rx_max_coalesced_frames_high ||
923 ethcoal->tx_coalesce_usecs_high ||
924 ethcoal->tx_max_coalesced_frames_high)
925 return -EINVAL;
926
927 if (!ethcoal->rx_coalesce_usecs ||
928 !ethcoal->rx_max_coalesced_frames) {
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000929 adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
930 adapter->ahw->coal.rx_time_us =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000931 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000932 adapter->ahw->coal.rx_packets =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000933 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
934 } else {
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000935 adapter->ahw->coal.flag = 0;
936 adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
937 adapter->ahw->coal.rx_packets =
938 ethcoal->rx_max_coalesced_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000939 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000940
941 qlcnic_config_intr_coalesce(adapter);
942
943 return 0;
944}
945
946static int qlcnic_get_intr_coalesce(struct net_device *netdev,
947 struct ethtool_coalesce *ethcoal)
948{
949 struct qlcnic_adapter *adapter = netdev_priv(netdev);
950
951 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
952 return -EINVAL;
953
Anirban Chakraborty8816d002011-04-01 14:28:21 +0000954 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
955 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000956
957 return 0;
958}
959
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +0000960static u32 qlcnic_get_msglevel(struct net_device *netdev)
961{
962 struct qlcnic_adapter *adapter = netdev_priv(netdev);
963
964 return adapter->msg_enable;
965}
966
967static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
968{
969 struct qlcnic_adapter *adapter = netdev_priv(netdev);
970
971 adapter->msg_enable = msglvl;
972}
973
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000974const struct ethtool_ops qlcnic_ethtool_ops = {
975 .get_settings = qlcnic_get_settings,
976 .set_settings = qlcnic_set_settings,
977 .get_drvinfo = qlcnic_get_drvinfo,
978 .get_regs_len = qlcnic_get_regs_len,
979 .get_regs = qlcnic_get_regs,
980 .get_link = ethtool_op_get_link,
981 .get_eeprom_len = qlcnic_get_eeprom_len,
982 .get_eeprom = qlcnic_get_eeprom,
983 .get_ringparam = qlcnic_get_ringparam,
984 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000985 .get_channels = qlcnic_get_channels,
986 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000987 .get_pauseparam = qlcnic_get_pauseparam,
988 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000989 .get_wol = qlcnic_get_wol,
990 .set_wol = qlcnic_set_wol,
991 .self_test = qlcnic_diag_test,
992 .get_strings = qlcnic_get_strings,
993 .get_ethtool_stats = qlcnic_get_ethtool_stats,
994 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000995 .get_coalesce = qlcnic_get_intr_coalesce,
996 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +0000997 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +0000998 .set_msglevel = qlcnic_set_msglevel,
999 .get_msglevel = qlcnic_get_msglevel,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001000};