blob: 11f4df75e84c9202be18f9e2d81ccab33c7ce1a3 [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 Chakraborty22c8c932011-06-22 02:52:23 +000087 "Interrupt_Test_offline",
Amit Kumar Salechae1428d22011-06-29 20:00:50 +000088 "Internal_Loopback_offline",
89 "External_Loopback_offline"
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000090};
91
92#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
93
94#define QLCNIC_RING_REGS_COUNT 20
95#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
96#define QLCNIC_MAX_EEPROM_LEN 1024
97
98static const u32 diag_registers[] = {
99 CRB_CMDPEG_STATE,
100 CRB_RCVPEG_STATE,
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000101 CRB_XG_STATE_P3P,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000102 CRB_FW_CAPABILITIES_1,
103 ISR_INT_STATE_REG,
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000104 QLCNIC_CRB_DRV_ACTIVE,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000105 QLCNIC_CRB_DEV_STATE,
106 QLCNIC_CRB_DRV_STATE,
107 QLCNIC_CRB_DRV_SCRATCH,
108 QLCNIC_CRB_DEV_PARTITION_INFO,
109 QLCNIC_CRB_DRV_IDC_VER,
110 QLCNIC_PEG_ALIVE_COUNTER,
111 QLCNIC_PEG_HALT_STATUS1,
112 QLCNIC_PEG_HALT_STATUS2,
113 QLCNIC_CRB_PEG_NET_0+0x3c,
114 QLCNIC_CRB_PEG_NET_1+0x3c,
115 QLCNIC_CRB_PEG_NET_2+0x3c,
116 QLCNIC_CRB_PEG_NET_4+0x3c,
117 -1
118};
119
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000120#define QLCNIC_MGMT_API_VERSION 2
121#define QLCNIC_DEV_INFO_SIZE 1
122#define QLCNIC_ETHTOOL_REGS_VER 2
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000123static int qlcnic_get_regs_len(struct net_device *dev)
124{
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000125 return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
126 QLCNIC_DEV_INFO_SIZE + 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000127}
128
129static int qlcnic_get_eeprom_len(struct net_device *dev)
130{
131 return QLCNIC_FLASH_TOTAL_SIZE;
132}
133
134static void
135qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
136{
137 struct qlcnic_adapter *adapter = netdev_priv(dev);
138 u32 fw_major, fw_minor, fw_build;
139
140 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
141 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
142 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
143 sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
144
145 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
146 strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
147 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
148}
149
150static int
151qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
152{
153 struct qlcnic_adapter *adapter = netdev_priv(dev);
154 int check_sfp_module = 0;
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000155 u16 pcifn = adapter->ahw->pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000156
157 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000158 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000159 ecmd->supported = (SUPPORTED_10baseT_Half |
160 SUPPORTED_10baseT_Full |
161 SUPPORTED_100baseT_Half |
162 SUPPORTED_100baseT_Full |
163 SUPPORTED_1000baseT_Half |
164 SUPPORTED_1000baseT_Full);
165
166 ecmd->advertising = (ADVERTISED_100baseT_Half |
167 ADVERTISED_100baseT_Full |
168 ADVERTISED_1000baseT_Half |
169 ADVERTISED_1000baseT_Full);
170
David Decotigny70739492011-04-27 18:32:40 +0000171 ethtool_cmd_speed_set(ecmd, adapter->link_speed);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000172 ecmd->duplex = adapter->link_duplex;
173 ecmd->autoneg = adapter->link_autoneg;
174
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000175 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000176 u32 val;
177
178 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
179 if (val == QLCNIC_PORT_MODE_802_3_AP) {
180 ecmd->supported = SUPPORTED_1000baseT_Full;
181 ecmd->advertising = ADVERTISED_1000baseT_Full;
182 } else {
183 ecmd->supported = SUPPORTED_10000baseT_Full;
184 ecmd->advertising = ADVERTISED_10000baseT_Full;
185 }
186
187 if (netif_running(dev) && adapter->has_link_events) {
David Decotigny70739492011-04-27 18:32:40 +0000188 ethtool_cmd_speed_set(ecmd, adapter->link_speed);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000189 ecmd->autoneg = adapter->link_autoneg;
190 ecmd->duplex = adapter->link_duplex;
191 goto skip;
192 }
193
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000194 val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
David Decotigny70739492011-04-27 18:32:40 +0000195 ethtool_cmd_speed_set(ecmd, P3P_LINK_SPEED_MHZ *
196 P3P_LINK_SPEED_VAL(pcifn, val));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000197 ecmd->duplex = DUPLEX_FULL;
198 ecmd->autoneg = AUTONEG_DISABLE;
199 } else
200 return -EIO;
201
202skip:
203 ecmd->phy_address = adapter->physical_port;
204 ecmd->transceiver = XCVR_EXTERNAL;
205
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000206 switch (adapter->ahw->board_type) {
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000207 case QLCNIC_BRDTYPE_P3P_REF_QG:
208 case QLCNIC_BRDTYPE_P3P_4_GB:
209 case QLCNIC_BRDTYPE_P3P_4_GB_MM:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000210
211 ecmd->supported |= SUPPORTED_Autoneg;
212 ecmd->advertising |= ADVERTISED_Autoneg;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000213 case QLCNIC_BRDTYPE_P3P_10G_CX4:
214 case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
215 case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000216 ecmd->supported |= SUPPORTED_TP;
217 ecmd->advertising |= ADVERTISED_TP;
218 ecmd->port = PORT_TP;
219 ecmd->autoneg = adapter->link_autoneg;
220 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000221 case QLCNIC_BRDTYPE_P3P_IMEZ:
222 case QLCNIC_BRDTYPE_P3P_XG_LOM:
223 case QLCNIC_BRDTYPE_P3P_HMEZ:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000224 ecmd->supported |= SUPPORTED_MII;
225 ecmd->advertising |= ADVERTISED_MII;
226 ecmd->port = PORT_MII;
227 ecmd->autoneg = AUTONEG_DISABLE;
228 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000229 case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
230 case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
231 case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000232 ecmd->advertising |= ADVERTISED_TP;
233 ecmd->supported |= SUPPORTED_TP;
234 check_sfp_module = netif_running(dev) &&
235 adapter->has_link_events;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000236 case QLCNIC_BRDTYPE_P3P_10G_XFP:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000237 ecmd->supported |= SUPPORTED_FIBRE;
238 ecmd->advertising |= ADVERTISED_FIBRE;
239 ecmd->port = PORT_FIBRE;
240 ecmd->autoneg = AUTONEG_DISABLE;
241 break;
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000242 case QLCNIC_BRDTYPE_P3P_10G_TP:
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000243 if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000244 ecmd->autoneg = AUTONEG_DISABLE;
245 ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
246 ecmd->advertising |=
247 (ADVERTISED_FIBRE | ADVERTISED_TP);
248 ecmd->port = PORT_FIBRE;
249 check_sfp_module = netif_running(dev) &&
250 adapter->has_link_events;
251 } else {
252 ecmd->autoneg = AUTONEG_ENABLE;
253 ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
254 ecmd->advertising |=
255 (ADVERTISED_TP | ADVERTISED_Autoneg);
256 ecmd->port = PORT_TP;
257 }
258 break;
259 default:
260 dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000261 adapter->ahw->board_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000262 return -EIO;
263 }
264
265 if (check_sfp_module) {
266 switch (adapter->module_type) {
267 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
268 case LINKEVENT_MODULE_OPTICAL_SRLR:
269 case LINKEVENT_MODULE_OPTICAL_LRM:
270 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
271 ecmd->port = PORT_FIBRE;
272 break;
273 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
274 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
275 case LINKEVENT_MODULE_TWINAX:
276 ecmd->port = PORT_TP;
277 break;
278 default:
279 ecmd->port = PORT_OTHER;
280 }
281 }
282
283 return 0;
284}
285
286static int
287qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
288{
Sony Chacko7e610ca2011-04-28 11:48:19 +0000289 u32 config = 0;
290 u32 ret = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000291 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sony Chacko7e610ca2011-04-28 11:48:19 +0000292
293 if (adapter->ahw->port_type != QLCNIC_GBE)
294 return -EOPNOTSUPP;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000295
296 /* read which mode */
Sony Chacko7e610ca2011-04-28 11:48:19 +0000297 if (ecmd->duplex)
298 config |= 0x1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000299
Sony Chacko7e610ca2011-04-28 11:48:19 +0000300 if (ecmd->autoneg)
301 config |= 0x2;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000302
Sony Chacko7e610ca2011-04-28 11:48:19 +0000303 switch (ethtool_cmd_speed(ecmd)) {
304 case SPEED_10:
305 config |= (0 << 8);
306 break;
307 case SPEED_100:
308 config |= (1 << 8);
309 break;
310 case SPEED_1000:
311 config |= (10 << 8);
312 break;
313 default:
314 return -EIO;
315 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000316
Sony Chacko7e610ca2011-04-28 11:48:19 +0000317 ret = qlcnic_fw_cmd_set_port(adapter, config);
318
319 if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000320 return -EOPNOTSUPP;
Sony Chacko7e610ca2011-04-28 11:48:19 +0000321 else if (ret)
322 return -EIO;
323
324 adapter->link_speed = ethtool_cmd_speed(ecmd);
325 adapter->link_duplex = ecmd->duplex;
326 adapter->link_autoneg = ecmd->autoneg;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000327
328 if (!netif_running(dev))
329 return 0;
330
331 dev->netdev_ops->ndo_stop(dev);
332 return dev->netdev_ops->ndo_open(dev);
333}
334
335static void
336qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
337{
338 struct qlcnic_adapter *adapter = netdev_priv(dev);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000339 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000340 struct qlcnic_host_sds_ring *sds_ring;
341 u32 *regs_buff = p;
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000342 int ring, i = 0, j = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000343
344 memset(p, 0, qlcnic_get_regs_len(dev));
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000345 regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000346 (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000347
Rajesh Borundia2cffcdb2010-08-31 17:17:45 +0000348 regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
349 regs_buff[1] = QLCNIC_MGMT_API_VERSION;
350
Amit Kumar Salechac265eb62010-10-04 04:20:11 +0000351 for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
352 regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000353
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000354 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechace668442010-02-01 05:24:57 +0000355 return;
356
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000357 regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
358
359 regs_buff[i++] = 1; /* No. of tx ring */
360 regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
361 regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
362
363 regs_buff[i++] = 2; /* No. of rx ring */
364 regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
365 regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
366
367 regs_buff[i++] = adapter->max_sds_rings;
368
369 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
370 sds_ring = &(recv_ctx->sds_rings[ring]);
371 regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
372 }
373}
374
375static u32 qlcnic_test_link(struct net_device *dev)
376{
377 struct qlcnic_adapter *adapter = netdev_priv(dev);
378 u32 val;
379
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000380 val = QLCRD32(adapter, CRB_XG_STATE_P3P);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000381 val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
Sritej Velagaff1b1bf82010-10-07 23:46:10 +0000382 return (val == XG_LINK_UP_P3P) ? 0 : 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000383}
384
385static int
386qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
387 u8 *bytes)
388{
389 struct qlcnic_adapter *adapter = netdev_priv(dev);
390 int offset;
391 int ret;
392
393 if (eeprom->len == 0)
394 return -EINVAL;
395
396 eeprom->magic = (adapter->pdev)->vendor |
397 ((adapter->pdev)->device << 16);
398 offset = eeprom->offset;
399
400 ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
401 eeprom->len);
402 if (ret < 0)
403 return ret;
404
405 return 0;
406}
407
408static void
409qlcnic_get_ringparam(struct net_device *dev,
410 struct ethtool_ringparam *ring)
411{
412 struct qlcnic_adapter *adapter = netdev_priv(dev);
413
414 ring->rx_pending = adapter->num_rxd;
415 ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000416 ring->tx_pending = adapter->num_txd;
417
Sony Chacko90d19002010-10-26 17:53:08 +0000418 ring->rx_max_pending = adapter->max_rxd;
419 ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000420 ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
421
422 ring->rx_mini_max_pending = 0;
423 ring->rx_mini_pending = 0;
424}
425
426static u32
427qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
428{
429 u32 num_desc;
430 num_desc = max(val, min);
431 num_desc = min(num_desc, max);
432 num_desc = roundup_pow_of_two(num_desc);
433
434 if (val != num_desc) {
435 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
436 qlcnic_driver_name, r_name, num_desc, val);
437 }
438
439 return num_desc;
440}
441
442static int
443qlcnic_set_ringparam(struct net_device *dev,
444 struct ethtool_ringparam *ring)
445{
446 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000447 u16 num_rxd, num_jumbo_rxd, num_txd;
448
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000449 if (ring->rx_mini_pending)
450 return -EOPNOTSUPP;
451
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000452 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000453 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000454
455 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000456 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
457 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000458
459 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
460 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
461
462 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
463 num_jumbo_rxd == adapter->num_jumbo_rxd)
464 return 0;
465
466 adapter->num_rxd = num_rxd;
467 adapter->num_jumbo_rxd = num_jumbo_rxd;
468 adapter->num_txd = num_txd;
469
470 return qlcnic_reset_context(adapter);
471}
472
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000473static void qlcnic_get_channels(struct net_device *dev,
474 struct ethtool_channels *channel)
475{
476 struct qlcnic_adapter *adapter = netdev_priv(dev);
477
478 channel->max_rx = rounddown_pow_of_two(min_t(int,
479 adapter->max_rx_ques, num_online_cpus()));
480 channel->max_tx = adapter->max_tx_ques;
481
482 channel->rx_count = adapter->max_sds_rings;
483 channel->tx_count = adapter->max_tx_ques;
484}
485
486static int qlcnic_set_channels(struct net_device *dev,
487 struct ethtool_channels *channel)
488{
489 struct qlcnic_adapter *adapter = netdev_priv(dev);
490 int err;
491
492 if (channel->other_count || channel->combined_count ||
493 channel->tx_count != channel->max_tx)
494 return -EINVAL;
495
496 err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
497 if (err)
498 return err;
499
500 err = qlcnic_set_max_rss(adapter, channel->rx_count);
501 netdev_info(dev, "allocated 0x%x sds rings\n",
502 adapter->max_sds_rings);
503 return err;
504}
505
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000506static void
507qlcnic_get_pauseparam(struct net_device *netdev,
508 struct ethtool_pauseparam *pause)
509{
510 struct qlcnic_adapter *adapter = netdev_priv(netdev);
511 int port = adapter->physical_port;
512 __u32 val;
513
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000514 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000515 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
516 return;
517 /* get flow control settings */
518 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
519 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
520 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
521 switch (port) {
522 case 0:
523 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
524 break;
525 case 1:
526 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
527 break;
528 case 2:
529 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
530 break;
531 case 3:
532 default:
533 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
534 break;
535 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000536 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000537 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
538 return;
539 pause->rx_pause = 1;
540 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
541 if (port == 0)
542 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
543 else
544 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
545 } else {
546 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000547 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000548 }
549}
550
551static int
552qlcnic_set_pauseparam(struct net_device *netdev,
553 struct ethtool_pauseparam *pause)
554{
555 struct qlcnic_adapter *adapter = netdev_priv(netdev);
556 int port = adapter->physical_port;
557 __u32 val;
558
559 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000560 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000561 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
562 return -EIO;
563 /* set flow control */
564 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
565
566 if (pause->rx_pause)
567 qlcnic_gb_rx_flowctl(val);
568 else
569 qlcnic_gb_unset_rx_flowctl(val);
570
571 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
572 val);
573 /* set autoneg */
574 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
575 switch (port) {
576 case 0:
577 if (pause->tx_pause)
578 qlcnic_gb_unset_gb0_mask(val);
579 else
580 qlcnic_gb_set_gb0_mask(val);
581 break;
582 case 1:
583 if (pause->tx_pause)
584 qlcnic_gb_unset_gb1_mask(val);
585 else
586 qlcnic_gb_set_gb1_mask(val);
587 break;
588 case 2:
589 if (pause->tx_pause)
590 qlcnic_gb_unset_gb2_mask(val);
591 else
592 qlcnic_gb_set_gb2_mask(val);
593 break;
594 case 3:
595 default:
596 if (pause->tx_pause)
597 qlcnic_gb_unset_gb3_mask(val);
598 else
599 qlcnic_gb_set_gb3_mask(val);
600 break;
601 }
602 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000603 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000604 if (!pause->rx_pause || pause->autoneg)
605 return -EOPNOTSUPP;
606
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000607 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
608 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000609
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000610 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
611 if (port == 0) {
612 if (pause->tx_pause)
613 qlcnic_xg_unset_xg0_mask(val);
614 else
615 qlcnic_xg_set_xg0_mask(val);
616 } else {
617 if (pause->tx_pause)
618 qlcnic_xg_unset_xg1_mask(val);
619 else
620 qlcnic_xg_set_xg1_mask(val);
621 }
622 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
623 } else {
624 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000625 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000626 }
627 return 0;
628}
629
630static int qlcnic_reg_test(struct net_device *dev)
631{
632 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000633 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000634
635 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
636 if ((data_read & 0xffff) != adapter->pdev->vendor)
637 return 1;
638
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000639 return 0;
640}
641
642static int qlcnic_get_sset_count(struct net_device *dev, int sset)
643{
amit salecha3666e0b2010-10-18 01:47:48 +0000644 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000645 switch (sset) {
646 case ETH_SS_TEST:
647 return QLCNIC_TEST_LEN;
648 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000649 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
650 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000651 return QLCNIC_STATS_LEN;
652 default:
653 return -EOPNOTSUPP;
654 }
655}
656
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000657static int qlcnic_irq_test(struct net_device *netdev)
658{
659 struct qlcnic_adapter *adapter = netdev_priv(netdev);
660 int max_sds_rings = adapter->max_sds_rings;
661 int ret;
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000662 struct qlcnic_cmd_args cmd;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000663
664 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
665 return -EIO;
666
667 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
668 if (ret)
669 goto clear_it;
670
671 adapter->diag_cnt = 0;
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000672 memset(&cmd, 0, sizeof(cmd));
673 cmd.req.cmd = QLCNIC_CDRP_CMD_INTRPT_TEST;
674 cmd.req.arg1 = adapter->ahw->pci_func;
675 qlcnic_issue_cmd(adapter, &cmd);
676 ret = cmd.rsp.cmd;
677
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
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000694#define QLCNIC_ILB_PKT_SIZE 64
695#define QLCNIC_NUM_ILB_PKT 16
696#define QLCNIC_ILB_MAX_RCV_LOOP 10
697
698static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
699{
700 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
701
702 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
703
704 memcpy(data, mac, ETH_ALEN);
705 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
706
707 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
708}
709
710int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
711{
712 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
713 qlcnic_create_loopback_buff(buff, mac);
714 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
715}
716
Manish chopradf3cfbe2011-08-29 12:50:27 +0000717static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000718{
719 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
720 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
721 struct sk_buff *skb;
722 int i, loop, cnt = 0;
723
724 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
725 skb = dev_alloc_skb(QLCNIC_ILB_PKT_SIZE);
726 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
727 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
728
729 adapter->diag_cnt = 0;
730 qlcnic_xmit_frame(skb, adapter->netdev);
731
732 loop = 0;
733 do {
734 msleep(1);
735 qlcnic_process_rcv_ring_diag(sds_ring);
736 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
737 break;
738 } while (!adapter->diag_cnt);
739
740 dev_kfree_skb_any(skb);
741
742 if (!adapter->diag_cnt)
Manish chopradf3cfbe2011-08-29 12:50:27 +0000743 QLCDB(adapter, DRV,
744 "LB Test: packet #%d was not received\n", i + 1);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000745 else
746 cnt++;
747 }
748 if (cnt != i) {
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000749 dev_warn(&adapter->pdev->dev, "LB Test failed\n");
Manish chopradf3cfbe2011-08-29 12:50:27 +0000750 if (mode != QLCNIC_ILB_MODE) {
751 dev_warn(&adapter->pdev->dev,
752 "WARNING: Please make sure external"
753 "loopback connector is plugged in\n");
754 }
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000755 return -1;
756 }
757 return 0;
758}
759
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000760static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000761{
762 struct qlcnic_adapter *adapter = netdev_priv(netdev);
763 int max_sds_rings = adapter->max_sds_rings;
764 struct qlcnic_host_sds_ring *sds_ring;
765 int loop = 0;
766 int ret;
767
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000768 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
769 netdev_info(netdev, "Firmware is not loopback test capable\n");
770 return -EOPNOTSUPP;
771 }
772
Manish chopradf3cfbe2011-08-29 12:50:27 +0000773 QLCDB(adapter, DRV, "%s loopback test in progress\n",
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000774 mode == QLCNIC_ILB_MODE ? "internal" : "external");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000775 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
776 netdev_warn(netdev, "Loopback test not supported for non "
777 "privilege function\n");
778 return 0;
779 }
780
781 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000782 return -EBUSY;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000783
784 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
785 if (ret)
786 goto clear_it;
787
788 sds_ring = &adapter->recv_ctx->sds_rings[0];
789
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000790 ret = qlcnic_set_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000791 if (ret)
792 goto free_res;
793
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000794 adapter->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000795 do {
796 msleep(500);
797 qlcnic_process_rcv_ring_diag(sds_ring);
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000798 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
799 netdev_info(netdev, "firmware didnt respond to loopback"
800 " configure request\n");
801 ret = -QLCNIC_FW_NOT_RESPOND;
802 goto free_res;
803 } else if (adapter->diag_cnt) {
804 ret = adapter->diag_cnt;
805 goto free_res;
806 }
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000807 } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
808
Manish chopradf3cfbe2011-08-29 12:50:27 +0000809 ret = qlcnic_do_lb_test(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000810
811 qlcnic_clear_lb_mode(adapter);
812
813 free_res:
814 qlcnic_diag_free_res(netdev, max_sds_rings);
815
816 clear_it:
817 adapter->max_sds_rings = max_sds_rings;
818 clear_bit(__QLCNIC_RESETTING, &adapter->state);
819 return ret;
820}
821
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000822static void
823qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
824 u64 *data)
825{
826 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000827
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000828 data[0] = qlcnic_reg_test(dev);
829 if (data[0])
830 eth_test->flags |= ETH_TEST_FL_FAILED;
831
832 data[1] = (u64) qlcnic_test_link(dev);
833 if (data[1])
834 eth_test->flags |= ETH_TEST_FL_FAILED;
835
Sony Chacko13b93ed2011-01-10 00:15:22 +0000836 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000837 data[2] = qlcnic_irq_test(dev);
838 if (data[2])
839 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000840
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000841 data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000842 if (data[3])
843 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000844 if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
845 data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
846 if (data[4])
847 eth_test->flags |= ETH_TEST_FL_FAILED;
848 eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
849 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000850 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000851}
852
853static void
854qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
855{
amit salecha3666e0b2010-10-18 01:47:48 +0000856 struct qlcnic_adapter *adapter = netdev_priv(dev);
857 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000858
859 switch (stringset) {
860 case ETH_SS_TEST:
861 memcpy(data, *qlcnic_gstrings_test,
862 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
863 break;
864 case ETH_SS_STATS:
865 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
866 memcpy(data + index * ETH_GSTRING_LEN,
867 qlcnic_gstrings_stats[index].stat_string,
868 ETH_GSTRING_LEN);
869 }
amit salecha3666e0b2010-10-18 01:47:48 +0000870 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
871 return;
872 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
873 memcpy(data + index * ETH_GSTRING_LEN,
874 qlcnic_device_gstrings_stats[i],
875 ETH_GSTRING_LEN);
876 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000877 }
878}
879
amit salecha3666e0b2010-10-18 01:47:48 +0000880#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
881 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
882
883static void
884qlcnic_fill_device_stats(int *index, u64 *data,
885 struct __qlcnic_esw_statistics *stats)
886{
887 int ind = *index;
888
889 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
890 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
891 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
892 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
893 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
894 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
895 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
896
897 *index = ind;
898}
899
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000900static void
901qlcnic_get_ethtool_stats(struct net_device *dev,
902 struct ethtool_stats *stats, u64 * data)
903{
904 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000905 struct qlcnic_esw_statistics port_stats;
906 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000907
908 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
909 char *p =
910 (char *)adapter +
911 qlcnic_gstrings_stats[index].stat_offset;
912 data[index] =
913 (qlcnic_gstrings_stats[index].sizeof_stat ==
914 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
915 }
amit salecha3666e0b2010-10-18 01:47:48 +0000916
917 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
918 return;
919
920 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000921 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000922 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
923 if (ret)
924 return;
925
926 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
927
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000928 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000929 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
930 if (ret)
931 return;
932
933 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000934}
935
stephen hemminger94469f72011-04-06 11:47:23 +0000936static int qlcnic_set_led(struct net_device *dev,
937 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000938{
939 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000940 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000941
stephen hemminger94469f72011-04-06 11:47:23 +0000942 switch (state) {
943 case ETHTOOL_ID_ACTIVE:
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +0000944 if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
945 return -EBUSY;
946
stephen hemminger94469f72011-04-06 11:47:23 +0000947 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
948 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
949 return -EIO;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000950
stephen hemminger94469f72011-04-06 11:47:23 +0000951 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) {
952 clear_bit(__QLCNIC_RESETTING, &adapter->state);
953 return -EIO;
954 }
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000955 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000956 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000957
stephen hemminger94469f72011-04-06 11:47:23 +0000958 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0)
959 return 0;
960
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000961 dev_err(&adapter->pdev->dev,
962 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +0000963 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000964
stephen hemminger94469f72011-04-06 11:47:23 +0000965 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000966 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
967 dev_err(&adapter->pdev->dev,
968 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000969
stephen hemminger94469f72011-04-06 11:47:23 +0000970 break;
971
972 default:
973 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000974 }
975
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000976 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) {
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000977 qlcnic_diag_free_res(dev, max_sds_rings);
978 clear_bit(__QLCNIC_RESETTING, &adapter->state);
979 }
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000980
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +0000981 clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
982
stephen hemminger94469f72011-04-06 11:47:23 +0000983 return -EIO;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000984}
985
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000986static void
987qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
988{
989 struct qlcnic_adapter *adapter = netdev_priv(dev);
990 u32 wol_cfg;
991
992 wol->supported = 0;
993 wol->wolopts = 0;
994
995 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
996 if (wol_cfg & (1UL << adapter->portnum))
997 wol->supported |= WAKE_MAGIC;
998
999 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1000 if (wol_cfg & (1UL << adapter->portnum))
1001 wol->wolopts |= WAKE_MAGIC;
1002}
1003
1004static int
1005qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1006{
1007 struct qlcnic_adapter *adapter = netdev_priv(dev);
1008 u32 wol_cfg;
1009
1010 if (wol->wolopts & ~WAKE_MAGIC)
1011 return -EOPNOTSUPP;
1012
1013 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1014 if (!(wol_cfg & (1 << adapter->portnum)))
1015 return -EOPNOTSUPP;
1016
1017 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1018 if (wol->wolopts & WAKE_MAGIC)
1019 wol_cfg |= 1UL << adapter->portnum;
1020 else
1021 wol_cfg &= ~(1UL << adapter->portnum);
1022
1023 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1024
1025 return 0;
1026}
1027
1028/*
1029 * Set the coalescing parameters. Currently only normal is supported.
1030 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1031 * firmware coalescing to default.
1032 */
1033static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1034 struct ethtool_coalesce *ethcoal)
1035{
1036 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1037
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001038 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001039 return -EINVAL;
1040
1041 /*
1042 * Return Error if unsupported values or
1043 * unsupported parameters are set.
1044 */
1045 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1046 ethcoal->rx_max_coalesced_frames > 0xffff ||
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001047 ethcoal->tx_coalesce_usecs ||
1048 ethcoal->tx_max_coalesced_frames ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001049 ethcoal->rx_coalesce_usecs_irq ||
1050 ethcoal->rx_max_coalesced_frames_irq ||
1051 ethcoal->tx_coalesce_usecs_irq ||
1052 ethcoal->tx_max_coalesced_frames_irq ||
1053 ethcoal->stats_block_coalesce_usecs ||
1054 ethcoal->use_adaptive_rx_coalesce ||
1055 ethcoal->use_adaptive_tx_coalesce ||
1056 ethcoal->pkt_rate_low ||
1057 ethcoal->rx_coalesce_usecs_low ||
1058 ethcoal->rx_max_coalesced_frames_low ||
1059 ethcoal->tx_coalesce_usecs_low ||
1060 ethcoal->tx_max_coalesced_frames_low ||
1061 ethcoal->pkt_rate_high ||
1062 ethcoal->rx_coalesce_usecs_high ||
1063 ethcoal->rx_max_coalesced_frames_high ||
1064 ethcoal->tx_coalesce_usecs_high ||
1065 ethcoal->tx_max_coalesced_frames_high)
1066 return -EINVAL;
1067
1068 if (!ethcoal->rx_coalesce_usecs ||
1069 !ethcoal->rx_max_coalesced_frames) {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001070 adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
1071 adapter->ahw->coal.rx_time_us =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001072 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001073 adapter->ahw->coal.rx_packets =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001074 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1075 } else {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001076 adapter->ahw->coal.flag = 0;
1077 adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
1078 adapter->ahw->coal.rx_packets =
1079 ethcoal->rx_max_coalesced_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001080 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001081
1082 qlcnic_config_intr_coalesce(adapter);
1083
1084 return 0;
1085}
1086
1087static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1088 struct ethtool_coalesce *ethcoal)
1089{
1090 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1091
1092 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1093 return -EINVAL;
1094
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001095 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
1096 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001097
1098 return 0;
1099}
1100
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001101static u32 qlcnic_get_msglevel(struct net_device *netdev)
1102{
1103 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1104
1105 return adapter->msg_enable;
1106}
1107
1108static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1109{
1110 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1111
1112 adapter->msg_enable = msglvl;
1113}
1114
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001115static int
1116qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1117{
1118 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1119 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1120
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001121 if (fw_dump->clr)
1122 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1123 else
1124 dump->len = 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001125 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1126 dump->version = adapter->fw_version;
1127 return 0;
1128}
1129
1130static int
1131qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1132 void *buffer)
1133{
1134 int i, copy_sz;
1135 u32 *hdr_ptr, *data;
1136 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1137 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1138
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001139 if (!fw_dump->clr) {
1140 netdev_info(netdev, "Dump not available\n");
1141 qlcnic_api_unlock(adapter);
1142 return -EINVAL;
1143 }
1144 /* Copy template header first */
1145 copy_sz = fw_dump->tmpl_hdr->size;
1146 hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
Joe Perches43d620c2011-06-16 19:08:06 +00001147 data = buffer;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001148 for (i = 0; i < copy_sz/sizeof(u32); i++)
1149 *data++ = cpu_to_le32(*hdr_ptr++);
1150
1151 /* Copy captured dump data */
1152 memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1153 dump->len = copy_sz + fw_dump->size;
1154 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1155
1156 /* Free dump area once data has been captured */
1157 vfree(fw_dump->data);
1158 fw_dump->data = NULL;
1159 fw_dump->clr = 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001160
1161 return 0;
1162}
1163
1164static int
1165qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1166{
1167 int ret = 0;
1168 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1169 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1170
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001171 switch (val->flag) {
1172 case QLCNIC_FORCE_FW_DUMP_KEY:
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001173 if (!fw_dump->enable) {
1174 netdev_info(netdev, "FW dump not enabled\n");
1175 return ret;
1176 }
1177 if (fw_dump->clr) {
1178 dev_info(&adapter->pdev->dev,
1179 "Previous dump not cleared, not forcing dump\n");
1180 return ret;
1181 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001182 netdev_info(netdev, "Forcing a FW dump\n");
1183 qlcnic_dev_request_reset(adapter);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001184 break;
1185 case QLCNIC_DISABLE_FW_DUMP:
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001186 if (fw_dump->enable) {
1187 netdev_info(netdev, "Disabling FW dump\n");
1188 fw_dump->enable = 0;
1189 }
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001190 break;
1191 case QLCNIC_ENABLE_FW_DUMP:
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001192 if (!fw_dump->enable && fw_dump->tmpl_hdr) {
1193 netdev_info(netdev, "Enabling FW dump\n");
1194 fw_dump->enable = 1;
1195 }
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001196 break;
1197 case QLCNIC_FORCE_FW_RESET:
1198 netdev_info(netdev, "Forcing a FW reset\n");
1199 qlcnic_dev_request_reset(adapter);
1200 adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
1201 break;
1202 default:
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001203 if (val->flag > QLCNIC_DUMP_MASK_MAX ||
1204 val->flag < QLCNIC_DUMP_MASK_MIN) {
1205 netdev_info(netdev,
1206 "Invalid dump level: 0x%x\n", val->flag);
1207 ret = -EINVAL;
1208 goto out;
1209 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001210 fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001211 netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1212 fw_dump->tmpl_hdr->drv_cap_mask);
1213 }
1214out:
1215 return ret;
1216}
1217
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001218const struct ethtool_ops qlcnic_ethtool_ops = {
1219 .get_settings = qlcnic_get_settings,
1220 .set_settings = qlcnic_set_settings,
1221 .get_drvinfo = qlcnic_get_drvinfo,
1222 .get_regs_len = qlcnic_get_regs_len,
1223 .get_regs = qlcnic_get_regs,
1224 .get_link = ethtool_op_get_link,
1225 .get_eeprom_len = qlcnic_get_eeprom_len,
1226 .get_eeprom = qlcnic_get_eeprom,
1227 .get_ringparam = qlcnic_get_ringparam,
1228 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +00001229 .get_channels = qlcnic_get_channels,
1230 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001231 .get_pauseparam = qlcnic_get_pauseparam,
1232 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001233 .get_wol = qlcnic_get_wol,
1234 .set_wol = qlcnic_set_wol,
1235 .self_test = qlcnic_diag_test,
1236 .get_strings = qlcnic_get_strings,
1237 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1238 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001239 .get_coalesce = qlcnic_get_intr_coalesce,
1240 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +00001241 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001242 .set_msglevel = qlcnic_set_msglevel,
1243 .get_msglevel = qlcnic_get_msglevel,
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001244 .get_dump_flag = qlcnic_get_dump_flag,
1245 .get_dump_data = qlcnic_get_dump_data,
1246 .set_dump = qlcnic_set_dump,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001247};