blob: 89ddf7f7d7df40b93e7a27431be82eb98cec8c4a [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);
Rick Jones68aad782011-11-07 13:29:27 +0000143 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
144 "%d.%d.%d", fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000145
Rick Jones68aad782011-11-07 13:29:27 +0000146 strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
147 sizeof(drvinfo->bus_info));
148 strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
149 strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
150 sizeof(drvinfo->version));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000151}
152
153static int
154qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
155{
156 struct qlcnic_adapter *adapter = netdev_priv(dev);
157 int check_sfp_module = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000158
159 /* read which mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000160 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000161 ecmd->supported = (SUPPORTED_10baseT_Half |
162 SUPPORTED_10baseT_Full |
163 SUPPORTED_100baseT_Half |
164 SUPPORTED_100baseT_Full |
165 SUPPORTED_1000baseT_Half |
166 SUPPORTED_1000baseT_Full);
167
168 ecmd->advertising = (ADVERTISED_100baseT_Half |
169 ADVERTISED_100baseT_Full |
170 ADVERTISED_1000baseT_Half |
171 ADVERTISED_1000baseT_Full);
172
David Decotigny70739492011-04-27 18:32:40 +0000173 ethtool_cmd_speed_set(ecmd, adapter->link_speed);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000174 ecmd->duplex = adapter->link_duplex;
175 ecmd->autoneg = adapter->link_autoneg;
176
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000177 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000178 u32 val;
179
180 val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
181 if (val == QLCNIC_PORT_MODE_802_3_AP) {
182 ecmd->supported = SUPPORTED_1000baseT_Full;
183 ecmd->advertising = ADVERTISED_1000baseT_Full;
184 } else {
185 ecmd->supported = SUPPORTED_10000baseT_Full;
186 ecmd->advertising = ADVERTISED_10000baseT_Full;
187 }
188
189 if (netif_running(dev) && adapter->has_link_events) {
David Decotigny70739492011-04-27 18:32:40 +0000190 ethtool_cmd_speed_set(ecmd, adapter->link_speed);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000191 ecmd->autoneg = adapter->link_autoneg;
192 ecmd->duplex = adapter->link_duplex;
193 goto skip;
194 }
195
Sony Chacko476a4b62012-02-03 13:45:42 +0000196 ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
197 ecmd->duplex = DUPLEX_UNKNOWN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000198 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;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000421}
422
423static u32
424qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
425{
426 u32 num_desc;
427 num_desc = max(val, min);
428 num_desc = min(num_desc, max);
429 num_desc = roundup_pow_of_two(num_desc);
430
431 if (val != num_desc) {
432 printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
433 qlcnic_driver_name, r_name, num_desc, val);
434 }
435
436 return num_desc;
437}
438
439static int
440qlcnic_set_ringparam(struct net_device *dev,
441 struct ethtool_ringparam *ring)
442{
443 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000444 u16 num_rxd, num_jumbo_rxd, num_txd;
445
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000446 if (ring->rx_mini_pending)
447 return -EOPNOTSUPP;
448
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000449 num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000450 MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000451
452 num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
Sony Chacko90d19002010-10-26 17:53:08 +0000453 MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
454 "rx jumbo");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000455
456 num_txd = qlcnic_validate_ringparam(ring->tx_pending,
457 MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
458
459 if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
460 num_jumbo_rxd == adapter->num_jumbo_rxd)
461 return 0;
462
463 adapter->num_rxd = num_rxd;
464 adapter->num_jumbo_rxd = num_jumbo_rxd;
465 adapter->num_txd = num_txd;
466
467 return qlcnic_reset_context(adapter);
468}
469
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +0000470static void qlcnic_get_channels(struct net_device *dev,
471 struct ethtool_channels *channel)
472{
473 struct qlcnic_adapter *adapter = netdev_priv(dev);
474
475 channel->max_rx = rounddown_pow_of_two(min_t(int,
476 adapter->max_rx_ques, num_online_cpus()));
477 channel->max_tx = adapter->max_tx_ques;
478
479 channel->rx_count = adapter->max_sds_rings;
480 channel->tx_count = adapter->max_tx_ques;
481}
482
483static int qlcnic_set_channels(struct net_device *dev,
484 struct ethtool_channels *channel)
485{
486 struct qlcnic_adapter *adapter = netdev_priv(dev);
487 int err;
488
489 if (channel->other_count || channel->combined_count ||
490 channel->tx_count != channel->max_tx)
491 return -EINVAL;
492
493 err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
494 if (err)
495 return err;
496
497 err = qlcnic_set_max_rss(adapter, channel->rx_count);
498 netdev_info(dev, "allocated 0x%x sds rings\n",
499 adapter->max_sds_rings);
500 return err;
501}
502
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000503static void
504qlcnic_get_pauseparam(struct net_device *netdev,
505 struct ethtool_pauseparam *pause)
506{
507 struct qlcnic_adapter *adapter = netdev_priv(netdev);
508 int port = adapter->physical_port;
509 __u32 val;
510
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000511 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000512 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
513 return;
514 /* get flow control settings */
515 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
516 pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
517 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
518 switch (port) {
519 case 0:
520 pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
521 break;
522 case 1:
523 pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
524 break;
525 case 2:
526 pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
527 break;
528 case 3:
529 default:
530 pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
531 break;
532 }
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000533 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000534 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
535 return;
536 pause->rx_pause = 1;
537 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
538 if (port == 0)
539 pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
540 else
541 pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
542 } else {
543 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000544 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000545 }
546}
547
548static int
549qlcnic_set_pauseparam(struct net_device *netdev,
550 struct ethtool_pauseparam *pause)
551{
552 struct qlcnic_adapter *adapter = netdev_priv(netdev);
553 int port = adapter->physical_port;
554 __u32 val;
555
556 /* read mode */
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000557 if (adapter->ahw->port_type == QLCNIC_GBE) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000558 if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
559 return -EIO;
560 /* set flow control */
561 val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
562
563 if (pause->rx_pause)
564 qlcnic_gb_rx_flowctl(val);
565 else
566 qlcnic_gb_unset_rx_flowctl(val);
567
568 QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
569 val);
570 /* set autoneg */
571 val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
572 switch (port) {
573 case 0:
574 if (pause->tx_pause)
575 qlcnic_gb_unset_gb0_mask(val);
576 else
577 qlcnic_gb_set_gb0_mask(val);
578 break;
579 case 1:
580 if (pause->tx_pause)
581 qlcnic_gb_unset_gb1_mask(val);
582 else
583 qlcnic_gb_set_gb1_mask(val);
584 break;
585 case 2:
586 if (pause->tx_pause)
587 qlcnic_gb_unset_gb2_mask(val);
588 else
589 qlcnic_gb_set_gb2_mask(val);
590 break;
591 case 3:
592 default:
593 if (pause->tx_pause)
594 qlcnic_gb_unset_gb3_mask(val);
595 else
596 qlcnic_gb_set_gb3_mask(val);
597 break;
598 }
599 QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000600 } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
Rajesh Borundia6d181682010-07-13 20:33:31 +0000601 if (!pause->rx_pause || pause->autoneg)
602 return -EOPNOTSUPP;
603
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000604 if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
605 return -EIO;
Rajesh Borundia6d181682010-07-13 20:33:31 +0000606
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000607 val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
608 if (port == 0) {
609 if (pause->tx_pause)
610 qlcnic_xg_unset_xg0_mask(val);
611 else
612 qlcnic_xg_set_xg0_mask(val);
613 } else {
614 if (pause->tx_pause)
615 qlcnic_xg_unset_xg1_mask(val);
616 else
617 qlcnic_xg_set_xg1_mask(val);
618 }
619 QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
620 } else {
621 dev_err(&netdev->dev, "Unknown board type: %x\n",
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000622 adapter->ahw->port_type);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000623 }
624 return 0;
625}
626
627static int qlcnic_reg_test(struct net_device *dev)
628{
629 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechadeffab02010-05-13 03:07:43 +0000630 u32 data_read;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000631
632 data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
633 if ((data_read & 0xffff) != adapter->pdev->vendor)
634 return 1;
635
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000636 return 0;
637}
638
639static int qlcnic_get_sset_count(struct net_device *dev, int sset)
640{
amit salecha3666e0b2010-10-18 01:47:48 +0000641 struct qlcnic_adapter *adapter = netdev_priv(dev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000642 switch (sset) {
643 case ETH_SS_TEST:
644 return QLCNIC_TEST_LEN;
645 case ETH_SS_STATS:
amit salecha3666e0b2010-10-18 01:47:48 +0000646 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
647 return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000648 return QLCNIC_STATS_LEN;
649 default:
650 return -EOPNOTSUPP;
651 }
652}
653
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000654static int qlcnic_irq_test(struct net_device *netdev)
655{
656 struct qlcnic_adapter *adapter = netdev_priv(netdev);
657 int max_sds_rings = adapter->max_sds_rings;
658 int ret;
Anirban Chakraborty7777de92011-09-13 08:06:18 +0000659 struct qlcnic_cmd_args cmd;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000660
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 Chakraborty7777de92011-09-13 08:06:18 +0000669 memset(&cmd, 0, sizeof(cmd));
670 cmd.req.cmd = QLCNIC_CDRP_CMD_INTRPT_TEST;
671 cmd.req.arg1 = adapter->ahw->pci_func;
672 qlcnic_issue_cmd(adapter, &cmd);
673 ret = cmd.rsp.cmd;
674
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000675 if (ret)
676 goto done;
677
678 msleep(10);
679
680 ret = !adapter->diag_cnt;
681
682done:
683 qlcnic_diag_free_res(netdev, max_sds_rings);
684
685clear_it:
686 adapter->max_sds_rings = max_sds_rings;
687 clear_bit(__QLCNIC_RESETTING, &adapter->state);
688 return ret;
689}
690
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000691#define QLCNIC_ILB_PKT_SIZE 64
692#define QLCNIC_NUM_ILB_PKT 16
693#define QLCNIC_ILB_MAX_RCV_LOOP 10
694
695static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
696{
697 unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
698
699 memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
700
701 memcpy(data, mac, ETH_ALEN);
702 memcpy(data + ETH_ALEN, mac, ETH_ALEN);
703
704 memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
705}
706
707int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
708{
709 unsigned char buff[QLCNIC_ILB_PKT_SIZE];
710 qlcnic_create_loopback_buff(buff, mac);
711 return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
712}
713
Manish chopradf3cfbe2011-08-29 12:50:27 +0000714static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000715{
716 struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
717 struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
718 struct sk_buff *skb;
719 int i, loop, cnt = 0;
720
721 for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
Pradeep A. Dalvidae2e9f2012-02-06 11:16:13 +0000722 skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000723 qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
724 skb_put(skb, QLCNIC_ILB_PKT_SIZE);
725
726 adapter->diag_cnt = 0;
727 qlcnic_xmit_frame(skb, adapter->netdev);
728
729 loop = 0;
730 do {
731 msleep(1);
732 qlcnic_process_rcv_ring_diag(sds_ring);
733 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
734 break;
735 } while (!adapter->diag_cnt);
736
737 dev_kfree_skb_any(skb);
738
739 if (!adapter->diag_cnt)
Manish chopradf3cfbe2011-08-29 12:50:27 +0000740 QLCDB(adapter, DRV,
741 "LB Test: packet #%d was not received\n", i + 1);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000742 else
743 cnt++;
744 }
745 if (cnt != i) {
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000746 dev_warn(&adapter->pdev->dev, "LB Test failed\n");
Manish chopradf3cfbe2011-08-29 12:50:27 +0000747 if (mode != QLCNIC_ILB_MODE) {
748 dev_warn(&adapter->pdev->dev,
749 "WARNING: Please make sure external"
750 "loopback connector is plugged in\n");
751 }
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000752 return -1;
753 }
754 return 0;
755}
756
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000757static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000758{
759 struct qlcnic_adapter *adapter = netdev_priv(netdev);
760 int max_sds_rings = adapter->max_sds_rings;
761 struct qlcnic_host_sds_ring *sds_ring;
762 int loop = 0;
763 int ret;
764
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000765 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
766 netdev_info(netdev, "Firmware is not loopback test capable\n");
767 return -EOPNOTSUPP;
768 }
769
Manish chopradf3cfbe2011-08-29 12:50:27 +0000770 QLCDB(adapter, DRV, "%s loopback test in progress\n",
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000771 mode == QLCNIC_ILB_MODE ? "internal" : "external");
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000772 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
773 netdev_warn(netdev, "Loopback test not supported for non "
774 "privilege function\n");
775 return 0;
776 }
777
778 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000779 return -EBUSY;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000780
781 ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
782 if (ret)
783 goto clear_it;
784
785 sds_ring = &adapter->recv_ctx->sds_rings[0];
786
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000787 ret = qlcnic_set_lb_mode(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000788 if (ret)
789 goto free_res;
790
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000791 adapter->diag_cnt = 0;
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000792 do {
793 msleep(500);
794 qlcnic_process_rcv_ring_diag(sds_ring);
Amit Kumar Salechafef0c062011-07-14 03:16:54 +0000795 if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
796 netdev_info(netdev, "firmware didnt respond to loopback"
797 " configure request\n");
798 ret = -QLCNIC_FW_NOT_RESPOND;
799 goto free_res;
800 } else if (adapter->diag_cnt) {
801 ret = adapter->diag_cnt;
802 goto free_res;
803 }
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000804 } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
805
Manish chopradf3cfbe2011-08-29 12:50:27 +0000806 ret = qlcnic_do_lb_test(adapter, mode);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000807
808 qlcnic_clear_lb_mode(adapter);
809
810 free_res:
811 qlcnic_diag_free_res(netdev, max_sds_rings);
812
813 clear_it:
814 adapter->max_sds_rings = max_sds_rings;
815 clear_bit(__QLCNIC_RESETTING, &adapter->state);
816 return ret;
817}
818
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000819static void
820qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
821 u64 *data)
822{
823 memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000824
Sony Chacko8dec32cc2010-08-17 00:34:24 +0000825 data[0] = qlcnic_reg_test(dev);
826 if (data[0])
827 eth_test->flags |= ETH_TEST_FL_FAILED;
828
829 data[1] = (u64) qlcnic_test_link(dev);
830 if (data[1])
831 eth_test->flags |= ETH_TEST_FL_FAILED;
832
Sony Chacko13b93ed2011-01-10 00:15:22 +0000833 if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000834 data[2] = qlcnic_irq_test(dev);
835 if (data[2])
836 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechacdaff182010-02-01 05:25:00 +0000837
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000838 data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
Sucheta Chakraborty22c8c932011-06-22 02:52:23 +0000839 if (data[3])
840 eth_test->flags |= ETH_TEST_FL_FAILED;
Amit Kumar Salechae1428d22011-06-29 20:00:50 +0000841 if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
842 data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
843 if (data[4])
844 eth_test->flags |= ETH_TEST_FL_FAILED;
845 eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
846 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000847 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000848}
849
850static void
851qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
852{
amit salecha3666e0b2010-10-18 01:47:48 +0000853 struct qlcnic_adapter *adapter = netdev_priv(dev);
854 int index, i;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000855
856 switch (stringset) {
857 case ETH_SS_TEST:
858 memcpy(data, *qlcnic_gstrings_test,
859 QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
860 break;
861 case ETH_SS_STATS:
862 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
863 memcpy(data + index * ETH_GSTRING_LEN,
864 qlcnic_gstrings_stats[index].stat_string,
865 ETH_GSTRING_LEN);
866 }
amit salecha3666e0b2010-10-18 01:47:48 +0000867 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
868 return;
869 for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
870 memcpy(data + index * ETH_GSTRING_LEN,
871 qlcnic_device_gstrings_stats[i],
872 ETH_GSTRING_LEN);
873 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000874 }
875}
876
amit salecha3666e0b2010-10-18 01:47:48 +0000877#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
878 (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
879
880static void
881qlcnic_fill_device_stats(int *index, u64 *data,
882 struct __qlcnic_esw_statistics *stats)
883{
884 int ind = *index;
885
886 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
887 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
888 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
889 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
890 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
891 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
892 data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
893
894 *index = ind;
895}
896
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000897static void
898qlcnic_get_ethtool_stats(struct net_device *dev,
899 struct ethtool_stats *stats, u64 * data)
900{
901 struct qlcnic_adapter *adapter = netdev_priv(dev);
amit salecha3666e0b2010-10-18 01:47:48 +0000902 struct qlcnic_esw_statistics port_stats;
903 int index, ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000904
905 for (index = 0; index < QLCNIC_STATS_LEN; index++) {
906 char *p =
907 (char *)adapter +
908 qlcnic_gstrings_stats[index].stat_offset;
909 data[index] =
910 (qlcnic_gstrings_stats[index].sizeof_stat ==
911 sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
912 }
amit salecha3666e0b2010-10-18 01:47:48 +0000913
914 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
915 return;
916
917 memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000918 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000919 QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
920 if (ret)
921 return;
922
923 qlcnic_fill_device_stats(&index, data, &port_stats.rx);
924
Anirban Chakrabortyb1fc6d32011-04-01 14:28:05 +0000925 ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
amit salecha3666e0b2010-10-18 01:47:48 +0000926 QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
927 if (ret)
928 return;
929
930 qlcnic_fill_device_stats(&index, data, &port_stats.tx);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000931}
932
stephen hemminger94469f72011-04-06 11:47:23 +0000933static int qlcnic_set_led(struct net_device *dev,
934 enum ethtool_phys_id_state state)
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000935{
936 struct qlcnic_adapter *adapter = netdev_priv(dev);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000937 int max_sds_rings = adapter->max_sds_rings;
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000938 int err = -EIO, active = 1;
939
940 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
941 netdev_warn(dev, "LED test not supported for non "
942 "privilege function\n");
943 return -EOPNOTSUPP;
944 }
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000945
stephen hemminger94469f72011-04-06 11:47:23 +0000946 switch (state) {
947 case ETHTOOL_ID_ACTIVE:
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +0000948 if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
949 return -EBUSY;
950
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000951 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
952 break;
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000953
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000954 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
955 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
956 break;
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000957 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000958 }
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000959
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000960 if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
961 err = 0;
962 break;
963 }
stephen hemminger94469f72011-04-06 11:47:23 +0000964
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000965 dev_err(&adapter->pdev->dev,
966 "Failed to set LED blink state.\n");
stephen hemminger94469f72011-04-06 11:47:23 +0000967 break;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000968
stephen hemminger94469f72011-04-06 11:47:23 +0000969 case ETHTOOL_ID_INACTIVE:
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000970 active = 0;
971
972 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
973 break;
974
975 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
976 if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST))
977 break;
978 set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
979 }
980
Sucheta Chakraborty89b42082011-04-27 14:43:44 +0000981 if (adapter->nic_ops->config_led(adapter, 0, 0xf))
982 dev_err(&adapter->pdev->dev,
983 "Failed to reset LED blink state.\n");
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000984
stephen hemminger94469f72011-04-06 11:47:23 +0000985 break;
986
987 default:
988 return -EINVAL;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000989 }
990
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000991 if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000992 qlcnic_diag_free_res(dev, max_sds_rings);
Sucheta Chakrabortyc75822a2010-12-16 22:59:00 +0000993
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000994 if (!active || err)
995 clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
Sucheta Chakraborty728a98b2011-08-29 12:50:30 +0000996
Sucheta Chakraborty10ee0fa2011-10-28 12:57:15 +0000997 return err;
Sucheta Chakraborty897d3592010-02-01 05:24:58 +0000998}
999
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001000static void
1001qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1002{
1003 struct qlcnic_adapter *adapter = netdev_priv(dev);
1004 u32 wol_cfg;
1005
1006 wol->supported = 0;
1007 wol->wolopts = 0;
1008
1009 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1010 if (wol_cfg & (1UL << adapter->portnum))
1011 wol->supported |= WAKE_MAGIC;
1012
1013 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1014 if (wol_cfg & (1UL << adapter->portnum))
1015 wol->wolopts |= WAKE_MAGIC;
1016}
1017
1018static int
1019qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1020{
1021 struct qlcnic_adapter *adapter = netdev_priv(dev);
1022 u32 wol_cfg;
1023
1024 if (wol->wolopts & ~WAKE_MAGIC)
1025 return -EOPNOTSUPP;
1026
1027 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
1028 if (!(wol_cfg & (1 << adapter->portnum)))
1029 return -EOPNOTSUPP;
1030
1031 wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
1032 if (wol->wolopts & WAKE_MAGIC)
1033 wol_cfg |= 1UL << adapter->portnum;
1034 else
1035 wol_cfg &= ~(1UL << adapter->portnum);
1036
1037 QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
1038
1039 return 0;
1040}
1041
1042/*
1043 * Set the coalescing parameters. Currently only normal is supported.
1044 * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
1045 * firmware coalescing to default.
1046 */
1047static int qlcnic_set_intr_coalesce(struct net_device *netdev,
1048 struct ethtool_coalesce *ethcoal)
1049{
1050 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1051
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001052 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001053 return -EINVAL;
1054
1055 /*
1056 * Return Error if unsupported values or
1057 * unsupported parameters are set.
1058 */
1059 if (ethcoal->rx_coalesce_usecs > 0xffff ||
1060 ethcoal->rx_max_coalesced_frames > 0xffff ||
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001061 ethcoal->tx_coalesce_usecs ||
1062 ethcoal->tx_max_coalesced_frames ||
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001063 ethcoal->rx_coalesce_usecs_irq ||
1064 ethcoal->rx_max_coalesced_frames_irq ||
1065 ethcoal->tx_coalesce_usecs_irq ||
1066 ethcoal->tx_max_coalesced_frames_irq ||
1067 ethcoal->stats_block_coalesce_usecs ||
1068 ethcoal->use_adaptive_rx_coalesce ||
1069 ethcoal->use_adaptive_tx_coalesce ||
1070 ethcoal->pkt_rate_low ||
1071 ethcoal->rx_coalesce_usecs_low ||
1072 ethcoal->rx_max_coalesced_frames_low ||
1073 ethcoal->tx_coalesce_usecs_low ||
1074 ethcoal->tx_max_coalesced_frames_low ||
1075 ethcoal->pkt_rate_high ||
1076 ethcoal->rx_coalesce_usecs_high ||
1077 ethcoal->rx_max_coalesced_frames_high ||
1078 ethcoal->tx_coalesce_usecs_high ||
1079 ethcoal->tx_max_coalesced_frames_high)
1080 return -EINVAL;
1081
1082 if (!ethcoal->rx_coalesce_usecs ||
1083 !ethcoal->rx_max_coalesced_frames) {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001084 adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
1085 adapter->ahw->coal.rx_time_us =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001086 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001087 adapter->ahw->coal.rx_packets =
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001088 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1089 } else {
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001090 adapter->ahw->coal.flag = 0;
1091 adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
1092 adapter->ahw->coal.rx_packets =
1093 ethcoal->rx_max_coalesced_frames;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001094 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001095
1096 qlcnic_config_intr_coalesce(adapter);
1097
1098 return 0;
1099}
1100
1101static int qlcnic_get_intr_coalesce(struct net_device *netdev,
1102 struct ethtool_coalesce *ethcoal)
1103{
1104 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1105
1106 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1107 return -EINVAL;
1108
Anirban Chakraborty8816d002011-04-01 14:28:21 +00001109 ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
1110 ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001111
1112 return 0;
1113}
1114
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001115static u32 qlcnic_get_msglevel(struct net_device *netdev)
1116{
1117 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1118
1119 return adapter->msg_enable;
1120}
1121
1122static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
1123{
1124 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1125
1126 adapter->msg_enable = msglvl;
1127}
1128
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001129static int
1130qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1131{
1132 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1133 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1134
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001135 if (fw_dump->clr)
1136 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1137 else
1138 dump->len = 0;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001139 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1140 dump->version = adapter->fw_version;
1141 return 0;
1142}
1143
1144static int
1145qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1146 void *buffer)
1147{
1148 int i, copy_sz;
1149 u32 *hdr_ptr, *data;
1150 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1151 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1152
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001153 if (!fw_dump->clr) {
1154 netdev_info(netdev, "Dump not available\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001155 return -EINVAL;
1156 }
1157 /* Copy template header first */
1158 copy_sz = fw_dump->tmpl_hdr->size;
1159 hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
Joe Perches43d620c2011-06-16 19:08:06 +00001160 data = buffer;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001161 for (i = 0; i < copy_sz/sizeof(u32); i++)
1162 *data++ = cpu_to_le32(*hdr_ptr++);
1163
1164 /* Copy captured dump data */
1165 memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1166 dump->len = copy_sz + fw_dump->size;
1167 dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1168
1169 /* Free dump area once data has been captured */
1170 vfree(fw_dump->data);
1171 fw_dump->data = NULL;
1172 fw_dump->clr = 0;
Manish choprac47884e42012-02-03 13:45:44 +00001173 netdev_info(netdev, "extracted the FW dump Successfully\n");
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001174 return 0;
1175}
1176
1177static int
1178qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1179{
1180 int ret = 0;
1181 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1182 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1183
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001184 switch (val->flag) {
1185 case QLCNIC_FORCE_FW_DUMP_KEY:
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001186 if (!fw_dump->enable) {
1187 netdev_info(netdev, "FW dump not enabled\n");
1188 return ret;
1189 }
1190 if (fw_dump->clr) {
Manish choprac47884e42012-02-03 13:45:44 +00001191 netdev_info(netdev,
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001192 "Previous dump not cleared, not forcing dump\n");
1193 return ret;
1194 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001195 netdev_info(netdev, "Forcing a FW dump\n");
1196 qlcnic_dev_request_reset(adapter);
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001197 break;
1198 case QLCNIC_DISABLE_FW_DUMP:
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001199 if (fw_dump->enable) {
1200 netdev_info(netdev, "Disabling FW dump\n");
1201 fw_dump->enable = 0;
1202 }
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001203 break;
1204 case QLCNIC_ENABLE_FW_DUMP:
Anirban Chakraborty9d6a6442011-06-22 02:52:22 +00001205 if (!fw_dump->enable && fw_dump->tmpl_hdr) {
1206 netdev_info(netdev, "Enabling FW dump\n");
1207 fw_dump->enable = 1;
1208 }
Anirban Chakraborty3d465122011-07-29 13:30:26 +00001209 break;
1210 case QLCNIC_FORCE_FW_RESET:
1211 netdev_info(netdev, "Forcing a FW reset\n");
1212 qlcnic_dev_request_reset(adapter);
1213 adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
1214 break;
1215 default:
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001216 if (val->flag > QLCNIC_DUMP_MASK_MAX ||
1217 val->flag < QLCNIC_DUMP_MASK_MIN) {
1218 netdev_info(netdev,
1219 "Invalid dump level: 0x%x\n", val->flag);
1220 ret = -EINVAL;
1221 goto out;
1222 }
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001223 fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001224 netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1225 fw_dump->tmpl_hdr->drv_cap_mask);
1226 }
1227out:
1228 return ret;
1229}
1230
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001231const struct ethtool_ops qlcnic_ethtool_ops = {
1232 .get_settings = qlcnic_get_settings,
1233 .set_settings = qlcnic_set_settings,
1234 .get_drvinfo = qlcnic_get_drvinfo,
1235 .get_regs_len = qlcnic_get_regs_len,
1236 .get_regs = qlcnic_get_regs,
1237 .get_link = ethtool_op_get_link,
1238 .get_eeprom_len = qlcnic_get_eeprom_len,
1239 .get_eeprom = qlcnic_get_eeprom,
1240 .get_ringparam = qlcnic_get_ringparam,
1241 .set_ringparam = qlcnic_set_ringparam,
Sucheta Chakrabortyf94bc1e2011-04-28 11:48:18 +00001242 .get_channels = qlcnic_get_channels,
1243 .set_channels = qlcnic_set_channels,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001244 .get_pauseparam = qlcnic_get_pauseparam,
1245 .set_pauseparam = qlcnic_set_pauseparam,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001246 .get_wol = qlcnic_get_wol,
1247 .set_wol = qlcnic_set_wol,
1248 .self_test = qlcnic_diag_test,
1249 .get_strings = qlcnic_get_strings,
1250 .get_ethtool_stats = qlcnic_get_ethtool_stats,
1251 .get_sset_count = qlcnic_get_sset_count,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001252 .get_coalesce = qlcnic_get_intr_coalesce,
1253 .set_coalesce = qlcnic_set_intr_coalesce,
stephen hemminger94469f72011-04-06 11:47:23 +00001254 .set_phys_id = qlcnic_set_led,
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00001255 .set_msglevel = qlcnic_set_msglevel,
1256 .get_msglevel = qlcnic_get_msglevel,
Anirban Chakrabortyb3c68732011-05-12 12:48:34 +00001257 .get_dump_flag = qlcnic_get_dump_flag,
1258 .get_dump_data = qlcnic_get_dump_data,
1259 .set_dump = qlcnic_set_dump,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001260};