blob: d5c94a3364f7d565b78c88f455a210038bda335e [file] [log] [blame]
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001/*
2 * Copyright (C) 2009 - QLogic Corporation.
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 * MA 02111-1307, USA.
19 *
20 * The full GNU General Public License is included in this distribution
21 * in the file called "COPYING".
22 *
23 */
24
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000026#include <linux/vmalloc.h>
27#include <linux/interrupt.h>
28
29#include "qlcnic.h"
30
31#include <linux/dma-mapping.h>
32#include <linux/if_vlan.h>
33#include <net/ip.h>
34#include <linux/ipv6.h>
35#include <linux/inetdevice.h>
36#include <linux/sysfs.h>
Sucheta Chakraborty451724c2010-07-13 20:33:34 +000037#include <linux/aer.h>
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000038
Sritej Velaga7f9a0c32010-06-17 02:56:39 +000039MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000040MODULE_LICENSE("GPL");
41MODULE_VERSION(QLCNIC_LINUX_VERSIONID);
42MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME);
43
44char qlcnic_driver_name[] = "qlcnic";
Sritej Velaga7f9a0c32010-06-17 02:56:39 +000045static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
46 "Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000047
48static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
49
50/* Default to restricted 1G auto-neg mode */
51static int wol_port_mode = 5;
52
53static int use_msi = 1;
54module_param(use_msi, int, 0644);
55MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
56
57static int use_msi_x = 1;
58module_param(use_msi_x, int, 0644);
59MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
60
61static int auto_fw_reset = AUTO_FW_RESET_ENABLED;
62module_param(auto_fw_reset, int, 0644);
63MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
64
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +000065static int load_fw_file;
66module_param(load_fw_file, int, 0644);
67MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
68
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +000069static int qlcnic_config_npars;
70module_param(qlcnic_config_npars, int, 0644);
71MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
72
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000073static int __devinit qlcnic_probe(struct pci_dev *pdev,
74 const struct pci_device_id *ent);
75static void __devexit qlcnic_remove(struct pci_dev *pdev);
76static int qlcnic_open(struct net_device *netdev);
77static int qlcnic_close(struct net_device *netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000078static void qlcnic_tx_timeout(struct net_device *netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000079static void qlcnic_attach_work(struct work_struct *work);
80static void qlcnic_fwinit_work(struct work_struct *work);
81static void qlcnic_fw_poll_work(struct work_struct *work);
82static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
83 work_func_t func, int delay);
84static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
85static int qlcnic_poll(struct napi_struct *napi, int budget);
schacko8f891382010-06-17 02:56:40 +000086static int qlcnic_rx_poll(struct napi_struct *napi, int budget);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000087#ifdef CONFIG_NET_POLL_CONTROLLER
88static void qlcnic_poll_controller(struct net_device *netdev);
89#endif
90
91static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
92static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
93static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
94static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
95
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +000096static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000097static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
98static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
99
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000100static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000101static irqreturn_t qlcnic_intr(int irq, void *data);
102static irqreturn_t qlcnic_msi_intr(int irq, void *data);
103static irqreturn_t qlcnic_msix_intr(int irq, void *data);
104
105static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
106static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000107static int qlcnic_start_firmware(struct qlcnic_adapter *);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000108
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000109static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
110static void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *);
111static int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *);
112static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
113static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
114static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000115/* PCI Device ID Table */
116#define ENTRY(device) \
117 {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
118 .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
119
120#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020
121
Amit Kumar Salecha6a902882010-02-01 05:24:54 +0000122static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000123 ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
124 {0,}
125};
126
127MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl);
128
129
130void
131qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
132 struct qlcnic_host_tx_ring *tx_ring)
133{
134 writel(tx_ring->producer, tx_ring->crb_cmd_producer);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000135}
136
137static const u32 msi_tgt_status[8] = {
138 ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
139 ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
140 ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
141 ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
142};
143
144static const
145struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
146
147static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
148{
149 writel(0, sds_ring->crb_intr_mask);
150}
151
152static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
153{
154 struct qlcnic_adapter *adapter = sds_ring->adapter;
155
156 writel(0x1, sds_ring->crb_intr_mask);
157
158 if (!QLCNIC_IS_MSI_FAMILY(adapter))
159 writel(0xfbff, adapter->tgt_mask_reg);
160}
161
162static int
163qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
164{
165 int size = sizeof(struct qlcnic_host_sds_ring) * count;
166
167 recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL);
168
169 return (recv_ctx->sds_rings == NULL);
170}
171
172static void
173qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
174{
175 if (recv_ctx->sds_rings != NULL)
176 kfree(recv_ctx->sds_rings);
177
178 recv_ctx->sds_rings = NULL;
179}
180
181static int
182qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
183{
184 int ring;
185 struct qlcnic_host_sds_ring *sds_ring;
186 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
187
188 if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
189 return -ENOMEM;
190
191 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
192 sds_ring = &recv_ctx->sds_rings[ring];
schacko8f891382010-06-17 02:56:40 +0000193
194 if (ring == adapter->max_sds_rings - 1)
195 netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
196 QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
197 else
198 netif_napi_add(netdev, &sds_ring->napi,
199 qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000200 }
201
202 return 0;
203}
204
205static void
206qlcnic_napi_del(struct qlcnic_adapter *adapter)
207{
208 int ring;
209 struct qlcnic_host_sds_ring *sds_ring;
210 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
211
212 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
213 sds_ring = &recv_ctx->sds_rings[ring];
214 netif_napi_del(&sds_ring->napi);
215 }
216
217 qlcnic_free_sds_rings(&adapter->recv_ctx);
218}
219
220static void
221qlcnic_napi_enable(struct qlcnic_adapter *adapter)
222{
223 int ring;
224 struct qlcnic_host_sds_ring *sds_ring;
225 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
226
Amit Kumar Salecha780ab792010-04-22 02:51:41 +0000227 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
228 return;
229
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000230 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
231 sds_ring = &recv_ctx->sds_rings[ring];
232 napi_enable(&sds_ring->napi);
233 qlcnic_enable_int(sds_ring);
234 }
235}
236
237static void
238qlcnic_napi_disable(struct qlcnic_adapter *adapter)
239{
240 int ring;
241 struct qlcnic_host_sds_ring *sds_ring;
242 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
243
Amit Kumar Salecha780ab792010-04-22 02:51:41 +0000244 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
245 return;
246
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000247 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
248 sds_ring = &recv_ctx->sds_rings[ring];
249 qlcnic_disable_int(sds_ring);
250 napi_synchronize(&sds_ring->napi);
251 napi_disable(&sds_ring->napi);
252 }
253}
254
255static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
256{
257 memset(&adapter->stats, 0, sizeof(adapter->stats));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000258}
259
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000260static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter)
261{
262 u32 val, data;
263
264 val = adapter->ahw.board_type;
265 if ((val == QLCNIC_BRDTYPE_P3_HMEZ) ||
266 (val == QLCNIC_BRDTYPE_P3_XG_LOM)) {
267 if (port_mode == QLCNIC_PORT_MODE_802_3_AP) {
268 data = QLCNIC_PORT_MODE_802_3_AP;
269 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
270 } else if (port_mode == QLCNIC_PORT_MODE_XG) {
271 data = QLCNIC_PORT_MODE_XG;
272 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
273 } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_1G) {
274 data = QLCNIC_PORT_MODE_AUTO_NEG_1G;
275 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
276 } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_XG) {
277 data = QLCNIC_PORT_MODE_AUTO_NEG_XG;
278 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
279 } else {
280 data = QLCNIC_PORT_MODE_AUTO_NEG;
281 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
282 }
283
284 if ((wol_port_mode != QLCNIC_PORT_MODE_802_3_AP) &&
285 (wol_port_mode != QLCNIC_PORT_MODE_XG) &&
286 (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_1G) &&
287 (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_XG)) {
288 wol_port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
289 }
290 QLCWR32(adapter, QLCNIC_WOL_PORT_MODE, wol_port_mode);
291 }
292}
293
294static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
295{
296 u32 control;
297 int pos;
298
299 pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
300 if (pos) {
301 pci_read_config_dword(pdev, pos, &control);
302 if (enable)
303 control |= PCI_MSIX_FLAGS_ENABLE;
304 else
305 control = 0;
306 pci_write_config_dword(pdev, pos, control);
307 }
308}
309
310static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
311{
312 int i;
313
314 for (i = 0; i < count; i++)
315 adapter->msix_entries[i].entry = i;
316}
317
318static int
319qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
320{
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000321 u8 mac_addr[ETH_ALEN];
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000322 struct net_device *netdev = adapter->netdev;
323 struct pci_dev *pdev = adapter->pdev;
324
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000325 if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000326 return -EIO;
327
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000328 memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000329 memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
330 memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
331
332 /* set station address */
333
334 if (!is_valid_ether_addr(netdev->perm_addr))
335 dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
336 netdev->dev_addr);
337
338 return 0;
339}
340
341static int qlcnic_set_mac(struct net_device *netdev, void *p)
342{
343 struct qlcnic_adapter *adapter = netdev_priv(netdev);
344 struct sockaddr *addr = p;
345
346 if (!is_valid_ether_addr(addr->sa_data))
347 return -EINVAL;
348
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000349 if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000350 netif_device_detach(netdev);
351 qlcnic_napi_disable(adapter);
352 }
353
354 memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len);
355 memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
356 qlcnic_set_multi(adapter->netdev);
357
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000358 if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000359 netif_device_attach(netdev);
360 qlcnic_napi_enable(adapter);
361 }
362 return 0;
363}
364
365static const struct net_device_ops qlcnic_netdev_ops = {
366 .ndo_open = qlcnic_open,
367 .ndo_stop = qlcnic_close,
368 .ndo_start_xmit = qlcnic_xmit_frame,
369 .ndo_get_stats = qlcnic_get_stats,
370 .ndo_validate_addr = eth_validate_addr,
371 .ndo_set_multicast_list = qlcnic_set_multi,
372 .ndo_set_mac_address = qlcnic_set_mac,
373 .ndo_change_mtu = qlcnic_change_mtu,
374 .ndo_tx_timeout = qlcnic_tx_timeout,
375#ifdef CONFIG_NET_POLL_CONTROLLER
376 .ndo_poll_controller = qlcnic_poll_controller,
377#endif
378};
379
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000380static struct qlcnic_nic_template qlcnic_ops = {
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000381 .get_mac_addr = qlcnic_get_mac_address,
382 .config_bridged_mode = qlcnic_config_bridged_mode,
383 .config_led = qlcnic_config_led,
384 .set_ilb_mode = qlcnic_set_ilb_mode,
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000385 .clear_ilb_mode = qlcnic_clear_ilb_mode,
386 .start_firmware = qlcnic_start_firmware
387};
388
389static struct qlcnic_nic_template qlcnic_vf_ops = {
390 .get_mac_addr = qlcnic_get_mac_address,
391 .config_bridged_mode = qlcnicvf_config_bridged_mode,
392 .config_led = qlcnicvf_config_led,
393 .set_ilb_mode = qlcnicvf_set_ilb_mode,
394 .clear_ilb_mode = qlcnicvf_clear_ilb_mode,
395 .start_firmware = qlcnicvf_start_firmware
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000396};
397
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000398static void
399qlcnic_setup_intr(struct qlcnic_adapter *adapter)
400{
401 const struct qlcnic_legacy_intr_set *legacy_intrp;
402 struct pci_dev *pdev = adapter->pdev;
403 int err, num_msix;
404
405 if (adapter->rss_supported) {
406 num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
407 MSIX_ENTRIES_PER_ADAPTER : 2;
408 } else
409 num_msix = 1;
410
411 adapter->max_sds_rings = 1;
412
413 adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
414
415 legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
416
417 adapter->int_vec_bit = legacy_intrp->int_vec_bit;
418 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
419 legacy_intrp->tgt_status_reg);
420 adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
421 legacy_intrp->tgt_mask_reg);
422 adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
423
424 adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
425 ISR_INT_STATE_REG);
426
427 qlcnic_set_msix_bit(pdev, 0);
428
429 if (adapter->msix_supported) {
430
431 qlcnic_init_msix_entries(adapter, num_msix);
432 err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
433 if (err == 0) {
434 adapter->flags |= QLCNIC_MSIX_ENABLED;
435 qlcnic_set_msix_bit(pdev, 1);
436
437 if (adapter->rss_supported)
438 adapter->max_sds_rings = num_msix;
439
440 dev_info(&pdev->dev, "using msi-x interrupts\n");
441 return;
442 }
443
444 if (err > 0)
445 pci_disable_msix(pdev);
446
447 /* fall through for msi */
448 }
449
450 if (use_msi && !pci_enable_msi(pdev)) {
451 adapter->flags |= QLCNIC_MSI_ENABLED;
452 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
453 msi_tgt_status[adapter->ahw.pci_func]);
454 dev_info(&pdev->dev, "using msi interrupts\n");
455 adapter->msix_entries[0].vector = pdev->irq;
456 return;
457 }
458
459 dev_info(&pdev->dev, "using legacy interrupts\n");
460 adapter->msix_entries[0].vector = pdev->irq;
461}
462
463static void
464qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
465{
466 if (adapter->flags & QLCNIC_MSIX_ENABLED)
467 pci_disable_msix(adapter->pdev);
468 if (adapter->flags & QLCNIC_MSI_ENABLED)
469 pci_disable_msi(adapter->pdev);
470}
471
472static void
473qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
474{
475 if (adapter->ahw.pci_base0 != NULL)
476 iounmap(adapter->ahw.pci_base0);
477}
478
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000479static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000480qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
481{
482 struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
483 int i, ret = 0, err;
484 u8 pfn;
485
486 if (!adapter->npars)
487 adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
488 QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
489 if (!adapter->npars)
490 return -ENOMEM;
491
492 if (!adapter->eswitch)
493 adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
494 QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
495 if (!adapter->eswitch) {
496 err = -ENOMEM;
497 goto err_eswitch;
498 }
499
500 ret = qlcnic_get_pci_info(adapter, pci_info);
501 if (!ret) {
502 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
503 pfn = pci_info[i].id;
504 if (pfn > QLCNIC_MAX_PCI_FUNC)
505 return QL_STATUS_INVALID_PARAM;
506 adapter->npars[pfn].active = pci_info[i].active;
507 adapter->npars[pfn].type = pci_info[i].type;
508 adapter->npars[pfn].phy_port = pci_info[i].default_port;
509 adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
510 }
511
512 for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
513 adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
514
515 return ret;
516 }
517
518 kfree(adapter->eswitch);
519 adapter->eswitch = NULL;
520err_eswitch:
521 kfree(adapter->npars);
522
523 return ret;
524}
525
526static int
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000527qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
528{
529 u8 id;
530 u32 ref_count;
531 int i, ret = 1;
532 u32 data = QLCNIC_MGMT_FUNC;
533 void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
534
535 /* If other drivers are not in use set their privilege level */
536 ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
537 ret = qlcnic_api_lock(adapter);
538 if (ret)
539 goto err_lock;
540 if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
541 goto err_npar;
542
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000543 if (qlcnic_config_npars) {
544 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000545 id = i;
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000546 if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
547 id == adapter->ahw.pci_func)
548 continue;
549 data |= (qlcnic_config_npars &
550 QLC_DEV_SET_DRV(0xf, id));
551 }
552 } else {
553 data = readl(priv_op);
554 data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) |
555 (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
556 adapter->ahw.pci_func));
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000557 }
558 writel(data, priv_op);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000559err_npar:
560 qlcnic_api_unlock(adapter);
561err_lock:
562 return ret;
563}
564
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000565static u32
566qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
567{
568 void __iomem *msix_base_addr;
569 void __iomem *priv_op;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000570 struct qlcnic_info nic_info;
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000571 u32 func;
572 u32 msix_base;
573 u32 op_mode, priv_level;
574
575 /* Determine FW API version */
576 adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000577
578 /* Find PCI function number */
579 pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
580 msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
581 msix_base = readl(msix_base_addr);
582 func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
583 adapter->ahw.pci_func = func;
584
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000585 if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
586 adapter->capabilities = nic_info.capabilities;
587
588 if (adapter->capabilities & BIT_6)
589 adapter->flags |= QLCNIC_ESWITCH_ENABLED;
590 else
591 adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
592 }
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000593
594 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
595 adapter->nic_ops = &qlcnic_ops;
596 return adapter->fw_hal_version;
597 }
598
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000599 /* Determine function privilege level */
600 priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
601 op_mode = readl(priv_op);
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000602 if (op_mode == QLC_DEV_DRV_DEFAULT)
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000603 priv_level = QLCNIC_MGMT_FUNC;
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000604 else
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000605 priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
606
607 switch (priv_level) {
608 case QLCNIC_MGMT_FUNC:
609 adapter->op_mode = QLCNIC_MGMT_FUNC;
Anirban Chakraborty45918e22010-06-29 07:52:12 +0000610 adapter->nic_ops = &qlcnic_ops;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000611 qlcnic_init_pci_info(adapter);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000612 /* Set privilege level for other functions */
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000613 qlcnic_set_function_modes(adapter);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000614 dev_info(&adapter->pdev->dev,
615 "HAL Version: %d, Management function\n",
616 adapter->fw_hal_version);
617 break;
618 case QLCNIC_PRIV_FUNC:
619 adapter->op_mode = QLCNIC_PRIV_FUNC;
620 dev_info(&adapter->pdev->dev,
621 "HAL Version: %d, Privileged function\n",
622 adapter->fw_hal_version);
Anirban Chakraborty45918e22010-06-29 07:52:12 +0000623 adapter->nic_ops = &qlcnic_ops;
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000624 break;
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000625 case QLCNIC_NON_PRIV_FUNC:
626 adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
627 dev_info(&adapter->pdev->dev,
628 "HAL Version: %d Non Privileged function\n",
629 adapter->fw_hal_version);
630 adapter->nic_ops = &qlcnic_vf_ops;
631 break;
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000632 default:
633 dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
634 priv_level);
635 return 0;
636 }
637 return adapter->fw_hal_version;
638}
639
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000640static int
641qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
642{
643 void __iomem *mem_ptr0 = NULL;
644 resource_size_t mem_base;
645 unsigned long mem_len, pci_len0 = 0;
646
647 struct pci_dev *pdev = adapter->pdev;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000648
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000649 /* remap phys address */
650 mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
651 mem_len = pci_resource_len(pdev, 0);
652
653 if (mem_len == QLCNIC_PCI_2MB_SIZE) {
654
655 mem_ptr0 = pci_ioremap_bar(pdev, 0);
656 if (mem_ptr0 == NULL) {
657 dev_err(&pdev->dev, "failed to map PCI bar 0\n");
658 return -EIO;
659 }
660 pci_len0 = mem_len;
661 } else {
662 return -EIO;
663 }
664
665 dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
666
667 adapter->ahw.pci_base0 = mem_ptr0;
668 adapter->ahw.pci_len0 = pci_len0;
669
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000670 if (!qlcnic_get_driver_mode(adapter)) {
671 iounmap(adapter->ahw.pci_base0);
672 return -EIO;
673 }
674
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000675 adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000676 QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000677
678 return 0;
679}
680
681static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
682{
683 struct pci_dev *pdev = adapter->pdev;
684 int i, found = 0;
685
686 for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
687 if (qlcnic_boards[i].vendor == pdev->vendor &&
688 qlcnic_boards[i].device == pdev->device &&
689 qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
690 qlcnic_boards[i].sub_device == pdev->subsystem_device) {
Sucheta Chakraborty02f6e462010-05-17 01:22:09 +0000691 sprintf(name, "%pM: %s" ,
692 adapter->mac_addr,
693 qlcnic_boards[i].short_name);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000694 found = 1;
695 break;
696 }
697
698 }
699
700 if (!found)
Sritej Velaga7f9a0c32010-06-17 02:56:39 +0000701 sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000702}
703
704static void
705qlcnic_check_options(struct qlcnic_adapter *adapter)
706{
707 u32 fw_major, fw_minor, fw_build;
708 char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
709 char serial_num[32];
710 int i, offset, val;
711 int *ptr32;
712 struct pci_dev *pdev = adapter->pdev;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000713 struct qlcnic_info nic_info;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000714 adapter->driver_mismatch = 0;
715
716 ptr32 = (int *)&serial_num;
717 offset = QLCNIC_FW_SERIAL_NUM_OFFSET;
718 for (i = 0; i < 8; i++) {
719 if (qlcnic_rom_fast_read(adapter, offset, &val) == -1) {
720 dev_err(&pdev->dev, "error reading board info\n");
721 adapter->driver_mismatch = 1;
722 return;
723 }
724 ptr32[i] = cpu_to_le32(val);
725 offset += sizeof(u32);
726 }
727
728 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
729 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
730 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
731
732 adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
733
734 if (adapter->portnum == 0) {
735 get_brd_name(adapter, brd_name);
736
737 pr_info("%s: %s Board Chip rev 0x%x\n",
738 module_name(THIS_MODULE),
739 brd_name, adapter->ahw.revision_id);
740 }
741
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +0000742 dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
743 fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000744
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000745 adapter->flags &= ~QLCNIC_LRO_ENABLED;
746
747 if (adapter->ahw.port_type == QLCNIC_XGBE) {
748 adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
749 adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
750 } else if (adapter->ahw.port_type == QLCNIC_GBE) {
751 adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
752 adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
753 }
754
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000755 if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
756 adapter->physical_port = nic_info.phys_port;
757 adapter->switch_mode = nic_info.switch_mode;
758 adapter->max_tx_ques = nic_info.max_tx_ques;
759 adapter->max_rx_ques = nic_info.max_rx_ques;
760 adapter->capabilities = nic_info.capabilities;
761 adapter->max_mac_filters = nic_info.max_mac_filters;
762 adapter->max_mtu = nic_info.max_mtu;
763 }
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000764
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000765 adapter->msix_supported = !!use_msi_x;
766 adapter->rss_supported = !!use_msi_x;
767
768 adapter->num_txd = MAX_CMD_DESCRIPTORS;
769
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000770 adapter->max_rds_rings = 2;
771}
772
773static int
774qlcnic_start_firmware(struct qlcnic_adapter *adapter)
775{
776 int val, err, first_boot;
777
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +0000778 err = qlcnic_can_start_firmware(adapter);
779 if (err < 0)
780 return err;
781 else if (!err)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000782 goto wait_init;
783
784 first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc));
785 if (first_boot == 0x55555555)
786 /* This is the first boot after power up */
787 QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
788
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +0000789 if (load_fw_file)
790 qlcnic_request_firmware(adapter);
schacko8f891382010-06-17 02:56:40 +0000791 else {
792 if (qlcnic_check_flash_fw_ver(adapter))
793 goto err_out;
794
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +0000795 adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
schacko8f891382010-06-17 02:56:40 +0000796 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000797
798 err = qlcnic_need_fw_reset(adapter);
799 if (err < 0)
800 goto err_out;
801 if (err == 0)
802 goto wait_init;
803
804 if (first_boot != 0x55555555) {
805 QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
Amit Kumar Salecha900c6cf2010-06-22 03:18:59 +0000806 QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000807 qlcnic_pinit_from_rom(adapter);
808 msleep(1);
809 }
810
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000811 QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
812 QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
813
814 qlcnic_set_port_mode(adapter);
815
816 err = qlcnic_load_firmware(adapter);
817 if (err)
818 goto err_out;
819
820 qlcnic_release_firmware(adapter);
821
822 val = (_QLCNIC_LINUX_MAJOR << 16)
823 | ((_QLCNIC_LINUX_MINOR << 8))
824 | (_QLCNIC_LINUX_SUBVERSION);
825 QLCWR32(adapter, CRB_DRIVER_VERSION, val);
826
827wait_init:
828 /* Handshake with the card before we register the devices. */
Amit Kumar Salecha900c6cf2010-06-22 03:18:59 +0000829 err = qlcnic_init_firmware(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000830 if (err)
831 goto err_out;
832
833 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +0000834 qlcnic_idc_debug_info(adapter, 1);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000835
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000836 qlcnic_check_options(adapter);
837
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000838 if (adapter->flags & QLCNIC_ESWITCH_ENABLED &&
839 adapter->op_mode != QLCNIC_NON_PRIV_FUNC)
840 qlcnic_dev_set_npar_ready(adapter);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000841
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000842 adapter->need_fw_reset = 0;
843
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +0000844 qlcnic_release_firmware(adapter);
845 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000846
847err_out:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +0000848 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
849 dev_err(&adapter->pdev->dev, "Device state set to failed\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000850 qlcnic_release_firmware(adapter);
851 return err;
852}
853
854static int
855qlcnic_request_irq(struct qlcnic_adapter *adapter)
856{
857 irq_handler_t handler;
858 struct qlcnic_host_sds_ring *sds_ring;
859 int err, ring;
860
861 unsigned long flags = 0;
862 struct net_device *netdev = adapter->netdev;
863 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
864
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000865 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
866 handler = qlcnic_tmp_intr;
867 if (!QLCNIC_IS_MSI_FAMILY(adapter))
868 flags |= IRQF_SHARED;
869
870 } else {
871 if (adapter->flags & QLCNIC_MSIX_ENABLED)
872 handler = qlcnic_msix_intr;
873 else if (adapter->flags & QLCNIC_MSI_ENABLED)
874 handler = qlcnic_msi_intr;
875 else {
876 flags |= IRQF_SHARED;
877 handler = qlcnic_intr;
878 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000879 }
880 adapter->irq = netdev->irq;
881
882 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
883 sds_ring = &recv_ctx->sds_rings[ring];
884 sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
885 err = request_irq(sds_ring->irq, handler,
886 flags, sds_ring->name, sds_ring);
887 if (err)
888 return err;
889 }
890
891 return 0;
892}
893
894static void
895qlcnic_free_irq(struct qlcnic_adapter *adapter)
896{
897 int ring;
898 struct qlcnic_host_sds_ring *sds_ring;
899
900 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
901
902 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
903 sds_ring = &recv_ctx->sds_rings[ring];
904 free_irq(sds_ring->irq, sds_ring);
905 }
906}
907
908static void
909qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter)
910{
911 adapter->coal.flags = QLCNIC_INTR_DEFAULT;
912 adapter->coal.normal.data.rx_time_us =
913 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
914 adapter->coal.normal.data.rx_packets =
915 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
916 adapter->coal.normal.data.tx_time_us =
917 QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US;
918 adapter->coal.normal.data.tx_packets =
919 QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS;
920}
921
922static int
923__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
924{
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000925 int ring;
926 struct qlcnic_host_rds_ring *rds_ring;
927
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000928 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
929 return -EIO;
930
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000931 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
932 return 0;
933
934 if (qlcnic_fw_create_ctx(adapter))
935 return -EIO;
936
937 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
938 rds_ring = &adapter->recv_ctx.rds_rings[ring];
939 qlcnic_post_rx_buffers(adapter, ring, rds_ring);
940 }
941
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000942 qlcnic_set_multi(netdev);
943 qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
944
945 adapter->ahw.linkup = 0;
946
947 if (adapter->max_sds_rings > 1)
948 qlcnic_config_rss(adapter, 1);
949
950 qlcnic_config_intr_coalesce(adapter);
951
952 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
953 qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
954
955 qlcnic_napi_enable(adapter);
956
957 qlcnic_linkevent_request(adapter, 1);
958
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +0000959 adapter->reset_context = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000960 set_bit(__QLCNIC_DEV_UP, &adapter->state);
961 return 0;
962}
963
964/* Usage: During resume and firmware recovery module.*/
965
966static int
967qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
968{
969 int err = 0;
970
971 rtnl_lock();
972 if (netif_running(netdev))
973 err = __qlcnic_up(adapter, netdev);
974 rtnl_unlock();
975
976 return err;
977}
978
979static void
980__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
981{
982 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
983 return;
984
985 if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))
986 return;
987
988 smp_mb();
989 spin_lock(&adapter->tx_clean_lock);
990 netif_carrier_off(netdev);
991 netif_tx_disable(netdev);
992
993 qlcnic_free_mac_list(adapter);
994
995 qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
996
997 qlcnic_napi_disable(adapter);
998
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000999 qlcnic_fw_destroy_ctx(adapter);
1000
1001 qlcnic_reset_rx_buffers_list(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001002 qlcnic_release_tx_buffers(adapter);
1003 spin_unlock(&adapter->tx_clean_lock);
1004}
1005
1006/* Usage: During suspend and firmware recovery module */
1007
1008static void
1009qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
1010{
1011 rtnl_lock();
1012 if (netif_running(netdev))
1013 __qlcnic_down(adapter, netdev);
1014 rtnl_unlock();
1015
1016}
1017
1018static int
1019qlcnic_attach(struct qlcnic_adapter *adapter)
1020{
1021 struct net_device *netdev = adapter->netdev;
1022 struct pci_dev *pdev = adapter->pdev;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001023 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001024
1025 if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
1026 return 0;
1027
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001028 err = qlcnic_napi_add(adapter, netdev);
1029 if (err)
1030 return err;
1031
1032 err = qlcnic_alloc_sw_resources(adapter);
1033 if (err) {
1034 dev_err(&pdev->dev, "Error in setting sw resources\n");
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001035 goto err_out_napi_del;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001036 }
1037
1038 err = qlcnic_alloc_hw_resources(adapter);
1039 if (err) {
1040 dev_err(&pdev->dev, "Error in setting hw resources\n");
1041 goto err_out_free_sw;
1042 }
1043
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001044 err = qlcnic_request_irq(adapter);
1045 if (err) {
1046 dev_err(&pdev->dev, "failed to setup interrupt\n");
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001047 goto err_out_free_hw;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001048 }
1049
1050 qlcnic_init_coalesce_defaults(adapter);
1051
1052 qlcnic_create_sysfs_entries(adapter);
1053
1054 adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
1055 return 0;
1056
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001057err_out_free_hw:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001058 qlcnic_free_hw_resources(adapter);
1059err_out_free_sw:
1060 qlcnic_free_sw_resources(adapter);
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001061err_out_napi_del:
1062 qlcnic_napi_del(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001063 return err;
1064}
1065
1066static void
1067qlcnic_detach(struct qlcnic_adapter *adapter)
1068{
1069 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1070 return;
1071
1072 qlcnic_remove_sysfs_entries(adapter);
1073
1074 qlcnic_free_hw_resources(adapter);
1075 qlcnic_release_rx_buffers(adapter);
1076 qlcnic_free_irq(adapter);
1077 qlcnic_napi_del(adapter);
1078 qlcnic_free_sw_resources(adapter);
1079
1080 adapter->is_up = 0;
1081}
1082
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001083void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
1084{
1085 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1086 struct qlcnic_host_sds_ring *sds_ring;
1087 int ring;
1088
Sucheta Chakraborty78ad3892010-05-17 01:22:12 +00001089 clear_bit(__QLCNIC_DEV_UP, &adapter->state);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001090 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1091 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1092 sds_ring = &adapter->recv_ctx.sds_rings[ring];
1093 qlcnic_disable_int(sds_ring);
1094 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001095 }
1096
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001097 qlcnic_fw_destroy_ctx(adapter);
1098
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001099 qlcnic_detach(adapter);
1100
1101 adapter->diag_test = 0;
1102 adapter->max_sds_rings = max_sds_rings;
1103
1104 if (qlcnic_attach(adapter))
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001105 goto out;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001106
1107 if (netif_running(netdev))
1108 __qlcnic_up(adapter, netdev);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001109out:
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001110 netif_device_attach(netdev);
1111}
1112
1113int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
1114{
1115 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1116 struct qlcnic_host_sds_ring *sds_ring;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001117 struct qlcnic_host_rds_ring *rds_ring;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001118 int ring;
1119 int ret;
1120
1121 netif_device_detach(netdev);
1122
1123 if (netif_running(netdev))
1124 __qlcnic_down(adapter, netdev);
1125
1126 qlcnic_detach(adapter);
1127
1128 adapter->max_sds_rings = 1;
1129 adapter->diag_test = test;
1130
1131 ret = qlcnic_attach(adapter);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001132 if (ret) {
1133 netif_device_attach(netdev);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001134 return ret;
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001135 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001136
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001137 ret = qlcnic_fw_create_ctx(adapter);
1138 if (ret) {
1139 qlcnic_detach(adapter);
1140 return ret;
1141 }
1142
1143 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1144 rds_ring = &adapter->recv_ctx.rds_rings[ring];
1145 qlcnic_post_rx_buffers(adapter, ring, rds_ring);
1146 }
1147
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001148 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1149 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1150 sds_ring = &adapter->recv_ctx.sds_rings[ring];
1151 qlcnic_enable_int(sds_ring);
1152 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001153 }
Sucheta Chakraborty78ad3892010-05-17 01:22:12 +00001154 set_bit(__QLCNIC_DEV_UP, &adapter->state);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001155
1156 return 0;
1157}
1158
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00001159/* Reset context in hardware only */
1160static int
1161qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
1162{
1163 struct net_device *netdev = adapter->netdev;
1164
1165 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1166 return -EBUSY;
1167
1168 netif_device_detach(netdev);
1169
1170 qlcnic_down(adapter, netdev);
1171
1172 qlcnic_up(adapter, netdev);
1173
1174 netif_device_attach(netdev);
1175
1176 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1177 return 0;
1178}
1179
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001180int
1181qlcnic_reset_context(struct qlcnic_adapter *adapter)
1182{
1183 int err = 0;
1184 struct net_device *netdev = adapter->netdev;
1185
1186 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1187 return -EBUSY;
1188
1189 if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) {
1190
1191 netif_device_detach(netdev);
1192
1193 if (netif_running(netdev))
1194 __qlcnic_down(adapter, netdev);
1195
1196 qlcnic_detach(adapter);
1197
1198 if (netif_running(netdev)) {
1199 err = qlcnic_attach(adapter);
1200 if (!err)
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001201 __qlcnic_up(adapter, netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001202 }
1203
1204 netif_device_attach(netdev);
1205 }
1206
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001207 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1208 return err;
1209}
1210
1211static int
1212qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001213 struct net_device *netdev, u8 pci_using_dac)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001214{
1215 int err;
1216 struct pci_dev *pdev = adapter->pdev;
1217
1218 adapter->rx_csum = 1;
1219 adapter->mc_enabled = 0;
1220 adapter->max_mc_count = 38;
1221
1222 netdev->netdev_ops = &qlcnic_netdev_ops;
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00001223 netdev->watchdog_timeo = 5*HZ;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001224
1225 qlcnic_change_mtu(netdev, netdev->mtu);
1226
1227 SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
1228
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001229 netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +00001230 NETIF_F_IPV6_CSUM | NETIF_F_GRO);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001231 netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +00001232 NETIF_F_IPV6_CSUM);
1233
1234 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
1235 netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
1236 netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
1237 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001238
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001239 if (pci_using_dac) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001240 netdev->features |= NETIF_F_HIGHDMA;
1241 netdev->vlan_features |= NETIF_F_HIGHDMA;
1242 }
1243
1244 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
1245 netdev->features |= (NETIF_F_HW_VLAN_TX);
1246
1247 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
1248 netdev->features |= NETIF_F_LRO;
1249
1250 netdev->irq = adapter->msix_entries[0].vector;
1251
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001252 if (qlcnic_read_mac_addr(adapter))
1253 dev_warn(&pdev->dev, "failed to read mac addr\n");
1254
1255 netif_carrier_off(netdev);
1256 netif_stop_queue(netdev);
1257
1258 err = register_netdev(netdev);
1259 if (err) {
1260 dev_err(&pdev->dev, "failed to register net device\n");
1261 return err;
1262 }
1263
1264 return 0;
1265}
1266
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001267static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
1268{
1269 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
1270 !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
1271 *pci_using_dac = 1;
1272 else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) &&
1273 !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
1274 *pci_using_dac = 0;
1275 else {
1276 dev_err(&pdev->dev, "Unable to set DMA mask, aborting\n");
1277 return -EIO;
1278 }
1279
1280 return 0;
1281}
1282
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001283static int __devinit
1284qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1285{
1286 struct net_device *netdev = NULL;
1287 struct qlcnic_adapter *adapter = NULL;
1288 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001289 uint8_t revision_id;
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001290 uint8_t pci_using_dac;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001291
1292 err = pci_enable_device(pdev);
1293 if (err)
1294 return err;
1295
1296 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
1297 err = -ENODEV;
1298 goto err_out_disable_pdev;
1299 }
1300
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001301 err = qlcnic_set_dma_mask(pdev, &pci_using_dac);
1302 if (err)
1303 goto err_out_disable_pdev;
1304
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001305 err = pci_request_regions(pdev, qlcnic_driver_name);
1306 if (err)
1307 goto err_out_disable_pdev;
1308
1309 pci_set_master(pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00001310 pci_enable_pcie_error_reporting(pdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001311
1312 netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
1313 if (!netdev) {
1314 dev_err(&pdev->dev, "failed to allocate net_device\n");
1315 err = -ENOMEM;
1316 goto err_out_free_res;
1317 }
1318
1319 SET_NETDEV_DEV(netdev, &pdev->dev);
1320
1321 adapter = netdev_priv(netdev);
1322 adapter->netdev = netdev;
1323 adapter->pdev = pdev;
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00001324 adapter->dev_rst_time = jiffies;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001325
1326 revision_id = pdev->revision;
1327 adapter->ahw.revision_id = revision_id;
1328
1329 rwlock_init(&adapter->ahw.crb_lock);
1330 mutex_init(&adapter->ahw.mem_lock);
1331
1332 spin_lock_init(&adapter->tx_clean_lock);
1333 INIT_LIST_HEAD(&adapter->mac_list);
1334
1335 err = qlcnic_setup_pci_map(adapter);
1336 if (err)
1337 goto err_out_free_netdev;
1338
1339 /* This will be reset for mezz cards */
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001340 adapter->portnum = adapter->ahw.pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001341
1342 err = qlcnic_get_board_info(adapter);
1343 if (err) {
1344 dev_err(&pdev->dev, "Error getting board config info.\n");
1345 goto err_out_iounmap;
1346 }
1347
Sucheta Chakraborty02f6e462010-05-17 01:22:09 +00001348 if (qlcnic_read_mac_addr(adapter))
1349 dev_warn(&pdev->dev, "failed to read mac addr\n");
1350
Sucheta Chakrabortyb3a24642010-05-13 03:07:48 +00001351 if (qlcnic_setup_idc_param(adapter))
1352 goto err_out_iounmap;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001353
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00001354 err = adapter->nic_ops->start_firmware(adapter);
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001355 if (err) {
1356 dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001357 goto err_out_decr_ref;
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001358 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001359
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001360 qlcnic_clear_stats(adapter);
1361
1362 qlcnic_setup_intr(adapter);
1363
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001364 err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001365 if (err)
1366 goto err_out_disable_msi;
1367
1368 pci_set_drvdata(pdev, adapter);
1369
1370 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
1371
1372 switch (adapter->ahw.port_type) {
1373 case QLCNIC_GBE:
1374 dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
1375 adapter->netdev->name);
1376 break;
1377 case QLCNIC_XGBE:
1378 dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
1379 adapter->netdev->name);
1380 break;
1381 }
1382
1383 qlcnic_create_diag_entries(adapter);
1384
1385 return 0;
1386
1387err_out_disable_msi:
1388 qlcnic_teardown_intr(adapter);
1389
1390err_out_decr_ref:
1391 qlcnic_clr_all_drv_state(adapter);
1392
1393err_out_iounmap:
1394 qlcnic_cleanup_pci_map(adapter);
1395
1396err_out_free_netdev:
1397 free_netdev(netdev);
1398
1399err_out_free_res:
1400 pci_release_regions(pdev);
1401
1402err_out_disable_pdev:
1403 pci_set_drvdata(pdev, NULL);
1404 pci_disable_device(pdev);
1405 return err;
1406}
1407
1408static void __devexit qlcnic_remove(struct pci_dev *pdev)
1409{
1410 struct qlcnic_adapter *adapter;
1411 struct net_device *netdev;
1412
1413 adapter = pci_get_drvdata(pdev);
1414 if (adapter == NULL)
1415 return;
1416
1417 netdev = adapter->netdev;
1418
1419 qlcnic_cancel_fw_work(adapter);
1420
1421 unregister_netdev(netdev);
1422
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001423 qlcnic_detach(adapter);
1424
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001425 if (adapter->npars != NULL)
1426 kfree(adapter->npars);
1427 if (adapter->eswitch != NULL)
1428 kfree(adapter->eswitch);
1429
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001430 qlcnic_clr_all_drv_state(adapter);
1431
1432 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1433
1434 qlcnic_teardown_intr(adapter);
1435
1436 qlcnic_remove_diag_entries(adapter);
1437
1438 qlcnic_cleanup_pci_map(adapter);
1439
1440 qlcnic_release_firmware(adapter);
1441
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00001442 pci_disable_pcie_error_reporting(pdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001443 pci_release_regions(pdev);
1444 pci_disable_device(pdev);
1445 pci_set_drvdata(pdev, NULL);
1446
1447 free_netdev(netdev);
1448}
1449static int __qlcnic_shutdown(struct pci_dev *pdev)
1450{
1451 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
1452 struct net_device *netdev = adapter->netdev;
1453 int retval;
1454
1455 netif_device_detach(netdev);
1456
1457 qlcnic_cancel_fw_work(adapter);
1458
1459 if (netif_running(netdev))
1460 qlcnic_down(adapter, netdev);
1461
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001462 qlcnic_clr_all_drv_state(adapter);
1463
1464 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1465
1466 retval = pci_save_state(pdev);
1467 if (retval)
1468 return retval;
1469
1470 if (qlcnic_wol_supported(adapter)) {
1471 pci_enable_wake(pdev, PCI_D3cold, 1);
1472 pci_enable_wake(pdev, PCI_D3hot, 1);
1473 }
1474
1475 return 0;
1476}
1477
1478static void qlcnic_shutdown(struct pci_dev *pdev)
1479{
1480 if (__qlcnic_shutdown(pdev))
1481 return;
1482
1483 pci_disable_device(pdev);
1484}
1485
1486#ifdef CONFIG_PM
1487static int
1488qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
1489{
1490 int retval;
1491
1492 retval = __qlcnic_shutdown(pdev);
1493 if (retval)
1494 return retval;
1495
1496 pci_set_power_state(pdev, pci_choose_state(pdev, state));
1497 return 0;
1498}
1499
1500static int
1501qlcnic_resume(struct pci_dev *pdev)
1502{
1503 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
1504 struct net_device *netdev = adapter->netdev;
1505 int err;
1506
1507 err = pci_enable_device(pdev);
1508 if (err)
1509 return err;
1510
1511 pci_set_power_state(pdev, PCI_D0);
1512 pci_set_master(pdev);
1513 pci_restore_state(pdev);
1514
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00001515 err = adapter->nic_ops->start_firmware(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001516 if (err) {
1517 dev_err(&pdev->dev, "failed to start firmware\n");
1518 return err;
1519 }
1520
1521 if (netif_running(netdev)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001522 err = qlcnic_up(adapter, netdev);
1523 if (err)
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00001524 goto done;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001525
1526 qlcnic_config_indev_addr(netdev, NETDEV_UP);
1527 }
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00001528done:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001529 netif_device_attach(netdev);
1530 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
1531 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001532}
1533#endif
1534
1535static int qlcnic_open(struct net_device *netdev)
1536{
1537 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1538 int err;
1539
1540 if (adapter->driver_mismatch)
1541 return -EIO;
1542
1543 err = qlcnic_attach(adapter);
1544 if (err)
1545 return err;
1546
1547 err = __qlcnic_up(adapter, netdev);
1548 if (err)
1549 goto err_out;
1550
1551 netif_start_queue(netdev);
1552
1553 return 0;
1554
1555err_out:
1556 qlcnic_detach(adapter);
1557 return err;
1558}
1559
1560/*
1561 * qlcnic_close - Disables a network interface entry point
1562 */
1563static int qlcnic_close(struct net_device *netdev)
1564{
1565 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1566
1567 __qlcnic_down(adapter, netdev);
1568 return 0;
1569}
1570
1571static void
1572qlcnic_tso_check(struct net_device *netdev,
1573 struct qlcnic_host_tx_ring *tx_ring,
1574 struct cmd_desc_type0 *first_desc,
1575 struct sk_buff *skb)
1576{
1577 u8 opcode = TX_ETHER_PKT;
1578 __be16 protocol = skb->protocol;
1579 u16 flags = 0, vid = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001580 int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
1581 struct cmd_desc_type0 *hwdesc;
1582 struct vlan_ethhdr *vh;
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00001583 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001584 u32 producer = tx_ring->producer;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001585
1586 if (protocol == cpu_to_be16(ETH_P_8021Q)) {
1587
1588 vh = (struct vlan_ethhdr *)skb->data;
1589 protocol = vh->h_vlan_encapsulated_proto;
1590 flags = FLAGS_VLAN_TAGGED;
1591
1592 } else if (vlan_tx_tag_present(skb)) {
1593
1594 flags = FLAGS_VLAN_OOB;
1595 vid = vlan_tx_tag_get(skb);
1596 qlcnic_set_tx_vlan_tci(first_desc, vid);
1597 vlan_oob = 1;
1598 }
1599
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001600 if (*(skb->data) & BIT_0) {
1601 flags |= BIT_0;
1602 memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
1603 }
1604
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001605 if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
1606 skb_shinfo(skb)->gso_size > 0) {
1607
1608 hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1609
1610 first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
1611 first_desc->total_hdr_length = hdr_len;
1612 if (vlan_oob) {
1613 first_desc->total_hdr_length += VLAN_HLEN;
1614 first_desc->tcp_hdr_offset = VLAN_HLEN;
1615 first_desc->ip_hdr_offset = VLAN_HLEN;
1616 /* Only in case of TSO on vlan device */
1617 flags |= FLAGS_VLAN_TAGGED;
1618 }
1619
1620 opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
1621 TX_TCP_LSO6 : TX_TCP_LSO;
1622 tso = 1;
1623
1624 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
1625 u8 l4proto;
1626
1627 if (protocol == cpu_to_be16(ETH_P_IP)) {
1628 l4proto = ip_hdr(skb)->protocol;
1629
1630 if (l4proto == IPPROTO_TCP)
1631 opcode = TX_TCP_PKT;
1632 else if (l4proto == IPPROTO_UDP)
1633 opcode = TX_UDP_PKT;
1634 } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
1635 l4proto = ipv6_hdr(skb)->nexthdr;
1636
1637 if (l4proto == IPPROTO_TCP)
1638 opcode = TX_TCPV6_PKT;
1639 else if (l4proto == IPPROTO_UDP)
1640 opcode = TX_UDPV6_PKT;
1641 }
1642 }
1643
1644 first_desc->tcp_hdr_offset += skb_transport_offset(skb);
1645 first_desc->ip_hdr_offset += skb_network_offset(skb);
1646 qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
1647
1648 if (!tso)
1649 return;
1650
1651 /* For LSO, we need to copy the MAC/IP/TCP headers into
1652 * the descriptor ring
1653 */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001654 copied = 0;
1655 offset = 2;
1656
1657 if (vlan_oob) {
1658 /* Create a TSO vlan header template for firmware */
1659
1660 hwdesc = &tx_ring->desc_head[producer];
1661 tx_ring->cmd_buf_arr[producer].skb = NULL;
1662
1663 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
1664 hdr_len + VLAN_HLEN);
1665
1666 vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
1667 skb_copy_from_linear_data(skb, vh, 12);
1668 vh->h_vlan_proto = htons(ETH_P_8021Q);
1669 vh->h_vlan_TCI = htons(vid);
1670 skb_copy_from_linear_data_offset(skb, 12,
1671 (char *)vh + 16, copy_len - 16);
1672
1673 copied = copy_len - VLAN_HLEN;
1674 offset = 0;
1675
1676 producer = get_next_index(producer, tx_ring->num_desc);
1677 }
1678
1679 while (copied < hdr_len) {
1680
1681 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
1682 (hdr_len - copied));
1683
1684 hwdesc = &tx_ring->desc_head[producer];
1685 tx_ring->cmd_buf_arr[producer].skb = NULL;
1686
1687 skb_copy_from_linear_data_offset(skb, copied,
1688 (char *)hwdesc + offset, copy_len);
1689
1690 copied += copy_len;
1691 offset = 0;
1692
1693 producer = get_next_index(producer, tx_ring->num_desc);
1694 }
1695
1696 tx_ring->producer = producer;
1697 barrier();
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00001698 adapter->stats.lso_frames++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001699}
1700
1701static int
1702qlcnic_map_tx_skb(struct pci_dev *pdev,
1703 struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
1704{
1705 struct qlcnic_skb_frag *nf;
1706 struct skb_frag_struct *frag;
1707 int i, nr_frags;
1708 dma_addr_t map;
1709
1710 nr_frags = skb_shinfo(skb)->nr_frags;
1711 nf = &pbuf->frag_array[0];
1712
1713 map = pci_map_single(pdev, skb->data,
1714 skb_headlen(skb), PCI_DMA_TODEVICE);
1715 if (pci_dma_mapping_error(pdev, map))
1716 goto out_err;
1717
1718 nf->dma = map;
1719 nf->length = skb_headlen(skb);
1720
1721 for (i = 0; i < nr_frags; i++) {
1722 frag = &skb_shinfo(skb)->frags[i];
1723 nf = &pbuf->frag_array[i+1];
1724
1725 map = pci_map_page(pdev, frag->page, frag->page_offset,
1726 frag->size, PCI_DMA_TODEVICE);
1727 if (pci_dma_mapping_error(pdev, map))
1728 goto unwind;
1729
1730 nf->dma = map;
1731 nf->length = frag->size;
1732 }
1733
1734 return 0;
1735
1736unwind:
1737 while (--i >= 0) {
1738 nf = &pbuf->frag_array[i+1];
1739 pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
1740 }
1741
1742 nf = &pbuf->frag_array[0];
1743 pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
1744
1745out_err:
1746 return -ENOMEM;
1747}
1748
1749static inline void
1750qlcnic_clear_cmddesc(u64 *desc)
1751{
1752 desc[0] = 0ULL;
1753 desc[2] = 0ULL;
1754}
1755
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001756netdev_tx_t
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001757qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
1758{
1759 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1760 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
1761 struct qlcnic_cmd_buffer *pbuf;
1762 struct qlcnic_skb_frag *buffrag;
1763 struct cmd_desc_type0 *hwdesc, *first_desc;
1764 struct pci_dev *pdev;
1765 int i, k;
1766
1767 u32 producer;
1768 int frag_count, no_of_desc;
1769 u32 num_txd = tx_ring->num_desc;
1770
Amit Kumar Salecha780ab792010-04-22 02:51:41 +00001771 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1772 netif_stop_queue(netdev);
1773 return NETDEV_TX_BUSY;
1774 }
1775
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001776 frag_count = skb_shinfo(skb)->nr_frags + 1;
1777
1778 /* 4 fragments per cmd des */
1779 no_of_desc = (frag_count + 3) >> 2;
1780
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00001781 if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001782 netif_stop_queue(netdev);
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00001783 smp_mb();
1784 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
1785 netif_start_queue(netdev);
1786 else {
1787 adapter->stats.xmit_off++;
1788 return NETDEV_TX_BUSY;
1789 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001790 }
1791
1792 producer = tx_ring->producer;
1793 pbuf = &tx_ring->cmd_buf_arr[producer];
1794
1795 pdev = adapter->pdev;
1796
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00001797 if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
1798 adapter->stats.tx_dma_map_error++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001799 goto drop_packet;
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00001800 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001801
1802 pbuf->skb = skb;
1803 pbuf->frag_count = frag_count;
1804
1805 first_desc = hwdesc = &tx_ring->desc_head[producer];
1806 qlcnic_clear_cmddesc((u64 *)hwdesc);
1807
1808 qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
1809 qlcnic_set_tx_port(first_desc, adapter->portnum);
1810
1811 for (i = 0; i < frag_count; i++) {
1812
1813 k = i % 4;
1814
1815 if ((k == 0) && (i > 0)) {
1816 /* move to next desc.*/
1817 producer = get_next_index(producer, num_txd);
1818 hwdesc = &tx_ring->desc_head[producer];
1819 qlcnic_clear_cmddesc((u64 *)hwdesc);
1820 tx_ring->cmd_buf_arr[producer].skb = NULL;
1821 }
1822
1823 buffrag = &pbuf->frag_array[i];
1824
1825 hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
1826 switch (k) {
1827 case 0:
1828 hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
1829 break;
1830 case 1:
1831 hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
1832 break;
1833 case 2:
1834 hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
1835 break;
1836 case 3:
1837 hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
1838 break;
1839 }
1840 }
1841
1842 tx_ring->producer = get_next_index(producer, num_txd);
1843
1844 qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
1845
1846 qlcnic_update_cmd_producer(adapter, tx_ring);
1847
1848 adapter->stats.txbytes += skb->len;
1849 adapter->stats.xmitcalled++;
1850
1851 return NETDEV_TX_OK;
1852
1853drop_packet:
1854 adapter->stats.txdropped++;
1855 dev_kfree_skb_any(skb);
1856 return NETDEV_TX_OK;
1857}
1858
1859static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
1860{
1861 struct net_device *netdev = adapter->netdev;
1862 u32 temp, temp_state, temp_val;
1863 int rv = 0;
1864
1865 temp = QLCRD32(adapter, CRB_TEMP_STATE);
1866
1867 temp_state = qlcnic_get_temp_state(temp);
1868 temp_val = qlcnic_get_temp_val(temp);
1869
1870 if (temp_state == QLCNIC_TEMP_PANIC) {
1871 dev_err(&netdev->dev,
1872 "Device temperature %d degrees C exceeds"
1873 " maximum allowed. Hardware has been shut down.\n",
1874 temp_val);
1875 rv = 1;
1876 } else if (temp_state == QLCNIC_TEMP_WARN) {
1877 if (adapter->temp == QLCNIC_TEMP_NORMAL) {
1878 dev_err(&netdev->dev,
1879 "Device temperature %d degrees C "
1880 "exceeds operating range."
1881 " Immediate action needed.\n",
1882 temp_val);
1883 }
1884 } else {
1885 if (adapter->temp == QLCNIC_TEMP_WARN) {
1886 dev_info(&netdev->dev,
1887 "Device temperature is now %d degrees C"
1888 " in normal range.\n", temp_val);
1889 }
1890 }
1891 adapter->temp = temp_state;
1892 return rv;
1893}
1894
1895void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
1896{
1897 struct net_device *netdev = adapter->netdev;
1898
1899 if (adapter->ahw.linkup && !linkup) {
1900 dev_info(&netdev->dev, "NIC Link is down\n");
1901 adapter->ahw.linkup = 0;
1902 if (netif_running(netdev)) {
1903 netif_carrier_off(netdev);
1904 netif_stop_queue(netdev);
1905 }
1906 } else if (!adapter->ahw.linkup && linkup) {
1907 dev_info(&netdev->dev, "NIC Link is up\n");
1908 adapter->ahw.linkup = 1;
1909 if (netif_running(netdev)) {
1910 netif_carrier_on(netdev);
1911 netif_wake_queue(netdev);
1912 }
1913 }
1914}
1915
1916static void qlcnic_tx_timeout(struct net_device *netdev)
1917{
1918 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1919
1920 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
1921 return;
1922
1923 dev_err(&netdev->dev, "transmit timeout, resetting.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001924
1925 if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00001926 adapter->need_fw_reset = 1;
1927 else
1928 adapter->reset_context = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001929}
1930
1931static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
1932{
1933 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1934 struct net_device_stats *stats = &netdev->stats;
1935
1936 memset(stats, 0, sizeof(*stats));
1937
1938 stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
1939 stats->tx_packets = adapter->stats.xmitfinished;
Sucheta Chakraborty7e382592010-05-17 01:22:10 +00001940 stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001941 stats->tx_bytes = adapter->stats.txbytes;
1942 stats->rx_dropped = adapter->stats.rxdropped;
1943 stats->tx_dropped = adapter->stats.txdropped;
1944
1945 return stats;
1946}
1947
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001948static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001949{
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001950 u32 status;
1951
1952 status = readl(adapter->isr_int_vec);
1953
1954 if (!(status & adapter->int_vec_bit))
1955 return IRQ_NONE;
1956
1957 /* check interrupt state machine, to be sure */
1958 status = readl(adapter->crb_int_state_reg);
1959 if (!ISR_LEGACY_INT_TRIGGERED(status))
1960 return IRQ_NONE;
1961
1962 writel(0xffffffff, adapter->tgt_status_reg);
1963 /* read twice to ensure write is flushed */
1964 readl(adapter->isr_int_vec);
1965 readl(adapter->isr_int_vec);
1966
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001967 return IRQ_HANDLED;
1968}
1969
1970static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
1971{
1972 struct qlcnic_host_sds_ring *sds_ring = data;
1973 struct qlcnic_adapter *adapter = sds_ring->adapter;
1974
1975 if (adapter->flags & QLCNIC_MSIX_ENABLED)
1976 goto done;
1977 else if (adapter->flags & QLCNIC_MSI_ENABLED) {
1978 writel(0xffffffff, adapter->tgt_status_reg);
1979 goto done;
1980 }
1981
1982 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
1983 return IRQ_NONE;
1984
1985done:
1986 adapter->diag_cnt++;
1987 qlcnic_enable_int(sds_ring);
1988 return IRQ_HANDLED;
1989}
1990
1991static irqreturn_t qlcnic_intr(int irq, void *data)
1992{
1993 struct qlcnic_host_sds_ring *sds_ring = data;
1994 struct qlcnic_adapter *adapter = sds_ring->adapter;
1995
1996 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
1997 return IRQ_NONE;
1998
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001999 napi_schedule(&sds_ring->napi);
2000
2001 return IRQ_HANDLED;
2002}
2003
2004static irqreturn_t qlcnic_msi_intr(int irq, void *data)
2005{
2006 struct qlcnic_host_sds_ring *sds_ring = data;
2007 struct qlcnic_adapter *adapter = sds_ring->adapter;
2008
2009 /* clear interrupt */
2010 writel(0xffffffff, adapter->tgt_status_reg);
2011
2012 napi_schedule(&sds_ring->napi);
2013 return IRQ_HANDLED;
2014}
2015
2016static irqreturn_t qlcnic_msix_intr(int irq, void *data)
2017{
2018 struct qlcnic_host_sds_ring *sds_ring = data;
2019
2020 napi_schedule(&sds_ring->napi);
2021 return IRQ_HANDLED;
2022}
2023
2024static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
2025{
2026 u32 sw_consumer, hw_consumer;
2027 int count = 0, i;
2028 struct qlcnic_cmd_buffer *buffer;
2029 struct pci_dev *pdev = adapter->pdev;
2030 struct net_device *netdev = adapter->netdev;
2031 struct qlcnic_skb_frag *frag;
2032 int done;
2033 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
2034
2035 if (!spin_trylock(&adapter->tx_clean_lock))
2036 return 1;
2037
2038 sw_consumer = tx_ring->sw_consumer;
2039 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2040
2041 while (sw_consumer != hw_consumer) {
2042 buffer = &tx_ring->cmd_buf_arr[sw_consumer];
2043 if (buffer->skb) {
2044 frag = &buffer->frag_array[0];
2045 pci_unmap_single(pdev, frag->dma, frag->length,
2046 PCI_DMA_TODEVICE);
2047 frag->dma = 0ULL;
2048 for (i = 1; i < buffer->frag_count; i++) {
2049 frag++;
2050 pci_unmap_page(pdev, frag->dma, frag->length,
2051 PCI_DMA_TODEVICE);
2052 frag->dma = 0ULL;
2053 }
2054
2055 adapter->stats.xmitfinished++;
2056 dev_kfree_skb_any(buffer->skb);
2057 buffer->skb = NULL;
2058 }
2059
2060 sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
2061 if (++count >= MAX_STATUS_HANDLE)
2062 break;
2063 }
2064
2065 if (count && netif_running(netdev)) {
2066 tx_ring->sw_consumer = sw_consumer;
2067
2068 smp_mb();
2069
2070 if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002071 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
2072 netif_wake_queue(netdev);
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00002073 adapter->stats.xmit_on++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002074 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002075 }
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002076 adapter->tx_timeo_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002077 }
2078 /*
2079 * If everything is freed up to consumer then check if the ring is full
2080 * If the ring is full then check if more needs to be freed and
2081 * schedule the call back again.
2082 *
2083 * This happens when there are 2 CPUs. One could be freeing and the
2084 * other filling it. If the ring is full when we get out of here and
2085 * the card has already interrupted the host then the host can miss the
2086 * interrupt.
2087 *
2088 * There is still a possible race condition and the host could miss an
2089 * interrupt. The card has to take care of this.
2090 */
2091 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2092 done = (sw_consumer == hw_consumer);
2093 spin_unlock(&adapter->tx_clean_lock);
2094
2095 return done;
2096}
2097
2098static int qlcnic_poll(struct napi_struct *napi, int budget)
2099{
2100 struct qlcnic_host_sds_ring *sds_ring =
2101 container_of(napi, struct qlcnic_host_sds_ring, napi);
2102
2103 struct qlcnic_adapter *adapter = sds_ring->adapter;
2104
2105 int tx_complete;
2106 int work_done;
2107
2108 tx_complete = qlcnic_process_cmd_ring(adapter);
2109
2110 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2111
2112 if ((work_done < budget) && tx_complete) {
2113 napi_complete(&sds_ring->napi);
2114 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2115 qlcnic_enable_int(sds_ring);
2116 }
2117
2118 return work_done;
2119}
2120
schacko8f891382010-06-17 02:56:40 +00002121static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
2122{
2123 struct qlcnic_host_sds_ring *sds_ring =
2124 container_of(napi, struct qlcnic_host_sds_ring, napi);
2125
2126 struct qlcnic_adapter *adapter = sds_ring->adapter;
2127 int work_done;
2128
2129 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2130
2131 if (work_done < budget) {
2132 napi_complete(&sds_ring->napi);
2133 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2134 qlcnic_enable_int(sds_ring);
2135 }
2136
2137 return work_done;
2138}
2139
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002140#ifdef CONFIG_NET_POLL_CONTROLLER
2141static void qlcnic_poll_controller(struct net_device *netdev)
2142{
2143 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2144 disable_irq(adapter->irq);
2145 qlcnic_intr(adapter->irq, adapter);
2146 enable_irq(adapter->irq);
2147}
2148#endif
2149
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002150static void
2151qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
2152{
2153 u32 val;
2154
2155 val = adapter->portnum & 0xf;
2156 val |= encoding << 7;
2157 val |= (jiffies - adapter->dev_rst_time) << 8;
2158
2159 QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
2160 adapter->dev_rst_time = jiffies;
2161}
2162
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002163static int
2164qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002165{
2166 u32 val;
2167
2168 WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
2169 state != QLCNIC_DEV_NEED_QUISCENT);
2170
2171 if (qlcnic_api_lock(adapter))
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002172 return -EIO;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002173
2174 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
2175
2176 if (state == QLCNIC_DEV_NEED_RESET)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002177 QLC_DEV_SET_RST_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002178 else if (state == QLCNIC_DEV_NEED_QUISCENT)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002179 QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002180
2181 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2182
2183 qlcnic_api_unlock(adapter);
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002184
2185 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002186}
2187
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002188static int
2189qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
2190{
2191 u32 val;
2192
2193 if (qlcnic_api_lock(adapter))
2194 return -EBUSY;
2195
2196 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002197 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002198 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2199
2200 qlcnic_api_unlock(adapter);
2201
2202 return 0;
2203}
2204
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002205static void
2206qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
2207{
2208 u32 val;
2209
2210 if (qlcnic_api_lock(adapter))
2211 goto err;
2212
2213 val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002214 QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002215 QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
2216
2217 if (!(val & 0x11111111))
2218 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
2219
2220 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002221 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002222 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2223
2224 qlcnic_api_unlock(adapter);
2225err:
2226 adapter->fw_fail_cnt = 0;
2227 clear_bit(__QLCNIC_START_FW, &adapter->state);
2228 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2229}
2230
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002231/* Grab api lock, before checking state */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002232static int
2233qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
2234{
2235 int act, state;
2236
2237 state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
2238 act = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
2239
2240 if (((state & 0x11111111) == (act & 0x11111111)) ||
2241 ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
2242 return 0;
2243 else
2244 return 1;
2245}
2246
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002247static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
2248{
2249 u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
2250
2251 if (val != QLCNIC_DRV_IDC_VER) {
2252 dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
2253 " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
2254 }
2255
2256 return 0;
2257}
2258
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002259static int
2260qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
2261{
2262 u32 val, prev_state;
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002263 u8 dev_init_timeo = adapter->dev_init_timeo;
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002264 u8 portnum = adapter->portnum;
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002265 u8 ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002266
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002267 if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
2268 return 1;
2269
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002270 if (qlcnic_api_lock(adapter))
2271 return -1;
2272
2273 val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002274 if (!(val & (1 << (portnum * 4)))) {
2275 QLC_DEV_SET_REF_CNT(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002276 QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002277 }
2278
2279 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002280 QLCDB(adapter, HW, "Device state = %u\n", prev_state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002281
2282 switch (prev_state) {
2283 case QLCNIC_DEV_COLD:
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002284 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002285 QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002286 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002287 qlcnic_api_unlock(adapter);
2288 return 1;
2289
2290 case QLCNIC_DEV_READY:
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002291 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002292 qlcnic_api_unlock(adapter);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002293 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002294
2295 case QLCNIC_DEV_NEED_RESET:
2296 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002297 QLC_DEV_SET_RST_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002298 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2299 break;
2300
2301 case QLCNIC_DEV_NEED_QUISCENT:
2302 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002303 QLC_DEV_SET_QSCNT_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002304 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2305 break;
2306
2307 case QLCNIC_DEV_FAILED:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00002308 dev_err(&adapter->pdev->dev, "Device in failed state.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002309 qlcnic_api_unlock(adapter);
2310 return -1;
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002311
2312 case QLCNIC_DEV_INITIALIZING:
2313 case QLCNIC_DEV_QUISCENT:
2314 break;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002315 }
2316
2317 qlcnic_api_unlock(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002318
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002319 do {
2320 msleep(1000);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002321 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2322
2323 if (prev_state == QLCNIC_DEV_QUISCENT)
2324 continue;
2325 } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002326
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002327 if (!dev_init_timeo) {
2328 dev_err(&adapter->pdev->dev,
2329 "Waiting for device to initialize timeout\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002330 return -1;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002331 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002332
2333 if (qlcnic_api_lock(adapter))
2334 return -1;
2335
2336 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002337 QLC_DEV_CLR_RST_QSCNT(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002338 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2339
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002340 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002341 qlcnic_api_unlock(adapter);
2342
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002343 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002344}
2345
2346static void
2347qlcnic_fwinit_work(struct work_struct *work)
2348{
2349 struct qlcnic_adapter *adapter = container_of(work,
2350 struct qlcnic_adapter, fw_work.work);
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002351 u32 dev_state = 0xf, npar_state;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002352
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002353 if (qlcnic_api_lock(adapter))
2354 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002355
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002356 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2357 if (dev_state == QLCNIC_DEV_QUISCENT) {
2358 qlcnic_api_unlock(adapter);
2359 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2360 FW_POLL_DELAY * 2);
2361 return;
2362 }
2363
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002364 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
2365 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2366 if (npar_state == QLCNIC_DEV_NPAR_RDY) {
2367 qlcnic_api_unlock(adapter);
2368 goto wait_npar;
2369 } else {
2370 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2371 FW_POLL_DELAY);
2372 qlcnic_api_unlock(adapter);
2373 return;
2374 }
2375 }
2376
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002377 if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
2378 dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
2379 adapter->reset_ack_timeo);
2380 goto skip_ack_check;
2381 }
2382
2383 if (!qlcnic_check_drv_state(adapter)) {
2384skip_ack_check:
2385 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002386
2387 if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2388 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2389 QLCNIC_DEV_QUISCENT);
2390 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2391 FW_POLL_DELAY * 2);
2392 QLCDB(adapter, DRV, "Quiscing the driver\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002393 qlcnic_idc_debug_info(adapter, 0);
2394
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002395 qlcnic_api_unlock(adapter);
2396 return;
2397 }
2398
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002399 if (dev_state == QLCNIC_DEV_NEED_RESET) {
2400 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2401 QLCNIC_DEV_INITIALIZING);
2402 set_bit(__QLCNIC_START_FW, &adapter->state);
2403 QLCDB(adapter, DRV, "Restarting fw\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002404 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002405 }
2406
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002407 qlcnic_api_unlock(adapter);
2408
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002409 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002410 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
2411 return;
2412 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002413 goto err_ret;
2414 }
2415
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002416 qlcnic_api_unlock(adapter);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002417
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002418wait_npar:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002419 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002420 QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002421
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002422 switch (dev_state) {
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002423 case QLCNIC_DEV_QUISCENT:
2424 case QLCNIC_DEV_NEED_QUISCENT:
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002425 case QLCNIC_DEV_NEED_RESET:
2426 qlcnic_schedule_work(adapter,
2427 qlcnic_fwinit_work, FW_POLL_DELAY);
2428 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002429 case QLCNIC_DEV_FAILED:
2430 break;
2431
2432 default:
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002433 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002434 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
2435 return;
2436 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002437 }
2438
2439err_ret:
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002440 dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
2441 "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002442 netif_device_attach(adapter->netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002443 qlcnic_clr_all_drv_state(adapter);
2444}
2445
2446static void
2447qlcnic_detach_work(struct work_struct *work)
2448{
2449 struct qlcnic_adapter *adapter = container_of(work,
2450 struct qlcnic_adapter, fw_work.work);
2451 struct net_device *netdev = adapter->netdev;
2452 u32 status;
2453
2454 netif_device_detach(netdev);
2455
2456 qlcnic_down(adapter, netdev);
2457
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002458 status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
2459
2460 if (status & QLCNIC_RCODE_FATAL_ERROR)
2461 goto err_ret;
2462
2463 if (adapter->temp == QLCNIC_TEMP_PANIC)
2464 goto err_ret;
2465
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002466 if (qlcnic_set_drv_state(adapter, adapter->dev_state))
2467 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002468
2469 adapter->fw_wait_cnt = 0;
2470
2471 qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
2472
2473 return;
2474
2475err_ret:
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002476 dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
2477 status, adapter->temp);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002478 netif_device_attach(netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002479 qlcnic_clr_all_drv_state(adapter);
2480
2481}
2482
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002483/*Transit to RESET state from READY state only */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002484static void
2485qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
2486{
2487 u32 state;
2488
2489 if (qlcnic_api_lock(adapter))
2490 return;
2491
2492 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2493
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002494 if (state == QLCNIC_DEV_READY) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002495 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002496 QLCDB(adapter, DRV, "NEED_RESET state set\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002497 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002498 }
2499
2500 qlcnic_api_unlock(adapter);
2501}
2502
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002503/* Transit to NPAR READY state from NPAR NOT READY state */
2504static void
2505qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
2506{
2507 u32 state;
2508
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002509 if (qlcnic_api_lock(adapter))
2510 return;
2511
2512 state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2513
2514 if (state != QLCNIC_DEV_NPAR_RDY) {
2515 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
2516 QLCNIC_DEV_NPAR_RDY);
2517 QLCDB(adapter, DRV, "NPAR READY state set\n");
2518 }
2519
2520 qlcnic_api_unlock(adapter);
2521}
2522
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002523static void
2524qlcnic_schedule_work(struct qlcnic_adapter *adapter,
2525 work_func_t func, int delay)
2526{
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002527 if (test_bit(__QLCNIC_AER, &adapter->state))
2528 return;
2529
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002530 INIT_DELAYED_WORK(&adapter->fw_work, func);
2531 schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
2532}
2533
2534static void
2535qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
2536{
2537 while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
2538 msleep(10);
2539
2540 cancel_delayed_work_sync(&adapter->fw_work);
2541}
2542
2543static void
2544qlcnic_attach_work(struct work_struct *work)
2545{
2546 struct qlcnic_adapter *adapter = container_of(work,
2547 struct qlcnic_adapter, fw_work.work);
2548 struct net_device *netdev = adapter->netdev;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002549
2550 if (netif_running(netdev)) {
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00002551 if (qlcnic_up(adapter, netdev))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002552 goto done;
2553
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002554 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2555 }
2556
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002557done:
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002558 netif_device_attach(netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002559 adapter->fw_fail_cnt = 0;
2560 clear_bit(__QLCNIC_RESETTING, &adapter->state);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002561
2562 if (!qlcnic_clr_drv_state(adapter))
2563 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2564 FW_POLL_DELAY);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002565}
2566
2567static int
2568qlcnic_check_health(struct qlcnic_adapter *adapter)
2569{
2570 u32 state = 0, heartbit;
2571 struct net_device *netdev = adapter->netdev;
2572
2573 if (qlcnic_check_temp(adapter))
2574 goto detach;
2575
Amit Kumar Salecha2372a5f2010-05-13 03:07:42 +00002576 if (adapter->need_fw_reset)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002577 qlcnic_dev_request_reset(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002578
2579 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2580 if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT)
2581 adapter->need_fw_reset = 1;
2582
2583 heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
2584 if (heartbit != adapter->heartbit) {
2585 adapter->heartbit = heartbit;
2586 adapter->fw_fail_cnt = 0;
2587 if (adapter->need_fw_reset)
2588 goto detach;
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002589
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002590 if (adapter->reset_context &&
2591 auto_fw_reset == AUTO_FW_RESET_ENABLED) {
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002592 qlcnic_reset_hw_context(adapter);
2593 adapter->netdev->trans_start = jiffies;
2594 }
2595
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002596 return 0;
2597 }
2598
2599 if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
2600 return 0;
2601
2602 qlcnic_dev_request_reset(adapter);
2603
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002604 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED))
2605 clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002606
2607 dev_info(&netdev->dev, "firmware hang detected\n");
2608
2609detach:
2610 adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
2611 QLCNIC_DEV_NEED_RESET;
2612
2613 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002614 !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) {
2615
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002616 qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002617 QLCDB(adapter, DRV, "fw recovery scheduled.\n");
2618 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002619
2620 return 1;
2621}
2622
2623static void
2624qlcnic_fw_poll_work(struct work_struct *work)
2625{
2626 struct qlcnic_adapter *adapter = container_of(work,
2627 struct qlcnic_adapter, fw_work.work);
2628
2629 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
2630 goto reschedule;
2631
2632
2633 if (qlcnic_check_health(adapter))
2634 return;
2635
2636reschedule:
2637 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
2638}
2639
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002640static int qlcnic_is_first_func(struct pci_dev *pdev)
2641{
2642 struct pci_dev *oth_pdev;
2643 int val = pdev->devfn;
2644
2645 while (val-- > 0) {
2646 oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
2647 (pdev->bus), pdev->bus->number,
2648 PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
2649
2650 if (oth_pdev && (oth_pdev->current_state != PCI_D3cold))
2651 return 0;
2652 }
2653 return 1;
2654}
2655
2656static int qlcnic_attach_func(struct pci_dev *pdev)
2657{
2658 int err, first_func;
2659 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2660 struct net_device *netdev = adapter->netdev;
2661
2662 pdev->error_state = pci_channel_io_normal;
2663
2664 err = pci_enable_device(pdev);
2665 if (err)
2666 return err;
2667
2668 pci_set_power_state(pdev, PCI_D0);
2669 pci_set_master(pdev);
2670 pci_restore_state(pdev);
2671
2672 first_func = qlcnic_is_first_func(pdev);
2673
2674 if (qlcnic_api_lock(adapter))
2675 return -EINVAL;
2676
2677 if (first_func) {
2678 adapter->need_fw_reset = 1;
2679 set_bit(__QLCNIC_START_FW, &adapter->state);
2680 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
2681 QLCDB(adapter, DRV, "Restarting fw\n");
2682 }
2683 qlcnic_api_unlock(adapter);
2684
2685 err = adapter->nic_ops->start_firmware(adapter);
2686 if (err)
2687 return err;
2688
2689 qlcnic_clr_drv_state(adapter);
2690 qlcnic_setup_intr(adapter);
2691
2692 if (netif_running(netdev)) {
2693 err = qlcnic_attach(adapter);
2694 if (err) {
2695 qlcnic_clr_all_drv_state(adapter);
2696 clear_bit(__QLCNIC_AER, &adapter->state);
2697 netif_device_attach(netdev);
2698 return err;
2699 }
2700
2701 err = qlcnic_up(adapter, netdev);
2702 if (err)
2703 goto done;
2704
2705 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2706 }
2707 done:
2708 netif_device_attach(netdev);
2709 return err;
2710}
2711
2712static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
2713 pci_channel_state_t state)
2714{
2715 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2716 struct net_device *netdev = adapter->netdev;
2717
2718 if (state == pci_channel_io_perm_failure)
2719 return PCI_ERS_RESULT_DISCONNECT;
2720
2721 if (state == pci_channel_io_normal)
2722 return PCI_ERS_RESULT_RECOVERED;
2723
2724 set_bit(__QLCNIC_AER, &adapter->state);
2725 netif_device_detach(netdev);
2726
2727 cancel_delayed_work_sync(&adapter->fw_work);
2728
2729 if (netif_running(netdev))
2730 qlcnic_down(adapter, netdev);
2731
2732 qlcnic_detach(adapter);
2733 qlcnic_teardown_intr(adapter);
2734
2735 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2736
2737 pci_save_state(pdev);
2738 pci_disable_device(pdev);
2739
2740 return PCI_ERS_RESULT_NEED_RESET;
2741}
2742
2743static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
2744{
2745 return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
2746 PCI_ERS_RESULT_RECOVERED;
2747}
2748
2749static void qlcnic_io_resume(struct pci_dev *pdev)
2750{
2751 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2752
2753 pci_cleanup_aer_uncorrect_error_status(pdev);
2754
2755 if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
2756 test_and_clear_bit(__QLCNIC_AER, &adapter->state))
2757 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2758 FW_POLL_DELAY);
2759}
2760
2761
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00002762static int
2763qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
2764{
2765 int err;
2766
2767 err = qlcnic_can_start_firmware(adapter);
2768 if (err)
2769 return err;
2770
2771 qlcnic_check_options(adapter);
2772
2773 adapter->need_fw_reset = 0;
2774
2775 return err;
2776}
2777
2778static int
2779qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
2780{
2781 return -EOPNOTSUPP;
2782}
2783
2784static int
2785qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
2786{
2787 return -EOPNOTSUPP;
2788}
2789
2790static int
2791qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter)
2792{
2793 return -EOPNOTSUPP;
2794}
2795
2796static void
2797qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter)
2798{
2799 return;
2800}
2801
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002802static ssize_t
2803qlcnic_store_bridged_mode(struct device *dev,
2804 struct device_attribute *attr, const char *buf, size_t len)
2805{
2806 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2807 unsigned long new;
2808 int ret = -EINVAL;
2809
2810 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
2811 goto err_out;
2812
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00002813 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002814 goto err_out;
2815
2816 if (strict_strtoul(buf, 2, &new))
2817 goto err_out;
2818
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00002819 if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002820 ret = len;
2821
2822err_out:
2823 return ret;
2824}
2825
2826static ssize_t
2827qlcnic_show_bridged_mode(struct device *dev,
2828 struct device_attribute *attr, char *buf)
2829{
2830 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2831 int bridged_mode = 0;
2832
2833 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
2834 bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
2835
2836 return sprintf(buf, "%d\n", bridged_mode);
2837}
2838
2839static struct device_attribute dev_attr_bridged_mode = {
2840 .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
2841 .show = qlcnic_show_bridged_mode,
2842 .store = qlcnic_store_bridged_mode,
2843};
2844
2845static ssize_t
2846qlcnic_store_diag_mode(struct device *dev,
2847 struct device_attribute *attr, const char *buf, size_t len)
2848{
2849 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2850 unsigned long new;
2851
2852 if (strict_strtoul(buf, 2, &new))
2853 return -EINVAL;
2854
2855 if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
2856 adapter->flags ^= QLCNIC_DIAG_ENABLED;
2857
2858 return len;
2859}
2860
2861static ssize_t
2862qlcnic_show_diag_mode(struct device *dev,
2863 struct device_attribute *attr, char *buf)
2864{
2865 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2866
2867 return sprintf(buf, "%d\n",
2868 !!(adapter->flags & QLCNIC_DIAG_ENABLED));
2869}
2870
2871static struct device_attribute dev_attr_diag_mode = {
2872 .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
2873 .show = qlcnic_show_diag_mode,
2874 .store = qlcnic_store_diag_mode,
2875};
2876
2877static int
2878qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
2879 loff_t offset, size_t size)
2880{
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00002881 size_t crb_size = 4;
2882
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002883 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
2884 return -EIO;
2885
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00002886 if (offset < QLCNIC_PCI_CRBSPACE) {
2887 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
2888 QLCNIC_PCI_CAMQM_END))
2889 crb_size = 8;
2890 else
2891 return -EINVAL;
2892 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002893
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00002894 if ((size != crb_size) || (offset & (crb_size-1)))
2895 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002896
2897 return 0;
2898}
2899
2900static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07002901qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
2902 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002903 char *buf, loff_t offset, size_t size)
2904{
2905 struct device *dev = container_of(kobj, struct device, kobj);
2906 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2907 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00002908 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002909 int ret;
2910
2911 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
2912 if (ret != 0)
2913 return ret;
2914
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00002915 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
2916 qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
2917 memcpy(buf, &qmdata, size);
2918 } else {
2919 data = QLCRD32(adapter, offset);
2920 memcpy(buf, &data, size);
2921 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002922 return size;
2923}
2924
2925static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07002926qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
2927 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002928 char *buf, loff_t offset, size_t size)
2929{
2930 struct device *dev = container_of(kobj, struct device, kobj);
2931 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2932 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00002933 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002934 int ret;
2935
2936 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
2937 if (ret != 0)
2938 return ret;
2939
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00002940 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
2941 memcpy(&qmdata, buf, size);
2942 qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
2943 } else {
2944 memcpy(&data, buf, size);
2945 QLCWR32(adapter, offset, data);
2946 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002947 return size;
2948}
2949
2950static int
2951qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
2952 loff_t offset, size_t size)
2953{
2954 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
2955 return -EIO;
2956
2957 if ((size != 8) || (offset & 0x7))
2958 return -EIO;
2959
2960 return 0;
2961}
2962
2963static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07002964qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
2965 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002966 char *buf, loff_t offset, size_t size)
2967{
2968 struct device *dev = container_of(kobj, struct device, kobj);
2969 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2970 u64 data;
2971 int ret;
2972
2973 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
2974 if (ret != 0)
2975 return ret;
2976
2977 if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
2978 return -EIO;
2979
2980 memcpy(buf, &data, size);
2981
2982 return size;
2983}
2984
2985static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07002986qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
2987 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002988 char *buf, loff_t offset, size_t size)
2989{
2990 struct device *dev = container_of(kobj, struct device, kobj);
2991 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
2992 u64 data;
2993 int ret;
2994
2995 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
2996 if (ret != 0)
2997 return ret;
2998
2999 memcpy(&data, buf, size);
3000
3001 if (qlcnic_pci_mem_write_2M(adapter, offset, data))
3002 return -EIO;
3003
3004 return size;
3005}
3006
3007
3008static struct bin_attribute bin_attr_crb = {
3009 .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
3010 .size = 0,
3011 .read = qlcnic_sysfs_read_crb,
3012 .write = qlcnic_sysfs_write_crb,
3013};
3014
3015static struct bin_attribute bin_attr_mem = {
3016 .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
3017 .size = 0,
3018 .read = qlcnic_sysfs_read_mem,
3019 .write = qlcnic_sysfs_write_mem,
3020};
3021
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003022int
3023validate_pm_config(struct qlcnic_adapter *adapter,
3024 struct qlcnic_pm_func_cfg *pm_cfg, int count)
3025{
3026
3027 u8 src_pci_func, s_esw_id, d_esw_id;
3028 u8 dest_pci_func;
3029 int i;
3030
3031 for (i = 0; i < count; i++) {
3032 src_pci_func = pm_cfg[i].pci_func;
3033 dest_pci_func = pm_cfg[i].dest_npar;
3034 if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
3035 || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
3036 return QL_STATUS_INVALID_PARAM;
3037
3038 if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
3039 return QL_STATUS_INVALID_PARAM;
3040
3041 if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
3042 return QL_STATUS_INVALID_PARAM;
3043
3044 if (!IS_VALID_MODE(pm_cfg[i].action))
3045 return QL_STATUS_INVALID_PARAM;
3046
3047 s_esw_id = adapter->npars[src_pci_func].phy_port;
3048 d_esw_id = adapter->npars[dest_pci_func].phy_port;
3049
3050 if (s_esw_id != d_esw_id)
3051 return QL_STATUS_INVALID_PARAM;
3052
3053 }
3054 return 0;
3055
3056}
3057
3058static ssize_t
3059qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
3060 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3061{
3062 struct device *dev = container_of(kobj, struct device, kobj);
3063 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3064 struct qlcnic_pm_func_cfg *pm_cfg;
3065 u32 id, action, pci_func;
3066 int count, rem, i, ret;
3067
3068 count = size / sizeof(struct qlcnic_pm_func_cfg);
3069 rem = size % sizeof(struct qlcnic_pm_func_cfg);
3070 if (rem)
3071 return QL_STATUS_INVALID_PARAM;
3072
3073 pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
3074
3075 ret = validate_pm_config(adapter, pm_cfg, count);
3076 if (ret)
3077 return ret;
3078 for (i = 0; i < count; i++) {
3079 pci_func = pm_cfg[i].pci_func;
3080 action = pm_cfg[i].action;
3081 id = adapter->npars[pci_func].phy_port;
3082 ret = qlcnic_config_port_mirroring(adapter, id,
3083 action, pci_func);
3084 if (ret)
3085 return ret;
3086 }
3087
3088 for (i = 0; i < count; i++) {
3089 pci_func = pm_cfg[i].pci_func;
3090 id = adapter->npars[pci_func].phy_port;
3091 adapter->npars[pci_func].enable_pm = pm_cfg[i].action;
3092 adapter->npars[pci_func].dest_npar = id;
3093 }
3094 return size;
3095}
3096
3097static ssize_t
3098qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
3099 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3100{
3101 struct device *dev = container_of(kobj, struct device, kobj);
3102 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3103 struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
3104 int i;
3105
3106 if (size != sizeof(pm_cfg))
3107 return QL_STATUS_INVALID_PARAM;
3108
3109 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3110 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3111 continue;
3112 pm_cfg[i].action = adapter->npars[i].enable_pm;
3113 pm_cfg[i].dest_npar = 0;
3114 pm_cfg[i].pci_func = i;
3115 }
3116 memcpy(buf, &pm_cfg, size);
3117
3118 return size;
3119}
3120
3121int
3122validate_esw_config(struct qlcnic_adapter *adapter,
3123 struct qlcnic_esw_func_cfg *esw_cfg, int count)
3124{
3125 u8 pci_func;
3126 int i;
3127
3128 for (i = 0; i < count; i++) {
3129 pci_func = esw_cfg[i].pci_func;
3130 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3131 return QL_STATUS_INVALID_PARAM;
3132
3133 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3134 return QL_STATUS_INVALID_PARAM;
3135
3136 if (esw_cfg->host_vlan_tag == 1)
3137 if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
3138 return QL_STATUS_INVALID_PARAM;
3139
3140 if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
3141 || !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
3142 || !IS_VALID_MODE(esw_cfg[i].mac_learning)
3143 || !IS_VALID_MODE(esw_cfg[i].discard_tagged))
3144 return QL_STATUS_INVALID_PARAM;
3145 }
3146
3147 return 0;
3148}
3149
3150static ssize_t
3151qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
3152 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3153{
3154 struct device *dev = container_of(kobj, struct device, kobj);
3155 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3156 struct qlcnic_esw_func_cfg *esw_cfg;
3157 u8 id, discard_tagged, promsc_mode, mac_learn;
3158 u8 vlan_tagging, pci_func, vlan_id;
3159 int count, rem, i, ret;
3160
3161 count = size / sizeof(struct qlcnic_esw_func_cfg);
3162 rem = size % sizeof(struct qlcnic_esw_func_cfg);
3163 if (rem)
3164 return QL_STATUS_INVALID_PARAM;
3165
3166 esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
3167 ret = validate_esw_config(adapter, esw_cfg, count);
3168 if (ret)
3169 return ret;
3170
3171 for (i = 0; i < count; i++) {
3172 pci_func = esw_cfg[i].pci_func;
3173 id = adapter->npars[pci_func].phy_port;
3174 vlan_tagging = esw_cfg[i].host_vlan_tag;
3175 promsc_mode = esw_cfg[i].promisc_mode;
3176 mac_learn = esw_cfg[i].mac_learning;
3177 vlan_id = esw_cfg[i].vlan_id;
3178 discard_tagged = esw_cfg[i].discard_tagged;
3179 ret = qlcnic_config_switch_port(adapter, id, vlan_tagging,
3180 discard_tagged,
3181 promsc_mode,
3182 mac_learn,
3183 pci_func,
3184 vlan_id);
3185 if (ret)
3186 return ret;
3187 }
3188
3189 for (i = 0; i < count; i++) {
3190 pci_func = esw_cfg[i].pci_func;
3191 adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
3192 adapter->npars[pci_func].mac_learning = esw_cfg[i].mac_learning;
3193 adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
3194 adapter->npars[pci_func].discard_tagged =
3195 esw_cfg[i].discard_tagged;
3196 adapter->npars[pci_func].host_vlan_tag =
3197 esw_cfg[i].host_vlan_tag;
3198 }
3199
3200 return size;
3201}
3202
3203static ssize_t
3204qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
3205 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3206{
3207 struct device *dev = container_of(kobj, struct device, kobj);
3208 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3209 struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
3210 int i;
3211
3212 if (size != sizeof(esw_cfg))
3213 return QL_STATUS_INVALID_PARAM;
3214
3215 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3216 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3217 continue;
3218
3219 esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
3220 esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
3221 esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
3222 esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
3223 esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
3224 }
3225 memcpy(buf, &esw_cfg, size);
3226
3227 return size;
3228}
3229
3230int
3231validate_npar_config(struct qlcnic_adapter *adapter,
3232 struct qlcnic_npar_func_cfg *np_cfg, int count)
3233{
3234 u8 pci_func, i;
3235
3236 for (i = 0; i < count; i++) {
3237 pci_func = np_cfg[i].pci_func;
3238 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3239 return QL_STATUS_INVALID_PARAM;
3240
3241 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
3242 return QL_STATUS_INVALID_PARAM;
3243
3244 if (!IS_VALID_BW(np_cfg[i].min_bw)
3245 || !IS_VALID_BW(np_cfg[i].max_bw)
3246 || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
3247 || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
3248 return QL_STATUS_INVALID_PARAM;
3249 }
3250 return 0;
3251}
3252
3253static ssize_t
3254qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
3255 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3256{
3257 struct device *dev = container_of(kobj, struct device, kobj);
3258 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3259 struct qlcnic_info nic_info;
3260 struct qlcnic_npar_func_cfg *np_cfg;
3261 int i, count, rem, ret;
3262 u8 pci_func;
3263
3264 count = size / sizeof(struct qlcnic_npar_func_cfg);
3265 rem = size % sizeof(struct qlcnic_npar_func_cfg);
3266 if (rem)
3267 return QL_STATUS_INVALID_PARAM;
3268
3269 np_cfg = (struct qlcnic_npar_func_cfg *) buf;
3270 ret = validate_npar_config(adapter, np_cfg, count);
3271 if (ret)
3272 return ret;
3273
3274 for (i = 0; i < count ; i++) {
3275 pci_func = np_cfg[i].pci_func;
3276 ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
3277 if (ret)
3278 return ret;
3279 nic_info.pci_func = pci_func;
3280 nic_info.min_tx_bw = np_cfg[i].min_bw;
3281 nic_info.max_tx_bw = np_cfg[i].max_bw;
3282 ret = qlcnic_set_nic_info(adapter, &nic_info);
3283 if (ret)
3284 return ret;
3285 }
3286
3287 return size;
3288
3289}
3290static ssize_t
3291qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
3292 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3293{
3294 struct device *dev = container_of(kobj, struct device, kobj);
3295 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3296 struct qlcnic_info nic_info;
3297 struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
3298 int i, ret;
3299
3300 if (size != sizeof(np_cfg))
3301 return QL_STATUS_INVALID_PARAM;
3302
3303 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3304 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3305 continue;
3306 ret = qlcnic_get_nic_info(adapter, &nic_info, i);
3307 if (ret)
3308 return ret;
3309
3310 np_cfg[i].pci_func = i;
3311 np_cfg[i].op_mode = nic_info.op_mode;
3312 np_cfg[i].port_num = nic_info.phys_port;
3313 np_cfg[i].fw_capab = nic_info.capabilities;
3314 np_cfg[i].min_bw = nic_info.min_tx_bw ;
3315 np_cfg[i].max_bw = nic_info.max_tx_bw;
3316 np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
3317 np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
3318 }
3319 memcpy(buf, &np_cfg, size);
3320 return size;
3321}
3322
3323static ssize_t
3324qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
3325 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3326{
3327 struct device *dev = container_of(kobj, struct device, kobj);
3328 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3329 struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
3330 struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
3331 int i, ret;
3332
3333 if (size != sizeof(pci_cfg))
3334 return QL_STATUS_INVALID_PARAM;
3335
3336 ret = qlcnic_get_pci_info(adapter, pci_info);
3337 if (ret)
3338 return ret;
3339
3340 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3341 pci_cfg[i].pci_func = pci_info[i].id;
3342 pci_cfg[i].func_type = pci_info[i].type;
3343 pci_cfg[i].port_num = pci_info[i].default_port;
3344 pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
3345 pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
3346 memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
3347 }
3348 memcpy(buf, &pci_cfg, size);
3349 return size;
3350
3351}
3352static struct bin_attribute bin_attr_npar_config = {
3353 .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
3354 .size = 0,
3355 .read = qlcnic_sysfs_read_npar_config,
3356 .write = qlcnic_sysfs_write_npar_config,
3357};
3358
3359static struct bin_attribute bin_attr_pci_config = {
3360 .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
3361 .size = 0,
3362 .read = qlcnic_sysfs_read_pci_config,
3363 .write = NULL,
3364};
3365
3366static struct bin_attribute bin_attr_esw_config = {
3367 .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
3368 .size = 0,
3369 .read = qlcnic_sysfs_read_esw_config,
3370 .write = qlcnic_sysfs_write_esw_config,
3371};
3372
3373static struct bin_attribute bin_attr_pm_config = {
3374 .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
3375 .size = 0,
3376 .read = qlcnic_sysfs_read_pm_config,
3377 .write = qlcnic_sysfs_write_pm_config,
3378};
3379
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003380static void
3381qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
3382{
3383 struct device *dev = &adapter->pdev->dev;
3384
3385 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3386 if (device_create_file(dev, &dev_attr_bridged_mode))
3387 dev_warn(dev,
3388 "failed to create bridged_mode sysfs entry\n");
3389}
3390
3391static void
3392qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
3393{
3394 struct device *dev = &adapter->pdev->dev;
3395
3396 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3397 device_remove_file(dev, &dev_attr_bridged_mode);
3398}
3399
3400static void
3401qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
3402{
3403 struct device *dev = &adapter->pdev->dev;
3404
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003405 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3406 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003407 if (device_create_file(dev, &dev_attr_diag_mode))
3408 dev_info(dev, "failed to create diag_mode sysfs entry\n");
3409 if (device_create_bin_file(dev, &bin_attr_crb))
3410 dev_info(dev, "failed to create crb sysfs entry\n");
3411 if (device_create_bin_file(dev, &bin_attr_mem))
3412 dev_info(dev, "failed to create mem sysfs entry\n");
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003413 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
3414 adapter->op_mode != QLCNIC_MGMT_FUNC)
3415 return;
3416 if (device_create_bin_file(dev, &bin_attr_pci_config))
3417 dev_info(dev, "failed to create pci config sysfs entry");
3418 if (device_create_bin_file(dev, &bin_attr_npar_config))
3419 dev_info(dev, "failed to create npar config sysfs entry");
3420 if (device_create_bin_file(dev, &bin_attr_esw_config))
3421 dev_info(dev, "failed to create esw config sysfs entry");
3422 if (device_create_bin_file(dev, &bin_attr_pm_config))
3423 dev_info(dev, "failed to create pm config sysfs entry");
3424
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003425}
3426
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003427static void
3428qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
3429{
3430 struct device *dev = &adapter->pdev->dev;
3431
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003432 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3433 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003434 device_remove_file(dev, &dev_attr_diag_mode);
3435 device_remove_bin_file(dev, &bin_attr_crb);
3436 device_remove_bin_file(dev, &bin_attr_mem);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003437 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
3438 adapter->op_mode != QLCNIC_MGMT_FUNC)
3439 return;
3440 device_remove_bin_file(dev, &bin_attr_pci_config);
3441 device_remove_bin_file(dev, &bin_attr_npar_config);
3442 device_remove_bin_file(dev, &bin_attr_esw_config);
3443 device_remove_bin_file(dev, &bin_attr_pm_config);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003444}
3445
3446#ifdef CONFIG_INET
3447
3448#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
3449
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003450static void
3451qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
3452{
3453 struct in_device *indev;
3454 struct qlcnic_adapter *adapter = netdev_priv(dev);
3455
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003456 indev = in_dev_get(dev);
3457 if (!indev)
3458 return;
3459
3460 for_ifa(indev) {
3461 switch (event) {
3462 case NETDEV_UP:
3463 qlcnic_config_ipaddr(adapter,
3464 ifa->ifa_address, QLCNIC_IP_UP);
3465 break;
3466 case NETDEV_DOWN:
3467 qlcnic_config_ipaddr(adapter,
3468 ifa->ifa_address, QLCNIC_IP_DOWN);
3469 break;
3470 default:
3471 break;
3472 }
3473 } endfor_ifa(indev);
3474
3475 in_dev_put(indev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003476}
3477
3478static int qlcnic_netdev_event(struct notifier_block *this,
3479 unsigned long event, void *ptr)
3480{
3481 struct qlcnic_adapter *adapter;
3482 struct net_device *dev = (struct net_device *)ptr;
3483
3484recheck:
3485 if (dev == NULL)
3486 goto done;
3487
3488 if (dev->priv_flags & IFF_802_1Q_VLAN) {
3489 dev = vlan_dev_real_dev(dev);
3490 goto recheck;
3491 }
3492
3493 if (!is_qlcnic_netdev(dev))
3494 goto done;
3495
3496 adapter = netdev_priv(dev);
3497
3498 if (!adapter)
3499 goto done;
3500
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003501 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003502 goto done;
3503
3504 qlcnic_config_indev_addr(dev, event);
3505done:
3506 return NOTIFY_DONE;
3507}
3508
3509static int
3510qlcnic_inetaddr_event(struct notifier_block *this,
3511 unsigned long event, void *ptr)
3512{
3513 struct qlcnic_adapter *adapter;
3514 struct net_device *dev;
3515
3516 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
3517
3518 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
3519
3520recheck:
3521 if (dev == NULL || !netif_running(dev))
3522 goto done;
3523
3524 if (dev->priv_flags & IFF_802_1Q_VLAN) {
3525 dev = vlan_dev_real_dev(dev);
3526 goto recheck;
3527 }
3528
3529 if (!is_qlcnic_netdev(dev))
3530 goto done;
3531
3532 adapter = netdev_priv(dev);
3533
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +00003534 if (!adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003535 goto done;
3536
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003537 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003538 goto done;
3539
3540 switch (event) {
3541 case NETDEV_UP:
3542 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
3543 break;
3544 case NETDEV_DOWN:
3545 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
3546 break;
3547 default:
3548 break;
3549 }
3550
3551done:
3552 return NOTIFY_DONE;
3553}
3554
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003555static struct notifier_block qlcnic_netdev_cb = {
3556 .notifier_call = qlcnic_netdev_event,
3557};
3558
3559static struct notifier_block qlcnic_inetaddr_cb = {
3560 .notifier_call = qlcnic_inetaddr_event,
3561};
3562#else
3563static void
3564qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
3565{ }
3566#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003567static struct pci_error_handlers qlcnic_err_handler = {
3568 .error_detected = qlcnic_io_error_detected,
3569 .slot_reset = qlcnic_io_slot_reset,
3570 .resume = qlcnic_io_resume,
3571};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003572
3573static struct pci_driver qlcnic_driver = {
3574 .name = qlcnic_driver_name,
3575 .id_table = qlcnic_pci_tbl,
3576 .probe = qlcnic_probe,
3577 .remove = __devexit_p(qlcnic_remove),
3578#ifdef CONFIG_PM
3579 .suspend = qlcnic_suspend,
3580 .resume = qlcnic_resume,
3581#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003582 .shutdown = qlcnic_shutdown,
3583 .err_handler = &qlcnic_err_handler
3584
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003585};
3586
3587static int __init qlcnic_init_module(void)
3588{
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00003589 int ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003590
3591 printk(KERN_INFO "%s\n", qlcnic_driver_string);
3592
3593#ifdef CONFIG_INET
3594 register_netdevice_notifier(&qlcnic_netdev_cb);
3595 register_inetaddr_notifier(&qlcnic_inetaddr_cb);
3596#endif
3597
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00003598 ret = pci_register_driver(&qlcnic_driver);
3599 if (ret) {
3600#ifdef CONFIG_INET
3601 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
3602 unregister_netdevice_notifier(&qlcnic_netdev_cb);
3603#endif
3604 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003605
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00003606 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003607}
3608
3609module_init(qlcnic_init_module);
3610
3611static void __exit qlcnic_exit_module(void)
3612{
3613
3614 pci_unregister_driver(&qlcnic_driver);
3615
3616#ifdef CONFIG_INET
3617 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
3618 unregister_netdevice_notifier(&qlcnic_netdev_cb);
3619#endif
3620}
3621
3622module_exit(qlcnic_exit_module);