blob: 771a160b88c110b331d37365055792e730836144 [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 Salecha21854f02010-08-19 05:08:29 +000097static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000098static 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 *);
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000110static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
111static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
112static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
Rajesh Borundia0325d692010-08-19 05:08:26 +0000113static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
114 struct qlcnic_esw_func_cfg *);
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,
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000384 .start_firmware = qlcnic_start_firmware
385};
386
387static struct qlcnic_nic_template qlcnic_vf_ops = {
388 .get_mac_addr = qlcnic_get_mac_address,
389 .config_bridged_mode = qlcnicvf_config_bridged_mode,
390 .config_led = qlcnicvf_config_led,
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000391 .start_firmware = qlcnicvf_start_firmware
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000392};
393
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000394static void
395qlcnic_setup_intr(struct qlcnic_adapter *adapter)
396{
397 const struct qlcnic_legacy_intr_set *legacy_intrp;
398 struct pci_dev *pdev = adapter->pdev;
399 int err, num_msix;
400
401 if (adapter->rss_supported) {
402 num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
403 MSIX_ENTRIES_PER_ADAPTER : 2;
404 } else
405 num_msix = 1;
406
407 adapter->max_sds_rings = 1;
408
409 adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
410
411 legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
412
413 adapter->int_vec_bit = legacy_intrp->int_vec_bit;
414 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
415 legacy_intrp->tgt_status_reg);
416 adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
417 legacy_intrp->tgt_mask_reg);
418 adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
419
420 adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
421 ISR_INT_STATE_REG);
422
423 qlcnic_set_msix_bit(pdev, 0);
424
425 if (adapter->msix_supported) {
426
427 qlcnic_init_msix_entries(adapter, num_msix);
428 err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
429 if (err == 0) {
430 adapter->flags |= QLCNIC_MSIX_ENABLED;
431 qlcnic_set_msix_bit(pdev, 1);
432
433 if (adapter->rss_supported)
434 adapter->max_sds_rings = num_msix;
435
436 dev_info(&pdev->dev, "using msi-x interrupts\n");
437 return;
438 }
439
440 if (err > 0)
441 pci_disable_msix(pdev);
442
443 /* fall through for msi */
444 }
445
446 if (use_msi && !pci_enable_msi(pdev)) {
447 adapter->flags |= QLCNIC_MSI_ENABLED;
448 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
449 msi_tgt_status[adapter->ahw.pci_func]);
450 dev_info(&pdev->dev, "using msi interrupts\n");
451 adapter->msix_entries[0].vector = pdev->irq;
452 return;
453 }
454
455 dev_info(&pdev->dev, "using legacy interrupts\n");
456 adapter->msix_entries[0].vector = pdev->irq;
457}
458
459static void
460qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
461{
462 if (adapter->flags & QLCNIC_MSIX_ENABLED)
463 pci_disable_msix(adapter->pdev);
464 if (adapter->flags & QLCNIC_MSI_ENABLED)
465 pci_disable_msi(adapter->pdev);
466}
467
468static void
469qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
470{
471 if (adapter->ahw.pci_base0 != NULL)
472 iounmap(adapter->ahw.pci_base0);
473}
474
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000475static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000476qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
477{
Dan Carpentere88db3b2010-08-09 21:49:36 +0000478 struct qlcnic_pci_info *pci_info;
Julia Lawall900853a2010-08-16 10:23:51 +0000479 int i, ret = 0;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000480 u8 pfn;
481
Dan Carpentere88db3b2010-08-09 21:49:36 +0000482 pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
483 if (!pci_info)
484 return -ENOMEM;
485
Dan Carpenterca315ac2010-08-09 21:47:56 +0000486 adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000487 QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
Dan Carpentere88db3b2010-08-09 21:49:36 +0000488 if (!adapter->npars) {
Julia Lawall900853a2010-08-16 10:23:51 +0000489 ret = -ENOMEM;
Dan Carpentere88db3b2010-08-09 21:49:36 +0000490 goto err_pci_info;
491 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000492
Dan Carpenterca315ac2010-08-09 21:47:56 +0000493 adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000494 QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
495 if (!adapter->eswitch) {
Julia Lawall900853a2010-08-16 10:23:51 +0000496 ret = -ENOMEM;
Dan Carpenterca315ac2010-08-09 21:47:56 +0000497 goto err_npars;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000498 }
499
500 ret = qlcnic_get_pci_info(adapter, pci_info);
Dan Carpenterca315ac2010-08-09 21:47:56 +0000501 if (ret)
502 goto err_eswitch;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000503
Dan Carpenterca315ac2010-08-09 21:47:56 +0000504 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
505 pfn = pci_info[i].id;
506 if (pfn > QLCNIC_MAX_PCI_FUNC)
507 return QL_STATUS_INVALID_PARAM;
508 adapter->npars[pfn].active = pci_info[i].active;
509 adapter->npars[pfn].type = pci_info[i].type;
510 adapter->npars[pfn].phy_port = pci_info[i].default_port;
Dan Carpenterca315ac2010-08-09 21:47:56 +0000511 adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
512 adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000513 }
514
Dan Carpenterca315ac2010-08-09 21:47:56 +0000515 for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
516 adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
517
Dan Carpentere88db3b2010-08-09 21:49:36 +0000518 kfree(pci_info);
Dan Carpenterca315ac2010-08-09 21:47:56 +0000519 return 0;
520
521err_eswitch:
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000522 kfree(adapter->eswitch);
523 adapter->eswitch = NULL;
Dan Carpenterca315ac2010-08-09 21:47:56 +0000524err_npars:
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000525 kfree(adapter->npars);
Dan Carpenterca315ac2010-08-09 21:47:56 +0000526 adapter->npars = NULL;
Dan Carpentere88db3b2010-08-09 21:49:36 +0000527err_pci_info:
528 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000529
530 return ret;
531}
532
533static int
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000534qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
535{
536 u8 id;
537 u32 ref_count;
538 int i, ret = 1;
539 u32 data = QLCNIC_MGMT_FUNC;
540 void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
541
542 /* If other drivers are not in use set their privilege level */
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000543 ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000544 ret = qlcnic_api_lock(adapter);
545 if (ret)
546 goto err_lock;
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000547
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000548 if (qlcnic_config_npars) {
549 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000550 id = i;
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000551 if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
552 id == adapter->ahw.pci_func)
553 continue;
554 data |= (qlcnic_config_npars &
555 QLC_DEV_SET_DRV(0xf, id));
556 }
557 } else {
558 data = readl(priv_op);
559 data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) |
560 (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
561 adapter->ahw.pci_func));
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000562 }
563 writel(data, priv_op);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000564 qlcnic_api_unlock(adapter);
565err_lock:
566 return ret;
567}
568
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000569static void
570qlcnic_check_vf(struct qlcnic_adapter *adapter)
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000571{
572 void __iomem *msix_base_addr;
573 void __iomem *priv_op;
574 u32 func;
575 u32 msix_base;
576 u32 op_mode, priv_level;
577
578 /* Determine FW API version */
579 adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000580
581 /* Find PCI function number */
582 pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
583 msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
584 msix_base = readl(msix_base_addr);
585 func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
586 adapter->ahw.pci_func = func;
587
588 /* Determine function privilege level */
589 priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
590 op_mode = readl(priv_op);
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000591 if (op_mode == QLC_DEV_DRV_DEFAULT)
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000592 priv_level = QLCNIC_MGMT_FUNC;
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000593 else
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000594 priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
595
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000596 if (priv_level == QLCNIC_NON_PRIV_FUNC) {
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000597 adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
598 dev_info(&adapter->pdev->dev,
599 "HAL Version: %d Non Privileged function\n",
600 adapter->fw_hal_version);
601 adapter->nic_ops = &qlcnic_vf_ops;
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000602 } else
603 adapter->nic_ops = &qlcnic_ops;
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000604}
605
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000606static int
607qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
608{
609 void __iomem *mem_ptr0 = NULL;
610 resource_size_t mem_base;
611 unsigned long mem_len, pci_len0 = 0;
612
613 struct pci_dev *pdev = adapter->pdev;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000614
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000615 /* remap phys address */
616 mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
617 mem_len = pci_resource_len(pdev, 0);
618
619 if (mem_len == QLCNIC_PCI_2MB_SIZE) {
620
621 mem_ptr0 = pci_ioremap_bar(pdev, 0);
622 if (mem_ptr0 == NULL) {
623 dev_err(&pdev->dev, "failed to map PCI bar 0\n");
624 return -EIO;
625 }
626 pci_len0 = mem_len;
627 } else {
628 return -EIO;
629 }
630
631 dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
632
633 adapter->ahw.pci_base0 = mem_ptr0;
634 adapter->ahw.pci_len0 = pci_len0;
635
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000636 qlcnic_check_vf(adapter);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000637
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000638 adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000639 QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000640
641 return 0;
642}
643
644static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
645{
646 struct pci_dev *pdev = adapter->pdev;
647 int i, found = 0;
648
649 for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
650 if (qlcnic_boards[i].vendor == pdev->vendor &&
651 qlcnic_boards[i].device == pdev->device &&
652 qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
653 qlcnic_boards[i].sub_device == pdev->subsystem_device) {
Sucheta Chakraborty02f6e462010-05-17 01:22:09 +0000654 sprintf(name, "%pM: %s" ,
655 adapter->mac_addr,
656 qlcnic_boards[i].short_name);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000657 found = 1;
658 break;
659 }
660
661 }
662
663 if (!found)
Sritej Velaga7f9a0c32010-06-17 02:56:39 +0000664 sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000665}
666
667static void
668qlcnic_check_options(struct qlcnic_adapter *adapter)
669{
670 u32 fw_major, fw_minor, fw_build;
671 char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000672 struct pci_dev *pdev = adapter->pdev;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000673 struct qlcnic_info nic_info;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000674
675 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
676 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
677 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
678
679 adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
680
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000681 if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED))
682 if (qlcnic_read_mac_addr(adapter))
683 dev_warn(&pdev->dev, "failed to read mac addr\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000684 if (adapter->portnum == 0) {
685 get_brd_name(adapter, brd_name);
686
687 pr_info("%s: %s Board Chip rev 0x%x\n",
688 module_name(THIS_MODULE),
689 brd_name, adapter->ahw.revision_id);
690 }
691
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +0000692 dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
693 fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000694
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000695 adapter->flags &= ~QLCNIC_LRO_ENABLED;
696
697 if (adapter->ahw.port_type == QLCNIC_XGBE) {
698 adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
699 adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
700 } else if (adapter->ahw.port_type == QLCNIC_GBE) {
701 adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
702 adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
703 }
704
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000705 if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
706 adapter->physical_port = nic_info.phys_port;
707 adapter->switch_mode = nic_info.switch_mode;
708 adapter->max_tx_ques = nic_info.max_tx_ques;
709 adapter->max_rx_ques = nic_info.max_rx_ques;
710 adapter->capabilities = nic_info.capabilities;
711 adapter->max_mac_filters = nic_info.max_mac_filters;
712 adapter->max_mtu = nic_info.max_mtu;
713 }
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000714
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000715 adapter->msix_supported = !!use_msi_x;
716 adapter->rss_supported = !!use_msi_x;
717
718 adapter->num_txd = MAX_CMD_DESCRIPTORS;
719
Sony Chacko251b0362010-08-19 05:08:24 +0000720 adapter->max_rds_rings = MAX_RDS_RINGS;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000721}
722
Rajesh Borundia0325d692010-08-19 05:08:26 +0000723static void
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +0000724qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
725 struct qlcnic_esw_func_cfg *esw_cfg)
726{
727 if (esw_cfg->discard_tagged)
728 adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
729 else
730 adapter->flags |= QLCNIC_TAGGING_ENABLED;
731
732 if (esw_cfg->vlan_id)
733 adapter->pvid = esw_cfg->vlan_id;
734 else
735 adapter->pvid = 0;
736}
737
738static void
Rajesh Borundia0325d692010-08-19 05:08:26 +0000739qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
740 struct qlcnic_esw_func_cfg *esw_cfg)
741{
Sony Chackofe4d4342010-08-19 05:08:27 +0000742 adapter->flags &= ~QLCNIC_MACSPOOF;
743 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
744 if (esw_cfg->mac_anti_spoof)
745 adapter->flags |= QLCNIC_MACSPOOF;
746
Rajesh Borundia0325d692010-08-19 05:08:26 +0000747 qlcnic_set_netdev_features(adapter, esw_cfg);
748}
749
750static int
751qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
752{
753 struct qlcnic_esw_func_cfg esw_cfg;
754
755 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
756 return 0;
757
758 esw_cfg.pci_func = adapter->ahw.pci_func;
759 if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg))
760 return -EIO;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +0000761 qlcnic_set_vlan_config(adapter, &esw_cfg);
Rajesh Borundia0325d692010-08-19 05:08:26 +0000762 qlcnic_set_eswitch_port_features(adapter, &esw_cfg);
763
764 return 0;
765}
766
767static void
768qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
769 struct qlcnic_esw_func_cfg *esw_cfg)
770{
771 struct net_device *netdev = adapter->netdev;
772 unsigned long features, vlan_features;
773
774 features = (NETIF_F_SG | NETIF_F_IP_CSUM |
775 NETIF_F_IPV6_CSUM | NETIF_F_GRO);
776 vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
777 NETIF_F_IPV6_CSUM);
778
779 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
780 features |= (NETIF_F_TSO | NETIF_F_TSO6);
781 vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
782 }
783 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
784 features |= NETIF_F_LRO;
785
786 if (esw_cfg->offload_flags & BIT_0) {
787 netdev->features |= features;
788 adapter->rx_csum = 1;
789 if (!(esw_cfg->offload_flags & BIT_1))
790 netdev->features &= ~NETIF_F_TSO;
791 if (!(esw_cfg->offload_flags & BIT_2))
792 netdev->features &= ~NETIF_F_TSO6;
793 } else {
794 netdev->features &= ~features;
795 adapter->rx_csum = 0;
796 }
797
798 netdev->vlan_features = (features & vlan_features);
799}
800
801static int
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000802qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
803{
804 void __iomem *priv_op;
805 u32 op_mode, priv_level;
806 int err = 0;
807
808 if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
809 return 0;
810
811 priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
812 op_mode = readl(priv_op);
813 priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
814
815 if (op_mode == QLC_DEV_DRV_DEFAULT)
816 priv_level = QLCNIC_MGMT_FUNC;
817 else
818 priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
819
820 if (adapter->capabilities & BIT_6) {
821 adapter->flags |= QLCNIC_ESWITCH_ENABLED;
822 if (priv_level == QLCNIC_MGMT_FUNC) {
823 adapter->op_mode = QLCNIC_MGMT_FUNC;
824 err = qlcnic_init_pci_info(adapter);
825 if (err)
826 return err;
827 /* Set privilege level for other functions */
828 qlcnic_set_function_modes(adapter);
829 dev_info(&adapter->pdev->dev,
830 "HAL Version: %d, Management function\n",
831 adapter->fw_hal_version);
832 } else if (priv_level == QLCNIC_PRIV_FUNC) {
833 adapter->op_mode = QLCNIC_PRIV_FUNC;
834 dev_info(&adapter->pdev->dev,
835 "HAL Version: %d, Privileged function\n",
836 adapter->fw_hal_version);
837 }
838 } else
839 adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
840
841 adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
842
843 return err;
844}
845
846static int
Rajesh Borundia0325d692010-08-19 05:08:26 +0000847qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
848{
849 struct qlcnic_esw_func_cfg esw_cfg;
850 struct qlcnic_npar_info *npar;
851 u8 i;
852
853 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
854 adapter->need_fw_reset ||
855 adapter->op_mode != QLCNIC_MGMT_FUNC)
856 return 0;
857
858 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
859 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
860 continue;
861 memset(&esw_cfg, 0, sizeof(struct qlcnic_esw_func_cfg));
862 esw_cfg.pci_func = i;
863 esw_cfg.offload_flags = BIT_0;
864 esw_cfg.mac_learning = BIT_0;
865 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
866 esw_cfg.offload_flags |= (BIT_1 | BIT_2);
867 if (qlcnic_config_switch_port(adapter, &esw_cfg))
868 return -EIO;
869 npar = &adapter->npars[i];
870 npar->pvid = esw_cfg.vlan_id;
871 npar->mac_learning = esw_cfg.offload_flags;
872 npar->mac_anti_spoof = esw_cfg.mac_anti_spoof;
873 npar->discard_tagged = esw_cfg.discard_tagged;
874 npar->promisc_mode = esw_cfg.promisc_mode;
875 npar->offload_flags = esw_cfg.offload_flags;
876 }
877
878 return 0;
879}
880
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000881static int
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000882qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
883 struct qlcnic_npar_info *npar, int pci_func)
884{
885 struct qlcnic_esw_func_cfg esw_cfg;
886 esw_cfg.op_mode = QLCNIC_PORT_DEFAULTS;
887 esw_cfg.pci_func = pci_func;
888 esw_cfg.vlan_id = npar->pvid;
889 esw_cfg.mac_learning = npar->mac_learning;
890 esw_cfg.discard_tagged = npar->discard_tagged;
891 esw_cfg.mac_anti_spoof = npar->mac_anti_spoof;
892 esw_cfg.offload_flags = npar->offload_flags;
893 esw_cfg.promisc_mode = npar->promisc_mode;
894 if (qlcnic_config_switch_port(adapter, &esw_cfg))
895 return -EIO;
896
897 esw_cfg.op_mode = QLCNIC_ADD_VLAN;
898 if (qlcnic_config_switch_port(adapter, &esw_cfg))
899 return -EIO;
900
901 return 0;
902}
903
904static int
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000905qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
906{
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000907 int i, err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000908 struct qlcnic_npar_info *npar;
909 struct qlcnic_info nic_info;
910
911 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000912 !adapter->need_fw_reset || adapter->op_mode != QLCNIC_MGMT_FUNC)
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000913 return 0;
914
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000915 /* Set the NPAR config data after FW reset */
916 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
917 npar = &adapter->npars[i];
918 if (npar->type != QLCNIC_TYPE_NIC)
919 continue;
920 err = qlcnic_get_nic_info(adapter, &nic_info, i);
921 if (err)
922 return err;
923 nic_info.min_tx_bw = npar->min_bw;
924 nic_info.max_tx_bw = npar->max_bw;
925 err = qlcnic_set_nic_info(adapter, &nic_info);
926 if (err)
927 return err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000928
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000929 if (npar->enable_pm) {
930 err = qlcnic_config_port_mirroring(adapter,
931 npar->dest_npar, 1, i);
932 if (err)
933 return err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000934 }
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000935 err = qlcnic_reset_eswitch_config(adapter, npar, i);
936 if (err)
937 return err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000938 }
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000939 return 0;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000940}
941
Amit Kumar Salecha78f84e12010-08-19 05:08:28 +0000942static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
943{
944 u8 npar_opt_timeo = QLCNIC_DEV_NPAR_OPER_TIMEO;
945 u32 npar_state;
946
947 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
948 return 0;
949
950 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
951 while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
952 msleep(1000);
953 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
954 }
955 if (!npar_opt_timeo) {
956 dev_err(&adapter->pdev->dev,
957 "Waiting for NPAR state to opertional timeout\n");
958 return -EIO;
959 }
960 return 0;
961}
962
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000963static int
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000964qlcnic_start_firmware(struct qlcnic_adapter *adapter)
965{
Sony Chackod4066832010-08-19 05:08:31 +0000966 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000967
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +0000968 err = qlcnic_can_start_firmware(adapter);
969 if (err < 0)
970 return err;
971 else if (!err)
Sony Chackod4066832010-08-19 05:08:31 +0000972 goto check_fw_status;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000973
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +0000974 if (load_fw_file)
975 qlcnic_request_firmware(adapter);
schacko8f891382010-06-17 02:56:40 +0000976 else {
Sony Chacko8cfdce02010-08-26 14:02:41 +0000977 err = qlcnic_check_flash_fw_ver(adapter);
978 if (err)
schacko8f891382010-06-17 02:56:40 +0000979 goto err_out;
980
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +0000981 adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
schacko8f891382010-06-17 02:56:40 +0000982 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000983
984 err = qlcnic_need_fw_reset(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000985 if (err == 0)
Sony Chacko4e708122010-08-31 17:17:44 +0000986 goto check_fw_status;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000987
Sony Chackod4066832010-08-19 05:08:31 +0000988 err = qlcnic_pinit_from_rom(adapter);
989 if (err)
990 goto err_out;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000991 qlcnic_set_port_mode(adapter);
992
993 err = qlcnic_load_firmware(adapter);
994 if (err)
995 goto err_out;
996
997 qlcnic_release_firmware(adapter);
Sony Chackod4066832010-08-19 05:08:31 +0000998 QLCWR32(adapter, CRB_DRIVER_VERSION, QLCNIC_DRIVER_VERSION);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000999
Sony Chackod4066832010-08-19 05:08:31 +00001000check_fw_status:
1001 err = qlcnic_check_fw_status(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001002 if (err)
1003 goto err_out;
1004
1005 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00001006 qlcnic_idc_debug_info(adapter, 1);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00001007
Sony Chacko8cfdce02010-08-26 14:02:41 +00001008 err = qlcnic_set_default_offload_settings(adapter);
1009 if (err)
Rajesh Borundia0325d692010-08-19 05:08:26 +00001010 goto err_out;
Sony Chacko8cfdce02010-08-26 14:02:41 +00001011 err = qlcnic_reset_npar_config(adapter);
1012 if (err)
Anirban Chakrabortycea89752010-07-13 20:33:35 +00001013 goto err_out;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00001014 qlcnic_check_options(adapter);
Anirban Chakraborty0866d962010-08-26 14:02:52 +00001015 err = qlcnic_check_eswitch_mode(adapter);
1016 if (err) {
1017 dev_err(&adapter->pdev->dev,
1018 "Memory allocation failed for eswitch\n");
1019 goto err_out;
1020 }
1021 qlcnic_dev_set_npar_ready(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001022 adapter->need_fw_reset = 0;
1023
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001024 qlcnic_release_firmware(adapter);
1025 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001026
1027err_out:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001028 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
1029 dev_err(&adapter->pdev->dev, "Device state set to failed\n");
Anirban Chakraborty0866d962010-08-26 14:02:52 +00001030
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001031 qlcnic_release_firmware(adapter);
1032 return err;
1033}
1034
1035static int
1036qlcnic_request_irq(struct qlcnic_adapter *adapter)
1037{
1038 irq_handler_t handler;
1039 struct qlcnic_host_sds_ring *sds_ring;
1040 int err, ring;
1041
1042 unsigned long flags = 0;
1043 struct net_device *netdev = adapter->netdev;
1044 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
1045
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001046 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1047 handler = qlcnic_tmp_intr;
1048 if (!QLCNIC_IS_MSI_FAMILY(adapter))
1049 flags |= IRQF_SHARED;
1050
1051 } else {
1052 if (adapter->flags & QLCNIC_MSIX_ENABLED)
1053 handler = qlcnic_msix_intr;
1054 else if (adapter->flags & QLCNIC_MSI_ENABLED)
1055 handler = qlcnic_msi_intr;
1056 else {
1057 flags |= IRQF_SHARED;
1058 handler = qlcnic_intr;
1059 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001060 }
1061 adapter->irq = netdev->irq;
1062
1063 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1064 sds_ring = &recv_ctx->sds_rings[ring];
1065 sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
1066 err = request_irq(sds_ring->irq, handler,
1067 flags, sds_ring->name, sds_ring);
1068 if (err)
1069 return err;
1070 }
1071
1072 return 0;
1073}
1074
1075static void
1076qlcnic_free_irq(struct qlcnic_adapter *adapter)
1077{
1078 int ring;
1079 struct qlcnic_host_sds_ring *sds_ring;
1080
1081 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
1082
1083 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1084 sds_ring = &recv_ctx->sds_rings[ring];
1085 free_irq(sds_ring->irq, sds_ring);
1086 }
1087}
1088
1089static void
1090qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter)
1091{
1092 adapter->coal.flags = QLCNIC_INTR_DEFAULT;
1093 adapter->coal.normal.data.rx_time_us =
1094 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
1095 adapter->coal.normal.data.rx_packets =
1096 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1097 adapter->coal.normal.data.tx_time_us =
1098 QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US;
1099 adapter->coal.normal.data.tx_packets =
1100 QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS;
1101}
1102
1103static int
1104__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
1105{
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001106 int ring;
1107 struct qlcnic_host_rds_ring *rds_ring;
1108
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001109 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1110 return -EIO;
1111
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001112 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
1113 return 0;
Rajesh Borundia0325d692010-08-19 05:08:26 +00001114 if (qlcnic_set_eswitch_port_config(adapter))
1115 return -EIO;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001116
1117 if (qlcnic_fw_create_ctx(adapter))
1118 return -EIO;
1119
1120 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1121 rds_ring = &adapter->recv_ctx.rds_rings[ring];
1122 qlcnic_post_rx_buffers(adapter, ring, rds_ring);
1123 }
1124
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001125 qlcnic_set_multi(netdev);
1126 qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
1127
1128 adapter->ahw.linkup = 0;
1129
1130 if (adapter->max_sds_rings > 1)
1131 qlcnic_config_rss(adapter, 1);
1132
1133 qlcnic_config_intr_coalesce(adapter);
1134
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001135 if (netdev->features & NETIF_F_LRO)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001136 qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
1137
1138 qlcnic_napi_enable(adapter);
1139
1140 qlcnic_linkevent_request(adapter, 1);
1141
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00001142 adapter->reset_context = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001143 set_bit(__QLCNIC_DEV_UP, &adapter->state);
1144 return 0;
1145}
1146
1147/* Usage: During resume and firmware recovery module.*/
1148
1149static int
1150qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
1151{
1152 int err = 0;
1153
1154 rtnl_lock();
1155 if (netif_running(netdev))
1156 err = __qlcnic_up(adapter, netdev);
1157 rtnl_unlock();
1158
1159 return err;
1160}
1161
1162static void
1163__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
1164{
1165 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1166 return;
1167
1168 if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))
1169 return;
1170
1171 smp_mb();
1172 spin_lock(&adapter->tx_clean_lock);
1173 netif_carrier_off(netdev);
1174 netif_tx_disable(netdev);
1175
1176 qlcnic_free_mac_list(adapter);
1177
1178 qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
1179
1180 qlcnic_napi_disable(adapter);
1181
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001182 qlcnic_fw_destroy_ctx(adapter);
1183
1184 qlcnic_reset_rx_buffers_list(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001185 qlcnic_release_tx_buffers(adapter);
1186 spin_unlock(&adapter->tx_clean_lock);
1187}
1188
1189/* Usage: During suspend and firmware recovery module */
1190
1191static void
1192qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
1193{
1194 rtnl_lock();
1195 if (netif_running(netdev))
1196 __qlcnic_down(adapter, netdev);
1197 rtnl_unlock();
1198
1199}
1200
1201static int
1202qlcnic_attach(struct qlcnic_adapter *adapter)
1203{
1204 struct net_device *netdev = adapter->netdev;
1205 struct pci_dev *pdev = adapter->pdev;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001206 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001207
1208 if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
1209 return 0;
1210
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001211 err = qlcnic_napi_add(adapter, netdev);
1212 if (err)
1213 return err;
1214
1215 err = qlcnic_alloc_sw_resources(adapter);
1216 if (err) {
1217 dev_err(&pdev->dev, "Error in setting sw resources\n");
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001218 goto err_out_napi_del;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001219 }
1220
1221 err = qlcnic_alloc_hw_resources(adapter);
1222 if (err) {
1223 dev_err(&pdev->dev, "Error in setting hw resources\n");
1224 goto err_out_free_sw;
1225 }
1226
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001227 err = qlcnic_request_irq(adapter);
1228 if (err) {
1229 dev_err(&pdev->dev, "failed to setup interrupt\n");
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001230 goto err_out_free_hw;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001231 }
1232
1233 qlcnic_init_coalesce_defaults(adapter);
1234
1235 qlcnic_create_sysfs_entries(adapter);
1236
1237 adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
1238 return 0;
1239
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001240err_out_free_hw:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001241 qlcnic_free_hw_resources(adapter);
1242err_out_free_sw:
1243 qlcnic_free_sw_resources(adapter);
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001244err_out_napi_del:
1245 qlcnic_napi_del(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001246 return err;
1247}
1248
1249static void
1250qlcnic_detach(struct qlcnic_adapter *adapter)
1251{
1252 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1253 return;
1254
1255 qlcnic_remove_sysfs_entries(adapter);
1256
1257 qlcnic_free_hw_resources(adapter);
1258 qlcnic_release_rx_buffers(adapter);
1259 qlcnic_free_irq(adapter);
1260 qlcnic_napi_del(adapter);
1261 qlcnic_free_sw_resources(adapter);
1262
1263 adapter->is_up = 0;
1264}
1265
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001266void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
1267{
1268 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1269 struct qlcnic_host_sds_ring *sds_ring;
1270 int ring;
1271
Sucheta Chakraborty78ad3892010-05-17 01:22:12 +00001272 clear_bit(__QLCNIC_DEV_UP, &adapter->state);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001273 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1274 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1275 sds_ring = &adapter->recv_ctx.sds_rings[ring];
1276 qlcnic_disable_int(sds_ring);
1277 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001278 }
1279
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001280 qlcnic_fw_destroy_ctx(adapter);
1281
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001282 qlcnic_detach(adapter);
1283
1284 adapter->diag_test = 0;
1285 adapter->max_sds_rings = max_sds_rings;
1286
1287 if (qlcnic_attach(adapter))
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001288 goto out;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001289
1290 if (netif_running(netdev))
1291 __qlcnic_up(adapter, netdev);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001292out:
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001293 netif_device_attach(netdev);
1294}
1295
1296int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
1297{
1298 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1299 struct qlcnic_host_sds_ring *sds_ring;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001300 struct qlcnic_host_rds_ring *rds_ring;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001301 int ring;
1302 int ret;
1303
1304 netif_device_detach(netdev);
1305
1306 if (netif_running(netdev))
1307 __qlcnic_down(adapter, netdev);
1308
1309 qlcnic_detach(adapter);
1310
1311 adapter->max_sds_rings = 1;
1312 adapter->diag_test = test;
1313
1314 ret = qlcnic_attach(adapter);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001315 if (ret) {
1316 netif_device_attach(netdev);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001317 return ret;
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001318 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001319
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001320 ret = qlcnic_fw_create_ctx(adapter);
1321 if (ret) {
1322 qlcnic_detach(adapter);
Sony Chacko57e46242010-07-24 18:32:18 +00001323 netif_device_attach(netdev);
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001324 return ret;
1325 }
1326
1327 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1328 rds_ring = &adapter->recv_ctx.rds_rings[ring];
1329 qlcnic_post_rx_buffers(adapter, ring, rds_ring);
1330 }
1331
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001332 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1333 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1334 sds_ring = &adapter->recv_ctx.sds_rings[ring];
1335 qlcnic_enable_int(sds_ring);
1336 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001337 }
Sucheta Chakraborty78ad3892010-05-17 01:22:12 +00001338 set_bit(__QLCNIC_DEV_UP, &adapter->state);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001339
1340 return 0;
1341}
1342
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00001343/* Reset context in hardware only */
1344static int
1345qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
1346{
1347 struct net_device *netdev = adapter->netdev;
1348
1349 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1350 return -EBUSY;
1351
1352 netif_device_detach(netdev);
1353
1354 qlcnic_down(adapter, netdev);
1355
1356 qlcnic_up(adapter, netdev);
1357
1358 netif_device_attach(netdev);
1359
1360 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1361 return 0;
1362}
1363
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001364int
1365qlcnic_reset_context(struct qlcnic_adapter *adapter)
1366{
1367 int err = 0;
1368 struct net_device *netdev = adapter->netdev;
1369
1370 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1371 return -EBUSY;
1372
1373 if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) {
1374
1375 netif_device_detach(netdev);
1376
1377 if (netif_running(netdev))
1378 __qlcnic_down(adapter, netdev);
1379
1380 qlcnic_detach(adapter);
1381
1382 if (netif_running(netdev)) {
1383 err = qlcnic_attach(adapter);
1384 if (!err)
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001385 __qlcnic_up(adapter, netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001386 }
1387
1388 netif_device_attach(netdev);
1389 }
1390
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001391 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1392 return err;
1393}
1394
1395static int
1396qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001397 struct net_device *netdev, u8 pci_using_dac)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001398{
1399 int err;
1400 struct pci_dev *pdev = adapter->pdev;
1401
1402 adapter->rx_csum = 1;
1403 adapter->mc_enabled = 0;
1404 adapter->max_mc_count = 38;
1405
1406 netdev->netdev_ops = &qlcnic_netdev_ops;
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00001407 netdev->watchdog_timeo = 5*HZ;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001408
1409 qlcnic_change_mtu(netdev, netdev->mtu);
1410
1411 SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
1412
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001413 netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +00001414 NETIF_F_IPV6_CSUM | NETIF_F_GRO);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001415 netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +00001416 NETIF_F_IPV6_CSUM);
1417
1418 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
1419 netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
1420 netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
1421 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001422
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001423 if (pci_using_dac) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001424 netdev->features |= NETIF_F_HIGHDMA;
1425 netdev->vlan_features |= NETIF_F_HIGHDMA;
1426 }
1427
1428 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
1429 netdev->features |= (NETIF_F_HW_VLAN_TX);
1430
1431 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
1432 netdev->features |= NETIF_F_LRO;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001433 netdev->irq = adapter->msix_entries[0].vector;
1434
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001435 netif_carrier_off(netdev);
1436 netif_stop_queue(netdev);
1437
1438 err = register_netdev(netdev);
1439 if (err) {
1440 dev_err(&pdev->dev, "failed to register net device\n");
1441 return err;
1442 }
1443
1444 return 0;
1445}
1446
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001447static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
1448{
1449 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
1450 !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
1451 *pci_using_dac = 1;
1452 else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) &&
1453 !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
1454 *pci_using_dac = 0;
1455 else {
1456 dev_err(&pdev->dev, "Unable to set DMA mask, aborting\n");
1457 return -EIO;
1458 }
1459
1460 return 0;
1461}
1462
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001463static int __devinit
1464qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1465{
1466 struct net_device *netdev = NULL;
1467 struct qlcnic_adapter *adapter = NULL;
1468 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001469 uint8_t revision_id;
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001470 uint8_t pci_using_dac;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001471
1472 err = pci_enable_device(pdev);
1473 if (err)
1474 return err;
1475
1476 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
1477 err = -ENODEV;
1478 goto err_out_disable_pdev;
1479 }
1480
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001481 err = qlcnic_set_dma_mask(pdev, &pci_using_dac);
1482 if (err)
1483 goto err_out_disable_pdev;
1484
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001485 err = pci_request_regions(pdev, qlcnic_driver_name);
1486 if (err)
1487 goto err_out_disable_pdev;
1488
1489 pci_set_master(pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00001490 pci_enable_pcie_error_reporting(pdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001491
1492 netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
1493 if (!netdev) {
1494 dev_err(&pdev->dev, "failed to allocate net_device\n");
1495 err = -ENOMEM;
1496 goto err_out_free_res;
1497 }
1498
1499 SET_NETDEV_DEV(netdev, &pdev->dev);
1500
1501 adapter = netdev_priv(netdev);
1502 adapter->netdev = netdev;
1503 adapter->pdev = pdev;
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00001504 adapter->dev_rst_time = jiffies;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001505
1506 revision_id = pdev->revision;
1507 adapter->ahw.revision_id = revision_id;
1508
1509 rwlock_init(&adapter->ahw.crb_lock);
1510 mutex_init(&adapter->ahw.mem_lock);
1511
1512 spin_lock_init(&adapter->tx_clean_lock);
1513 INIT_LIST_HEAD(&adapter->mac_list);
1514
1515 err = qlcnic_setup_pci_map(adapter);
1516 if (err)
1517 goto err_out_free_netdev;
1518
1519 /* This will be reset for mezz cards */
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001520 adapter->portnum = adapter->ahw.pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001521
1522 err = qlcnic_get_board_info(adapter);
1523 if (err) {
1524 dev_err(&pdev->dev, "Error getting board config info.\n");
1525 goto err_out_iounmap;
1526 }
1527
Sony Chacko8cfdce02010-08-26 14:02:41 +00001528 err = qlcnic_setup_idc_param(adapter);
1529 if (err)
Sucheta Chakrabortyb3a24642010-05-13 03:07:48 +00001530 goto err_out_iounmap;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001531
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00001532 err = adapter->nic_ops->start_firmware(adapter);
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001533 if (err) {
1534 dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001535 goto err_out_decr_ref;
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001536 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001537
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001538 qlcnic_clear_stats(adapter);
1539
1540 qlcnic_setup_intr(adapter);
1541
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001542 err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001543 if (err)
1544 goto err_out_disable_msi;
1545
1546 pci_set_drvdata(pdev, adapter);
1547
1548 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
1549
1550 switch (adapter->ahw.port_type) {
1551 case QLCNIC_GBE:
1552 dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
1553 adapter->netdev->name);
1554 break;
1555 case QLCNIC_XGBE:
1556 dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
1557 adapter->netdev->name);
1558 break;
1559 }
1560
1561 qlcnic_create_diag_entries(adapter);
1562
1563 return 0;
1564
1565err_out_disable_msi:
1566 qlcnic_teardown_intr(adapter);
1567
1568err_out_decr_ref:
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00001569 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001570
1571err_out_iounmap:
1572 qlcnic_cleanup_pci_map(adapter);
1573
1574err_out_free_netdev:
1575 free_netdev(netdev);
1576
1577err_out_free_res:
1578 pci_release_regions(pdev);
1579
1580err_out_disable_pdev:
1581 pci_set_drvdata(pdev, NULL);
1582 pci_disable_device(pdev);
1583 return err;
1584}
1585
1586static void __devexit qlcnic_remove(struct pci_dev *pdev)
1587{
1588 struct qlcnic_adapter *adapter;
1589 struct net_device *netdev;
1590
1591 adapter = pci_get_drvdata(pdev);
1592 if (adapter == NULL)
1593 return;
1594
1595 netdev = adapter->netdev;
1596
1597 qlcnic_cancel_fw_work(adapter);
1598
1599 unregister_netdev(netdev);
1600
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001601 qlcnic_detach(adapter);
1602
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001603 if (adapter->npars != NULL)
1604 kfree(adapter->npars);
1605 if (adapter->eswitch != NULL)
1606 kfree(adapter->eswitch);
1607
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00001608 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001609
1610 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1611
1612 qlcnic_teardown_intr(adapter);
1613
1614 qlcnic_remove_diag_entries(adapter);
1615
1616 qlcnic_cleanup_pci_map(adapter);
1617
1618 qlcnic_release_firmware(adapter);
1619
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00001620 pci_disable_pcie_error_reporting(pdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001621 pci_release_regions(pdev);
1622 pci_disable_device(pdev);
1623 pci_set_drvdata(pdev, NULL);
1624
1625 free_netdev(netdev);
1626}
1627static int __qlcnic_shutdown(struct pci_dev *pdev)
1628{
1629 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
1630 struct net_device *netdev = adapter->netdev;
1631 int retval;
1632
1633 netif_device_detach(netdev);
1634
1635 qlcnic_cancel_fw_work(adapter);
1636
1637 if (netif_running(netdev))
1638 qlcnic_down(adapter, netdev);
1639
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00001640 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001641
1642 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1643
1644 retval = pci_save_state(pdev);
1645 if (retval)
1646 return retval;
1647
1648 if (qlcnic_wol_supported(adapter)) {
1649 pci_enable_wake(pdev, PCI_D3cold, 1);
1650 pci_enable_wake(pdev, PCI_D3hot, 1);
1651 }
1652
1653 return 0;
1654}
1655
1656static void qlcnic_shutdown(struct pci_dev *pdev)
1657{
1658 if (__qlcnic_shutdown(pdev))
1659 return;
1660
1661 pci_disable_device(pdev);
1662}
1663
1664#ifdef CONFIG_PM
1665static int
1666qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
1667{
1668 int retval;
1669
1670 retval = __qlcnic_shutdown(pdev);
1671 if (retval)
1672 return retval;
1673
1674 pci_set_power_state(pdev, pci_choose_state(pdev, state));
1675 return 0;
1676}
1677
1678static int
1679qlcnic_resume(struct pci_dev *pdev)
1680{
1681 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
1682 struct net_device *netdev = adapter->netdev;
1683 int err;
1684
1685 err = pci_enable_device(pdev);
1686 if (err)
1687 return err;
1688
1689 pci_set_power_state(pdev, PCI_D0);
1690 pci_set_master(pdev);
1691 pci_restore_state(pdev);
1692
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00001693 err = adapter->nic_ops->start_firmware(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001694 if (err) {
1695 dev_err(&pdev->dev, "failed to start firmware\n");
1696 return err;
1697 }
1698
1699 if (netif_running(netdev)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001700 err = qlcnic_up(adapter, netdev);
1701 if (err)
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00001702 goto done;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001703
1704 qlcnic_config_indev_addr(netdev, NETDEV_UP);
1705 }
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00001706done:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001707 netif_device_attach(netdev);
1708 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
1709 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001710}
1711#endif
1712
1713static int qlcnic_open(struct net_device *netdev)
1714{
1715 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1716 int err;
1717
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001718 err = qlcnic_attach(adapter);
1719 if (err)
1720 return err;
1721
1722 err = __qlcnic_up(adapter, netdev);
1723 if (err)
1724 goto err_out;
1725
1726 netif_start_queue(netdev);
1727
1728 return 0;
1729
1730err_out:
1731 qlcnic_detach(adapter);
1732 return err;
1733}
1734
1735/*
1736 * qlcnic_close - Disables a network interface entry point
1737 */
1738static int qlcnic_close(struct net_device *netdev)
1739{
1740 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1741
1742 __qlcnic_down(adapter, netdev);
1743 return 0;
1744}
1745
1746static void
1747qlcnic_tso_check(struct net_device *netdev,
1748 struct qlcnic_host_tx_ring *tx_ring,
1749 struct cmd_desc_type0 *first_desc,
1750 struct sk_buff *skb)
1751{
1752 u8 opcode = TX_ETHER_PKT;
1753 __be16 protocol = skb->protocol;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001754 u16 flags = 0;
1755 int copied, offset, copy_len, hdr_len = 0, tso = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001756 struct cmd_desc_type0 *hwdesc;
1757 struct vlan_ethhdr *vh;
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00001758 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001759 u32 producer = tx_ring->producer;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001760 int vlan_oob = first_desc->flags_opcode & cpu_to_le16(FLAGS_VLAN_OOB);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001761
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001762 if (*(skb->data) & BIT_0) {
1763 flags |= BIT_0;
1764 memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
1765 }
1766
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001767 if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
1768 skb_shinfo(skb)->gso_size > 0) {
1769
1770 hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1771
1772 first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
1773 first_desc->total_hdr_length = hdr_len;
1774 if (vlan_oob) {
1775 first_desc->total_hdr_length += VLAN_HLEN;
1776 first_desc->tcp_hdr_offset = VLAN_HLEN;
1777 first_desc->ip_hdr_offset = VLAN_HLEN;
1778 /* Only in case of TSO on vlan device */
1779 flags |= FLAGS_VLAN_TAGGED;
1780 }
1781
1782 opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
1783 TX_TCP_LSO6 : TX_TCP_LSO;
1784 tso = 1;
1785
1786 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
1787 u8 l4proto;
1788
1789 if (protocol == cpu_to_be16(ETH_P_IP)) {
1790 l4proto = ip_hdr(skb)->protocol;
1791
1792 if (l4proto == IPPROTO_TCP)
1793 opcode = TX_TCP_PKT;
1794 else if (l4proto == IPPROTO_UDP)
1795 opcode = TX_UDP_PKT;
1796 } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
1797 l4proto = ipv6_hdr(skb)->nexthdr;
1798
1799 if (l4proto == IPPROTO_TCP)
1800 opcode = TX_TCPV6_PKT;
1801 else if (l4proto == IPPROTO_UDP)
1802 opcode = TX_UDPV6_PKT;
1803 }
1804 }
1805
1806 first_desc->tcp_hdr_offset += skb_transport_offset(skb);
1807 first_desc->ip_hdr_offset += skb_network_offset(skb);
1808 qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
1809
1810 if (!tso)
1811 return;
1812
1813 /* For LSO, we need to copy the MAC/IP/TCP headers into
1814 * the descriptor ring
1815 */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001816 copied = 0;
1817 offset = 2;
1818
1819 if (vlan_oob) {
1820 /* Create a TSO vlan header template for firmware */
1821
1822 hwdesc = &tx_ring->desc_head[producer];
1823 tx_ring->cmd_buf_arr[producer].skb = NULL;
1824
1825 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
1826 hdr_len + VLAN_HLEN);
1827
1828 vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
1829 skb_copy_from_linear_data(skb, vh, 12);
1830 vh->h_vlan_proto = htons(ETH_P_8021Q);
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001831 vh->h_vlan_TCI = htons(first_desc->vlan_TCI);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001832 skb_copy_from_linear_data_offset(skb, 12,
1833 (char *)vh + 16, copy_len - 16);
1834
1835 copied = copy_len - VLAN_HLEN;
1836 offset = 0;
1837
1838 producer = get_next_index(producer, tx_ring->num_desc);
1839 }
1840
1841 while (copied < hdr_len) {
1842
1843 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
1844 (hdr_len - copied));
1845
1846 hwdesc = &tx_ring->desc_head[producer];
1847 tx_ring->cmd_buf_arr[producer].skb = NULL;
1848
1849 skb_copy_from_linear_data_offset(skb, copied,
1850 (char *)hwdesc + offset, copy_len);
1851
1852 copied += copy_len;
1853 offset = 0;
1854
1855 producer = get_next_index(producer, tx_ring->num_desc);
1856 }
1857
1858 tx_ring->producer = producer;
1859 barrier();
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00001860 adapter->stats.lso_frames++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001861}
1862
1863static int
1864qlcnic_map_tx_skb(struct pci_dev *pdev,
1865 struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
1866{
1867 struct qlcnic_skb_frag *nf;
1868 struct skb_frag_struct *frag;
1869 int i, nr_frags;
1870 dma_addr_t map;
1871
1872 nr_frags = skb_shinfo(skb)->nr_frags;
1873 nf = &pbuf->frag_array[0];
1874
1875 map = pci_map_single(pdev, skb->data,
1876 skb_headlen(skb), PCI_DMA_TODEVICE);
1877 if (pci_dma_mapping_error(pdev, map))
1878 goto out_err;
1879
1880 nf->dma = map;
1881 nf->length = skb_headlen(skb);
1882
1883 for (i = 0; i < nr_frags; i++) {
1884 frag = &skb_shinfo(skb)->frags[i];
1885 nf = &pbuf->frag_array[i+1];
1886
1887 map = pci_map_page(pdev, frag->page, frag->page_offset,
1888 frag->size, PCI_DMA_TODEVICE);
1889 if (pci_dma_mapping_error(pdev, map))
1890 goto unwind;
1891
1892 nf->dma = map;
1893 nf->length = frag->size;
1894 }
1895
1896 return 0;
1897
1898unwind:
1899 while (--i >= 0) {
1900 nf = &pbuf->frag_array[i+1];
1901 pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
1902 }
1903
1904 nf = &pbuf->frag_array[0];
1905 pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
1906
1907out_err:
1908 return -ENOMEM;
1909}
1910
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001911static int
1912qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter,
1913 struct sk_buff *skb,
1914 struct cmd_desc_type0 *first_desc)
1915{
1916 u8 opcode = 0;
1917 u16 flags = 0;
1918 __be16 protocol = skb->protocol;
1919 struct vlan_ethhdr *vh;
1920
1921 if (protocol == cpu_to_be16(ETH_P_8021Q)) {
1922 vh = (struct vlan_ethhdr *)skb->data;
1923 protocol = vh->h_vlan_encapsulated_proto;
1924 flags = FLAGS_VLAN_TAGGED;
1925 qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI));
1926 } else if (vlan_tx_tag_present(skb)) {
1927 flags = FLAGS_VLAN_OOB;
1928 qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb));
1929 }
1930 if (unlikely(adapter->pvid)) {
1931 if (first_desc->vlan_TCI &&
1932 !(adapter->flags & QLCNIC_TAGGING_ENABLED))
1933 return -EIO;
1934 if (first_desc->vlan_TCI &&
1935 (adapter->flags & QLCNIC_TAGGING_ENABLED))
1936 goto set_flags;
1937
1938 flags = FLAGS_VLAN_OOB;
1939 qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid);
1940 }
1941set_flags:
1942 qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
1943 return 0;
1944}
1945
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001946static inline void
1947qlcnic_clear_cmddesc(u64 *desc)
1948{
1949 desc[0] = 0ULL;
1950 desc[2] = 0ULL;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001951 desc[7] = 0ULL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001952}
1953
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001954netdev_tx_t
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001955qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
1956{
1957 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1958 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
1959 struct qlcnic_cmd_buffer *pbuf;
1960 struct qlcnic_skb_frag *buffrag;
1961 struct cmd_desc_type0 *hwdesc, *first_desc;
1962 struct pci_dev *pdev;
1963 int i, k;
1964
1965 u32 producer;
1966 int frag_count, no_of_desc;
1967 u32 num_txd = tx_ring->num_desc;
1968
Amit Kumar Salecha780ab792010-04-22 02:51:41 +00001969 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
1970 netif_stop_queue(netdev);
1971 return NETDEV_TX_BUSY;
1972 }
1973
Sony Chackofe4d4342010-08-19 05:08:27 +00001974 if (adapter->flags & QLCNIC_MACSPOOF) {
1975 if (compare_ether_addr(eth_hdr(skb)->h_source,
1976 adapter->mac_addr))
1977 goto drop_packet;
1978 }
1979
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001980 frag_count = skb_shinfo(skb)->nr_frags + 1;
1981
1982 /* 4 fragments per cmd des */
1983 no_of_desc = (frag_count + 3) >> 2;
1984
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00001985 if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001986 netif_stop_queue(netdev);
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00001987 smp_mb();
1988 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
1989 netif_start_queue(netdev);
1990 else {
1991 adapter->stats.xmit_off++;
1992 return NETDEV_TX_BUSY;
1993 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001994 }
1995
1996 producer = tx_ring->producer;
1997 pbuf = &tx_ring->cmd_buf_arr[producer];
1998
1999 pdev = adapter->pdev;
2000
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00002001 first_desc = hwdesc = &tx_ring->desc_head[producer];
2002 qlcnic_clear_cmddesc((u64 *)hwdesc);
2003
2004 if (qlcnic_check_tx_tagging(adapter, skb, first_desc))
2005 goto drop_packet;
2006
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00002007 if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
2008 adapter->stats.tx_dma_map_error++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002009 goto drop_packet;
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00002010 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002011
2012 pbuf->skb = skb;
2013 pbuf->frag_count = frag_count;
2014
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002015 qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
2016 qlcnic_set_tx_port(first_desc, adapter->portnum);
2017
2018 for (i = 0; i < frag_count; i++) {
2019
2020 k = i % 4;
2021
2022 if ((k == 0) && (i > 0)) {
2023 /* move to next desc.*/
2024 producer = get_next_index(producer, num_txd);
2025 hwdesc = &tx_ring->desc_head[producer];
2026 qlcnic_clear_cmddesc((u64 *)hwdesc);
2027 tx_ring->cmd_buf_arr[producer].skb = NULL;
2028 }
2029
2030 buffrag = &pbuf->frag_array[i];
2031
2032 hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
2033 switch (k) {
2034 case 0:
2035 hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
2036 break;
2037 case 1:
2038 hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
2039 break;
2040 case 2:
2041 hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
2042 break;
2043 case 3:
2044 hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
2045 break;
2046 }
2047 }
2048
2049 tx_ring->producer = get_next_index(producer, num_txd);
2050
2051 qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
2052
2053 qlcnic_update_cmd_producer(adapter, tx_ring);
2054
2055 adapter->stats.txbytes += skb->len;
2056 adapter->stats.xmitcalled++;
2057
2058 return NETDEV_TX_OK;
2059
2060drop_packet:
2061 adapter->stats.txdropped++;
2062 dev_kfree_skb_any(skb);
2063 return NETDEV_TX_OK;
2064}
2065
2066static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
2067{
2068 struct net_device *netdev = adapter->netdev;
2069 u32 temp, temp_state, temp_val;
2070 int rv = 0;
2071
2072 temp = QLCRD32(adapter, CRB_TEMP_STATE);
2073
2074 temp_state = qlcnic_get_temp_state(temp);
2075 temp_val = qlcnic_get_temp_val(temp);
2076
2077 if (temp_state == QLCNIC_TEMP_PANIC) {
2078 dev_err(&netdev->dev,
2079 "Device temperature %d degrees C exceeds"
2080 " maximum allowed. Hardware has been shut down.\n",
2081 temp_val);
2082 rv = 1;
2083 } else if (temp_state == QLCNIC_TEMP_WARN) {
2084 if (adapter->temp == QLCNIC_TEMP_NORMAL) {
2085 dev_err(&netdev->dev,
2086 "Device temperature %d degrees C "
2087 "exceeds operating range."
2088 " Immediate action needed.\n",
2089 temp_val);
2090 }
2091 } else {
2092 if (adapter->temp == QLCNIC_TEMP_WARN) {
2093 dev_info(&netdev->dev,
2094 "Device temperature is now %d degrees C"
2095 " in normal range.\n", temp_val);
2096 }
2097 }
2098 adapter->temp = temp_state;
2099 return rv;
2100}
2101
2102void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
2103{
2104 struct net_device *netdev = adapter->netdev;
2105
2106 if (adapter->ahw.linkup && !linkup) {
Sony Chacko69324272010-08-17 00:34:23 +00002107 netdev_info(netdev, "NIC Link is down\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002108 adapter->ahw.linkup = 0;
2109 if (netif_running(netdev)) {
2110 netif_carrier_off(netdev);
2111 netif_stop_queue(netdev);
2112 }
2113 } else if (!adapter->ahw.linkup && linkup) {
Sony Chacko69324272010-08-17 00:34:23 +00002114 netdev_info(netdev, "NIC Link is up\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002115 adapter->ahw.linkup = 1;
2116 if (netif_running(netdev)) {
2117 netif_carrier_on(netdev);
2118 netif_wake_queue(netdev);
2119 }
2120 }
2121}
2122
2123static void qlcnic_tx_timeout(struct net_device *netdev)
2124{
2125 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2126
2127 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
2128 return;
2129
2130 dev_err(&netdev->dev, "transmit timeout, resetting.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002131
2132 if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002133 adapter->need_fw_reset = 1;
2134 else
2135 adapter->reset_context = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002136}
2137
2138static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
2139{
2140 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2141 struct net_device_stats *stats = &netdev->stats;
2142
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002143 stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
2144 stats->tx_packets = adapter->stats.xmitfinished;
Sucheta Chakraborty7e382592010-05-17 01:22:10 +00002145 stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002146 stats->tx_bytes = adapter->stats.txbytes;
2147 stats->rx_dropped = adapter->stats.rxdropped;
2148 stats->tx_dropped = adapter->stats.txdropped;
2149
2150 return stats;
2151}
2152
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00002153static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002154{
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002155 u32 status;
2156
2157 status = readl(adapter->isr_int_vec);
2158
2159 if (!(status & adapter->int_vec_bit))
2160 return IRQ_NONE;
2161
2162 /* check interrupt state machine, to be sure */
2163 status = readl(adapter->crb_int_state_reg);
2164 if (!ISR_LEGACY_INT_TRIGGERED(status))
2165 return IRQ_NONE;
2166
2167 writel(0xffffffff, adapter->tgt_status_reg);
2168 /* read twice to ensure write is flushed */
2169 readl(adapter->isr_int_vec);
2170 readl(adapter->isr_int_vec);
2171
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00002172 return IRQ_HANDLED;
2173}
2174
2175static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
2176{
2177 struct qlcnic_host_sds_ring *sds_ring = data;
2178 struct qlcnic_adapter *adapter = sds_ring->adapter;
2179
2180 if (adapter->flags & QLCNIC_MSIX_ENABLED)
2181 goto done;
2182 else if (adapter->flags & QLCNIC_MSI_ENABLED) {
2183 writel(0xffffffff, adapter->tgt_status_reg);
2184 goto done;
2185 }
2186
2187 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
2188 return IRQ_NONE;
2189
2190done:
2191 adapter->diag_cnt++;
2192 qlcnic_enable_int(sds_ring);
2193 return IRQ_HANDLED;
2194}
2195
2196static irqreturn_t qlcnic_intr(int irq, void *data)
2197{
2198 struct qlcnic_host_sds_ring *sds_ring = data;
2199 struct qlcnic_adapter *adapter = sds_ring->adapter;
2200
2201 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
2202 return IRQ_NONE;
2203
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002204 napi_schedule(&sds_ring->napi);
2205
2206 return IRQ_HANDLED;
2207}
2208
2209static irqreturn_t qlcnic_msi_intr(int irq, void *data)
2210{
2211 struct qlcnic_host_sds_ring *sds_ring = data;
2212 struct qlcnic_adapter *adapter = sds_ring->adapter;
2213
2214 /* clear interrupt */
2215 writel(0xffffffff, adapter->tgt_status_reg);
2216
2217 napi_schedule(&sds_ring->napi);
2218 return IRQ_HANDLED;
2219}
2220
2221static irqreturn_t qlcnic_msix_intr(int irq, void *data)
2222{
2223 struct qlcnic_host_sds_ring *sds_ring = data;
2224
2225 napi_schedule(&sds_ring->napi);
2226 return IRQ_HANDLED;
2227}
2228
2229static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
2230{
2231 u32 sw_consumer, hw_consumer;
2232 int count = 0, i;
2233 struct qlcnic_cmd_buffer *buffer;
2234 struct pci_dev *pdev = adapter->pdev;
2235 struct net_device *netdev = adapter->netdev;
2236 struct qlcnic_skb_frag *frag;
2237 int done;
2238 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
2239
2240 if (!spin_trylock(&adapter->tx_clean_lock))
2241 return 1;
2242
2243 sw_consumer = tx_ring->sw_consumer;
2244 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2245
2246 while (sw_consumer != hw_consumer) {
2247 buffer = &tx_ring->cmd_buf_arr[sw_consumer];
2248 if (buffer->skb) {
2249 frag = &buffer->frag_array[0];
2250 pci_unmap_single(pdev, frag->dma, frag->length,
2251 PCI_DMA_TODEVICE);
2252 frag->dma = 0ULL;
2253 for (i = 1; i < buffer->frag_count; i++) {
2254 frag++;
2255 pci_unmap_page(pdev, frag->dma, frag->length,
2256 PCI_DMA_TODEVICE);
2257 frag->dma = 0ULL;
2258 }
2259
2260 adapter->stats.xmitfinished++;
2261 dev_kfree_skb_any(buffer->skb);
2262 buffer->skb = NULL;
2263 }
2264
2265 sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
2266 if (++count >= MAX_STATUS_HANDLE)
2267 break;
2268 }
2269
2270 if (count && netif_running(netdev)) {
2271 tx_ring->sw_consumer = sw_consumer;
2272
2273 smp_mb();
2274
2275 if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002276 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
2277 netif_wake_queue(netdev);
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00002278 adapter->stats.xmit_on++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002279 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002280 }
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002281 adapter->tx_timeo_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002282 }
2283 /*
2284 * If everything is freed up to consumer then check if the ring is full
2285 * If the ring is full then check if more needs to be freed and
2286 * schedule the call back again.
2287 *
2288 * This happens when there are 2 CPUs. One could be freeing and the
2289 * other filling it. If the ring is full when we get out of here and
2290 * the card has already interrupted the host then the host can miss the
2291 * interrupt.
2292 *
2293 * There is still a possible race condition and the host could miss an
2294 * interrupt. The card has to take care of this.
2295 */
2296 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2297 done = (sw_consumer == hw_consumer);
2298 spin_unlock(&adapter->tx_clean_lock);
2299
2300 return done;
2301}
2302
2303static int qlcnic_poll(struct napi_struct *napi, int budget)
2304{
2305 struct qlcnic_host_sds_ring *sds_ring =
2306 container_of(napi, struct qlcnic_host_sds_ring, napi);
2307
2308 struct qlcnic_adapter *adapter = sds_ring->adapter;
2309
2310 int tx_complete;
2311 int work_done;
2312
2313 tx_complete = qlcnic_process_cmd_ring(adapter);
2314
2315 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2316
2317 if ((work_done < budget) && tx_complete) {
2318 napi_complete(&sds_ring->napi);
2319 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2320 qlcnic_enable_int(sds_ring);
2321 }
2322
2323 return work_done;
2324}
2325
schacko8f891382010-06-17 02:56:40 +00002326static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
2327{
2328 struct qlcnic_host_sds_ring *sds_ring =
2329 container_of(napi, struct qlcnic_host_sds_ring, napi);
2330
2331 struct qlcnic_adapter *adapter = sds_ring->adapter;
2332 int work_done;
2333
2334 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2335
2336 if (work_done < budget) {
2337 napi_complete(&sds_ring->napi);
2338 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2339 qlcnic_enable_int(sds_ring);
2340 }
2341
2342 return work_done;
2343}
2344
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002345#ifdef CONFIG_NET_POLL_CONTROLLER
2346static void qlcnic_poll_controller(struct net_device *netdev)
2347{
2348 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2349 disable_irq(adapter->irq);
2350 qlcnic_intr(adapter->irq, adapter);
2351 enable_irq(adapter->irq);
2352}
2353#endif
2354
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002355static void
2356qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
2357{
2358 u32 val;
2359
2360 val = adapter->portnum & 0xf;
2361 val |= encoding << 7;
2362 val |= (jiffies - adapter->dev_rst_time) << 8;
2363
2364 QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
2365 adapter->dev_rst_time = jiffies;
2366}
2367
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002368static int
2369qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002370{
2371 u32 val;
2372
2373 WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
2374 state != QLCNIC_DEV_NEED_QUISCENT);
2375
2376 if (qlcnic_api_lock(adapter))
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002377 return -EIO;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002378
2379 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
2380
2381 if (state == QLCNIC_DEV_NEED_RESET)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002382 QLC_DEV_SET_RST_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002383 else if (state == QLCNIC_DEV_NEED_QUISCENT)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002384 QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002385
2386 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2387
2388 qlcnic_api_unlock(adapter);
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002389
2390 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002391}
2392
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002393static int
2394qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
2395{
2396 u32 val;
2397
2398 if (qlcnic_api_lock(adapter))
2399 return -EBUSY;
2400
2401 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002402 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002403 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2404
2405 qlcnic_api_unlock(adapter);
2406
2407 return 0;
2408}
2409
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002410static void
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002411qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002412{
2413 u32 val;
2414
2415 if (qlcnic_api_lock(adapter))
2416 goto err;
2417
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002418 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002419 QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002420 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002421
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002422 if (failed) {
2423 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
2424 dev_info(&adapter->pdev->dev,
2425 "Device state set to Failed. Please Reboot\n");
2426 } else if (!(val & 0x11111111))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002427 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
2428
2429 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002430 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002431 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2432
2433 qlcnic_api_unlock(adapter);
2434err:
2435 adapter->fw_fail_cnt = 0;
2436 clear_bit(__QLCNIC_START_FW, &adapter->state);
2437 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2438}
2439
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002440/* Grab api lock, before checking state */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002441static int
2442qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
2443{
2444 int act, state;
2445
2446 state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002447 act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002448
2449 if (((state & 0x11111111) == (act & 0x11111111)) ||
2450 ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
2451 return 0;
2452 else
2453 return 1;
2454}
2455
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002456static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
2457{
2458 u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
2459
2460 if (val != QLCNIC_DRV_IDC_VER) {
2461 dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
2462 " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
2463 }
2464
2465 return 0;
2466}
2467
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002468static int
2469qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
2470{
2471 u32 val, prev_state;
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002472 u8 dev_init_timeo = adapter->dev_init_timeo;
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002473 u8 portnum = adapter->portnum;
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002474 u8 ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002475
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002476 if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
2477 return 1;
2478
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002479 if (qlcnic_api_lock(adapter))
2480 return -1;
2481
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002482 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002483 if (!(val & (1 << (portnum * 4)))) {
2484 QLC_DEV_SET_REF_CNT(val, portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002485 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002486 }
2487
2488 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002489 QLCDB(adapter, HW, "Device state = %u\n", prev_state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002490
2491 switch (prev_state) {
2492 case QLCNIC_DEV_COLD:
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002493 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002494 QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002495 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002496 qlcnic_api_unlock(adapter);
2497 return 1;
2498
2499 case QLCNIC_DEV_READY:
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002500 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002501 qlcnic_api_unlock(adapter);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002502 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002503
2504 case QLCNIC_DEV_NEED_RESET:
2505 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002506 QLC_DEV_SET_RST_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002507 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2508 break;
2509
2510 case QLCNIC_DEV_NEED_QUISCENT:
2511 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002512 QLC_DEV_SET_QSCNT_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002513 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2514 break;
2515
2516 case QLCNIC_DEV_FAILED:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00002517 dev_err(&adapter->pdev->dev, "Device in failed state.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002518 qlcnic_api_unlock(adapter);
2519 return -1;
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002520
2521 case QLCNIC_DEV_INITIALIZING:
2522 case QLCNIC_DEV_QUISCENT:
2523 break;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002524 }
2525
2526 qlcnic_api_unlock(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002527
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002528 do {
2529 msleep(1000);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002530 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2531
2532 if (prev_state == QLCNIC_DEV_QUISCENT)
2533 continue;
2534 } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002535
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002536 if (!dev_init_timeo) {
2537 dev_err(&adapter->pdev->dev,
2538 "Waiting for device to initialize timeout\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002539 return -1;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002540 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002541
2542 if (qlcnic_api_lock(adapter))
2543 return -1;
2544
2545 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002546 QLC_DEV_CLR_RST_QSCNT(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002547 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2548
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002549 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002550 qlcnic_api_unlock(adapter);
2551
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002552 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002553}
2554
2555static void
2556qlcnic_fwinit_work(struct work_struct *work)
2557{
2558 struct qlcnic_adapter *adapter = container_of(work,
2559 struct qlcnic_adapter, fw_work.work);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002560 u32 dev_state = 0xf;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002561
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002562 if (qlcnic_api_lock(adapter))
2563 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002564
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002565 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2566 if (dev_state == QLCNIC_DEV_QUISCENT) {
2567 qlcnic_api_unlock(adapter);
2568 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2569 FW_POLL_DELAY * 2);
2570 return;
2571 }
2572
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002573 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002574 qlcnic_api_unlock(adapter);
2575 goto wait_npar;
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002576 }
2577
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002578 if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
2579 dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
2580 adapter->reset_ack_timeo);
2581 goto skip_ack_check;
2582 }
2583
2584 if (!qlcnic_check_drv_state(adapter)) {
2585skip_ack_check:
2586 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002587
2588 if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2589 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2590 QLCNIC_DEV_QUISCENT);
2591 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2592 FW_POLL_DELAY * 2);
2593 QLCDB(adapter, DRV, "Quiscing the driver\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002594 qlcnic_idc_debug_info(adapter, 0);
2595
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002596 qlcnic_api_unlock(adapter);
2597 return;
2598 }
2599
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002600 if (dev_state == QLCNIC_DEV_NEED_RESET) {
2601 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2602 QLCNIC_DEV_INITIALIZING);
2603 set_bit(__QLCNIC_START_FW, &adapter->state);
2604 QLCDB(adapter, DRV, "Restarting fw\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002605 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002606 }
2607
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002608 qlcnic_api_unlock(adapter);
2609
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002610 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002611 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002612 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002613 return;
2614 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002615 goto err_ret;
2616 }
2617
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002618 qlcnic_api_unlock(adapter);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002619
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002620wait_npar:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002621 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002622 QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002623
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002624 switch (dev_state) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002625 case QLCNIC_DEV_READY:
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002626 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002627 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002628 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002629 return;
2630 }
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002631 case QLCNIC_DEV_FAILED:
2632 break;
2633 default:
2634 qlcnic_schedule_work(adapter,
2635 qlcnic_fwinit_work, FW_POLL_DELAY);
2636 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002637 }
2638
2639err_ret:
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002640 dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
2641 "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002642 netif_device_attach(adapter->netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002643 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002644}
2645
2646static void
2647qlcnic_detach_work(struct work_struct *work)
2648{
2649 struct qlcnic_adapter *adapter = container_of(work,
2650 struct qlcnic_adapter, fw_work.work);
2651 struct net_device *netdev = adapter->netdev;
2652 u32 status;
2653
2654 netif_device_detach(netdev);
2655
2656 qlcnic_down(adapter, netdev);
2657
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002658 status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
2659
2660 if (status & QLCNIC_RCODE_FATAL_ERROR)
2661 goto err_ret;
2662
2663 if (adapter->temp == QLCNIC_TEMP_PANIC)
2664 goto err_ret;
2665
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002666 if (qlcnic_set_drv_state(adapter, adapter->dev_state))
2667 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002668
2669 adapter->fw_wait_cnt = 0;
2670
2671 qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
2672
2673 return;
2674
2675err_ret:
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002676 dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
2677 status, adapter->temp);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002678 netif_device_attach(netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002679 qlcnic_clr_all_drv_state(adapter, 1);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002680}
2681
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002682/*Transit NPAR state to NON Operational */
2683static void
2684qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
2685{
2686 u32 state;
2687
2688 state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2689 if (state == QLCNIC_DEV_NPAR_NON_OPER)
2690 return;
2691
2692 if (qlcnic_api_lock(adapter))
2693 return;
2694 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
2695 qlcnic_api_unlock(adapter);
2696}
2697
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002698/*Transit to RESET state from READY state only */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002699static void
2700qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
2701{
2702 u32 state;
2703
Anirban Chakrabortycea89752010-07-13 20:33:35 +00002704 adapter->need_fw_reset = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002705 if (qlcnic_api_lock(adapter))
2706 return;
2707
2708 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2709
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002710 if (state == QLCNIC_DEV_READY) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002711 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002712 QLCDB(adapter, DRV, "NEED_RESET state set\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002713 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002714 }
2715
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002716 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002717 qlcnic_api_unlock(adapter);
2718}
2719
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002720/* Transit to NPAR READY state from NPAR NOT READY state */
2721static void
2722qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
2723{
Anirban Chakrabortycea89752010-07-13 20:33:35 +00002724 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002725 adapter->op_mode != QLCNIC_MGMT_FUNC)
Anirban Chakrabortycea89752010-07-13 20:33:35 +00002726 return;
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002727 if (qlcnic_api_lock(adapter))
2728 return;
2729
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002730 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
2731 QLCDB(adapter, DRV, "NPAR operational state set\n");
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002732
2733 qlcnic_api_unlock(adapter);
2734}
2735
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002736static void
2737qlcnic_schedule_work(struct qlcnic_adapter *adapter,
2738 work_func_t func, int delay)
2739{
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002740 if (test_bit(__QLCNIC_AER, &adapter->state))
2741 return;
2742
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002743 INIT_DELAYED_WORK(&adapter->fw_work, func);
2744 schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
2745}
2746
2747static void
2748qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
2749{
2750 while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
2751 msleep(10);
2752
2753 cancel_delayed_work_sync(&adapter->fw_work);
2754}
2755
2756static void
2757qlcnic_attach_work(struct work_struct *work)
2758{
2759 struct qlcnic_adapter *adapter = container_of(work,
2760 struct qlcnic_adapter, fw_work.work);
2761 struct net_device *netdev = adapter->netdev;
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002762 u32 npar_state;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002763
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002764 if (adapter->op_mode != QLCNIC_MGMT_FUNC) {
2765 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2766 if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
2767 qlcnic_clr_all_drv_state(adapter, 0);
2768 else if (npar_state != QLCNIC_DEV_NPAR_OPER)
2769 qlcnic_schedule_work(adapter, qlcnic_attach_work,
2770 FW_POLL_DELAY);
2771 else
2772 goto attach;
2773 QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n");
2774 return;
2775 }
2776attach:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002777 if (netif_running(netdev)) {
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00002778 if (qlcnic_up(adapter, netdev))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002779 goto done;
2780
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002781 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2782 }
2783
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002784done:
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002785 netif_device_attach(netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002786 adapter->fw_fail_cnt = 0;
2787 clear_bit(__QLCNIC_RESETTING, &adapter->state);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002788
2789 if (!qlcnic_clr_drv_state(adapter))
2790 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2791 FW_POLL_DELAY);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002792}
2793
2794static int
2795qlcnic_check_health(struct qlcnic_adapter *adapter)
2796{
Sony Chacko4e708122010-08-31 17:17:44 +00002797 u32 state = 0, heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002798 struct net_device *netdev = adapter->netdev;
2799
2800 if (qlcnic_check_temp(adapter))
2801 goto detach;
2802
Amit Kumar Salecha2372a5f2010-05-13 03:07:42 +00002803 if (adapter->need_fw_reset)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002804 qlcnic_dev_request_reset(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002805
2806 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002807 if (state == QLCNIC_DEV_NEED_RESET ||
2808 state == QLCNIC_DEV_NEED_QUISCENT) {
2809 qlcnic_set_npar_non_operational(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002810 adapter->need_fw_reset = 1;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002811 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002812
Sony Chacko4e708122010-08-31 17:17:44 +00002813 heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
2814 if (heartbeat != adapter->heartbeat) {
2815 adapter->heartbeat = heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002816 adapter->fw_fail_cnt = 0;
2817 if (adapter->need_fw_reset)
2818 goto detach;
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002819
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002820 if (adapter->reset_context &&
2821 auto_fw_reset == AUTO_FW_RESET_ENABLED) {
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002822 qlcnic_reset_hw_context(adapter);
2823 adapter->netdev->trans_start = jiffies;
2824 }
2825
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002826 return 0;
2827 }
2828
2829 if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
2830 return 0;
2831
2832 qlcnic_dev_request_reset(adapter);
2833
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002834 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED))
2835 clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002836
2837 dev_info(&netdev->dev, "firmware hang detected\n");
2838
2839detach:
2840 adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
2841 QLCNIC_DEV_NEED_RESET;
2842
2843 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002844 !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) {
2845
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002846 qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002847 QLCDB(adapter, DRV, "fw recovery scheduled.\n");
2848 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002849
2850 return 1;
2851}
2852
2853static void
2854qlcnic_fw_poll_work(struct work_struct *work)
2855{
2856 struct qlcnic_adapter *adapter = container_of(work,
2857 struct qlcnic_adapter, fw_work.work);
2858
2859 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
2860 goto reschedule;
2861
2862
2863 if (qlcnic_check_health(adapter))
2864 return;
2865
2866reschedule:
2867 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
2868}
2869
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002870static int qlcnic_is_first_func(struct pci_dev *pdev)
2871{
2872 struct pci_dev *oth_pdev;
2873 int val = pdev->devfn;
2874
2875 while (val-- > 0) {
2876 oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
2877 (pdev->bus), pdev->bus->number,
2878 PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07002879 if (!oth_pdev)
2880 continue;
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002881
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07002882 if (oth_pdev->current_state != PCI_D3cold) {
2883 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002884 return 0;
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07002885 }
2886 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002887 }
2888 return 1;
2889}
2890
2891static int qlcnic_attach_func(struct pci_dev *pdev)
2892{
2893 int err, first_func;
2894 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2895 struct net_device *netdev = adapter->netdev;
2896
2897 pdev->error_state = pci_channel_io_normal;
2898
2899 err = pci_enable_device(pdev);
2900 if (err)
2901 return err;
2902
2903 pci_set_power_state(pdev, PCI_D0);
2904 pci_set_master(pdev);
2905 pci_restore_state(pdev);
2906
2907 first_func = qlcnic_is_first_func(pdev);
2908
2909 if (qlcnic_api_lock(adapter))
2910 return -EINVAL;
2911
Amit Kumar Salecha933fce122010-08-17 00:34:19 +00002912 if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002913 adapter->need_fw_reset = 1;
2914 set_bit(__QLCNIC_START_FW, &adapter->state);
2915 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
2916 QLCDB(adapter, DRV, "Restarting fw\n");
2917 }
2918 qlcnic_api_unlock(adapter);
2919
2920 err = adapter->nic_ops->start_firmware(adapter);
2921 if (err)
2922 return err;
2923
2924 qlcnic_clr_drv_state(adapter);
2925 qlcnic_setup_intr(adapter);
2926
2927 if (netif_running(netdev)) {
2928 err = qlcnic_attach(adapter);
2929 if (err) {
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002930 qlcnic_clr_all_drv_state(adapter, 1);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002931 clear_bit(__QLCNIC_AER, &adapter->state);
2932 netif_device_attach(netdev);
2933 return err;
2934 }
2935
2936 err = qlcnic_up(adapter, netdev);
2937 if (err)
2938 goto done;
2939
2940 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2941 }
2942 done:
2943 netif_device_attach(netdev);
2944 return err;
2945}
2946
2947static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
2948 pci_channel_state_t state)
2949{
2950 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2951 struct net_device *netdev = adapter->netdev;
2952
2953 if (state == pci_channel_io_perm_failure)
2954 return PCI_ERS_RESULT_DISCONNECT;
2955
2956 if (state == pci_channel_io_normal)
2957 return PCI_ERS_RESULT_RECOVERED;
2958
2959 set_bit(__QLCNIC_AER, &adapter->state);
2960 netif_device_detach(netdev);
2961
2962 cancel_delayed_work_sync(&adapter->fw_work);
2963
2964 if (netif_running(netdev))
2965 qlcnic_down(adapter, netdev);
2966
2967 qlcnic_detach(adapter);
2968 qlcnic_teardown_intr(adapter);
2969
2970 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2971
2972 pci_save_state(pdev);
2973 pci_disable_device(pdev);
2974
2975 return PCI_ERS_RESULT_NEED_RESET;
2976}
2977
2978static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
2979{
2980 return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
2981 PCI_ERS_RESULT_RECOVERED;
2982}
2983
2984static void qlcnic_io_resume(struct pci_dev *pdev)
2985{
2986 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2987
2988 pci_cleanup_aer_uncorrect_error_status(pdev);
2989
2990 if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
2991 test_and_clear_bit(__QLCNIC_AER, &adapter->state))
2992 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2993 FW_POLL_DELAY);
2994}
2995
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00002996static int
2997qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
2998{
2999 int err;
3000
3001 err = qlcnic_can_start_firmware(adapter);
3002 if (err)
3003 return err;
3004
Amit Kumar Salecha78f84e12010-08-19 05:08:28 +00003005 err = qlcnic_check_npar_opertional(adapter);
3006 if (err)
3007 return err;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00003008
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003009 qlcnic_check_options(adapter);
3010
3011 adapter->need_fw_reset = 0;
3012
3013 return err;
3014}
3015
3016static int
3017qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
3018{
3019 return -EOPNOTSUPP;
3020}
3021
3022static int
3023qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
3024{
3025 return -EOPNOTSUPP;
3026}
3027
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003028static ssize_t
3029qlcnic_store_bridged_mode(struct device *dev,
3030 struct device_attribute *attr, const char *buf, size_t len)
3031{
3032 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3033 unsigned long new;
3034 int ret = -EINVAL;
3035
3036 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
3037 goto err_out;
3038
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003039 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003040 goto err_out;
3041
3042 if (strict_strtoul(buf, 2, &new))
3043 goto err_out;
3044
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00003045 if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003046 ret = len;
3047
3048err_out:
3049 return ret;
3050}
3051
3052static ssize_t
3053qlcnic_show_bridged_mode(struct device *dev,
3054 struct device_attribute *attr, char *buf)
3055{
3056 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3057 int bridged_mode = 0;
3058
3059 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3060 bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
3061
3062 return sprintf(buf, "%d\n", bridged_mode);
3063}
3064
3065static struct device_attribute dev_attr_bridged_mode = {
3066 .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
3067 .show = qlcnic_show_bridged_mode,
3068 .store = qlcnic_store_bridged_mode,
3069};
3070
3071static ssize_t
3072qlcnic_store_diag_mode(struct device *dev,
3073 struct device_attribute *attr, const char *buf, size_t len)
3074{
3075 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3076 unsigned long new;
3077
3078 if (strict_strtoul(buf, 2, &new))
3079 return -EINVAL;
3080
3081 if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
3082 adapter->flags ^= QLCNIC_DIAG_ENABLED;
3083
3084 return len;
3085}
3086
3087static ssize_t
3088qlcnic_show_diag_mode(struct device *dev,
3089 struct device_attribute *attr, char *buf)
3090{
3091 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3092
3093 return sprintf(buf, "%d\n",
3094 !!(adapter->flags & QLCNIC_DIAG_ENABLED));
3095}
3096
3097static struct device_attribute dev_attr_diag_mode = {
3098 .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
3099 .show = qlcnic_show_diag_mode,
3100 .store = qlcnic_store_diag_mode,
3101};
3102
3103static int
3104qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
3105 loff_t offset, size_t size)
3106{
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003107 size_t crb_size = 4;
3108
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003109 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3110 return -EIO;
3111
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003112 if (offset < QLCNIC_PCI_CRBSPACE) {
3113 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
3114 QLCNIC_PCI_CAMQM_END))
3115 crb_size = 8;
3116 else
3117 return -EINVAL;
3118 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003119
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003120 if ((size != crb_size) || (offset & (crb_size-1)))
3121 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003122
3123 return 0;
3124}
3125
3126static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003127qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
3128 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003129 char *buf, loff_t offset, size_t size)
3130{
3131 struct device *dev = container_of(kobj, struct device, kobj);
3132 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3133 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003134 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003135 int ret;
3136
3137 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3138 if (ret != 0)
3139 return ret;
3140
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003141 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3142 qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
3143 memcpy(buf, &qmdata, size);
3144 } else {
3145 data = QLCRD32(adapter, offset);
3146 memcpy(buf, &data, size);
3147 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003148 return size;
3149}
3150
3151static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003152qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
3153 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003154 char *buf, loff_t offset, size_t size)
3155{
3156 struct device *dev = container_of(kobj, struct device, kobj);
3157 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3158 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003159 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003160 int ret;
3161
3162 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3163 if (ret != 0)
3164 return ret;
3165
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003166 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3167 memcpy(&qmdata, buf, size);
3168 qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
3169 } else {
3170 memcpy(&data, buf, size);
3171 QLCWR32(adapter, offset, data);
3172 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003173 return size;
3174}
3175
3176static int
3177qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
3178 loff_t offset, size_t size)
3179{
3180 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3181 return -EIO;
3182
3183 if ((size != 8) || (offset & 0x7))
3184 return -EIO;
3185
3186 return 0;
3187}
3188
3189static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003190qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
3191 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003192 char *buf, loff_t offset, size_t size)
3193{
3194 struct device *dev = container_of(kobj, struct device, kobj);
3195 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3196 u64 data;
3197 int ret;
3198
3199 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3200 if (ret != 0)
3201 return ret;
3202
3203 if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
3204 return -EIO;
3205
3206 memcpy(buf, &data, size);
3207
3208 return size;
3209}
3210
3211static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003212qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
3213 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003214 char *buf, loff_t offset, size_t size)
3215{
3216 struct device *dev = container_of(kobj, struct device, kobj);
3217 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3218 u64 data;
3219 int ret;
3220
3221 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3222 if (ret != 0)
3223 return ret;
3224
3225 memcpy(&data, buf, size);
3226
3227 if (qlcnic_pci_mem_write_2M(adapter, offset, data))
3228 return -EIO;
3229
3230 return size;
3231}
3232
3233
3234static struct bin_attribute bin_attr_crb = {
3235 .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
3236 .size = 0,
3237 .read = qlcnic_sysfs_read_crb,
3238 .write = qlcnic_sysfs_write_crb,
3239};
3240
3241static struct bin_attribute bin_attr_mem = {
3242 .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
3243 .size = 0,
3244 .read = qlcnic_sysfs_read_mem,
3245 .write = qlcnic_sysfs_write_mem,
3246};
3247
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003248static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003249validate_pm_config(struct qlcnic_adapter *adapter,
3250 struct qlcnic_pm_func_cfg *pm_cfg, int count)
3251{
3252
3253 u8 src_pci_func, s_esw_id, d_esw_id;
3254 u8 dest_pci_func;
3255 int i;
3256
3257 for (i = 0; i < count; i++) {
3258 src_pci_func = pm_cfg[i].pci_func;
3259 dest_pci_func = pm_cfg[i].dest_npar;
3260 if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
3261 || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
3262 return QL_STATUS_INVALID_PARAM;
3263
3264 if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
3265 return QL_STATUS_INVALID_PARAM;
3266
3267 if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
3268 return QL_STATUS_INVALID_PARAM;
3269
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003270 s_esw_id = adapter->npars[src_pci_func].phy_port;
3271 d_esw_id = adapter->npars[dest_pci_func].phy_port;
3272
3273 if (s_esw_id != d_esw_id)
3274 return QL_STATUS_INVALID_PARAM;
3275
3276 }
3277 return 0;
3278
3279}
3280
3281static ssize_t
3282qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
3283 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3284{
3285 struct device *dev = container_of(kobj, struct device, kobj);
3286 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3287 struct qlcnic_pm_func_cfg *pm_cfg;
3288 u32 id, action, pci_func;
3289 int count, rem, i, ret;
3290
3291 count = size / sizeof(struct qlcnic_pm_func_cfg);
3292 rem = size % sizeof(struct qlcnic_pm_func_cfg);
3293 if (rem)
3294 return QL_STATUS_INVALID_PARAM;
3295
3296 pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
3297
3298 ret = validate_pm_config(adapter, pm_cfg, count);
3299 if (ret)
3300 return ret;
3301 for (i = 0; i < count; i++) {
3302 pci_func = pm_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003303 action = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003304 id = adapter->npars[pci_func].phy_port;
3305 ret = qlcnic_config_port_mirroring(adapter, id,
3306 action, pci_func);
3307 if (ret)
3308 return ret;
3309 }
3310
3311 for (i = 0; i < count; i++) {
3312 pci_func = pm_cfg[i].pci_func;
3313 id = adapter->npars[pci_func].phy_port;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003314 adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003315 adapter->npars[pci_func].dest_npar = id;
3316 }
3317 return size;
3318}
3319
3320static ssize_t
3321qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
3322 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3323{
3324 struct device *dev = container_of(kobj, struct device, kobj);
3325 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3326 struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
3327 int i;
3328
3329 if (size != sizeof(pm_cfg))
3330 return QL_STATUS_INVALID_PARAM;
3331
3332 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3333 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3334 continue;
3335 pm_cfg[i].action = adapter->npars[i].enable_pm;
3336 pm_cfg[i].dest_npar = 0;
3337 pm_cfg[i].pci_func = i;
3338 }
3339 memcpy(buf, &pm_cfg, size);
3340
3341 return size;
3342}
3343
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003344static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003345validate_esw_config(struct qlcnic_adapter *adapter,
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003346 struct qlcnic_esw_func_cfg *esw_cfg, int count)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003347{
3348 u8 pci_func;
3349 int i;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003350 for (i = 0; i < count; i++) {
3351 pci_func = esw_cfg[i].pci_func;
3352 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3353 return QL_STATUS_INVALID_PARAM;
3354
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003355 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3356 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003357 return QL_STATUS_INVALID_PARAM;
3358
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003359 switch (esw_cfg[i].op_mode) {
3360 case QLCNIC_PORT_DEFAULTS:
3361 break;
3362 case QLCNIC_ADD_VLAN:
3363 if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
3364 return QL_STATUS_INVALID_PARAM;
3365 if (!esw_cfg[i].op_type)
3366 return QL_STATUS_INVALID_PARAM;
3367 break;
3368 case QLCNIC_DEL_VLAN:
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003369 if (!esw_cfg[i].op_type)
3370 return QL_STATUS_INVALID_PARAM;
3371 break;
3372 default:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003373 return QL_STATUS_INVALID_PARAM;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003374 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003375 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003376 return 0;
3377}
3378
3379static ssize_t
3380qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
3381 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3382{
3383 struct device *dev = container_of(kobj, struct device, kobj);
3384 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3385 struct qlcnic_esw_func_cfg *esw_cfg;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003386 struct qlcnic_npar_info *npar;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003387 int count, rem, i, ret;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003388 u8 pci_func, op_mode = 0;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003389
3390 count = size / sizeof(struct qlcnic_esw_func_cfg);
3391 rem = size % sizeof(struct qlcnic_esw_func_cfg);
3392 if (rem)
3393 return QL_STATUS_INVALID_PARAM;
3394
3395 esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
3396 ret = validate_esw_config(adapter, esw_cfg, count);
3397 if (ret)
3398 return ret;
3399
3400 for (i = 0; i < count; i++) {
Rajesh Borundia0325d692010-08-19 05:08:26 +00003401 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3402 if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
3403 return QL_STATUS_INVALID_PARAM;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003404
3405 if (adapter->ahw.pci_func != esw_cfg[i].pci_func)
3406 continue;
3407
3408 op_mode = esw_cfg[i].op_mode;
3409 qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
3410 esw_cfg[i].op_mode = op_mode;
3411 esw_cfg[i].pci_func = adapter->ahw.pci_func;
3412
3413 switch (esw_cfg[i].op_mode) {
3414 case QLCNIC_PORT_DEFAULTS:
3415 qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
3416 break;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00003417 case QLCNIC_ADD_VLAN:
3418 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3419 break;
3420 case QLCNIC_DEL_VLAN:
3421 esw_cfg[i].vlan_id = 0;
3422 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3423 break;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003424 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003425 }
3426
Rajesh Borundia0325d692010-08-19 05:08:26 +00003427 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
3428 goto out;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003429
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003430 for (i = 0; i < count; i++) {
3431 pci_func = esw_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003432 npar = &adapter->npars[pci_func];
3433 switch (esw_cfg[i].op_mode) {
3434 case QLCNIC_PORT_DEFAULTS:
3435 npar->promisc_mode = esw_cfg[i].promisc_mode;
3436 npar->mac_learning = esw_cfg[i].mac_learning;
3437 npar->offload_flags = esw_cfg[i].offload_flags;
3438 npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
3439 npar->discard_tagged = esw_cfg[i].discard_tagged;
3440 break;
3441 case QLCNIC_ADD_VLAN:
3442 npar->pvid = esw_cfg[i].vlan_id;
3443 break;
3444 case QLCNIC_DEL_VLAN:
3445 npar->pvid = 0;
3446 break;
3447 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003448 }
Rajesh Borundia0325d692010-08-19 05:08:26 +00003449out:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003450 return size;
3451}
3452
3453static ssize_t
3454qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
3455 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3456{
3457 struct device *dev = container_of(kobj, struct device, kobj);
3458 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3459 struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003460 u8 i;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003461
3462 if (size != sizeof(esw_cfg))
3463 return QL_STATUS_INVALID_PARAM;
3464
3465 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3466 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3467 continue;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003468 esw_cfg[i].pci_func = i;
3469 if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
3470 return QL_STATUS_INVALID_PARAM;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003471 }
3472 memcpy(buf, &esw_cfg, size);
3473
3474 return size;
3475}
3476
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003477static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003478validate_npar_config(struct qlcnic_adapter *adapter,
3479 struct qlcnic_npar_func_cfg *np_cfg, int count)
3480{
3481 u8 pci_func, i;
3482
3483 for (i = 0; i < count; i++) {
3484 pci_func = np_cfg[i].pci_func;
3485 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3486 return QL_STATUS_INVALID_PARAM;
3487
3488 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
3489 return QL_STATUS_INVALID_PARAM;
3490
3491 if (!IS_VALID_BW(np_cfg[i].min_bw)
3492 || !IS_VALID_BW(np_cfg[i].max_bw)
3493 || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
3494 || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
3495 return QL_STATUS_INVALID_PARAM;
3496 }
3497 return 0;
3498}
3499
3500static ssize_t
3501qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
3502 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3503{
3504 struct device *dev = container_of(kobj, struct device, kobj);
3505 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3506 struct qlcnic_info nic_info;
3507 struct qlcnic_npar_func_cfg *np_cfg;
3508 int i, count, rem, ret;
3509 u8 pci_func;
3510
3511 count = size / sizeof(struct qlcnic_npar_func_cfg);
3512 rem = size % sizeof(struct qlcnic_npar_func_cfg);
3513 if (rem)
3514 return QL_STATUS_INVALID_PARAM;
3515
3516 np_cfg = (struct qlcnic_npar_func_cfg *) buf;
3517 ret = validate_npar_config(adapter, np_cfg, count);
3518 if (ret)
3519 return ret;
3520
3521 for (i = 0; i < count ; i++) {
3522 pci_func = np_cfg[i].pci_func;
3523 ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
3524 if (ret)
3525 return ret;
3526 nic_info.pci_func = pci_func;
3527 nic_info.min_tx_bw = np_cfg[i].min_bw;
3528 nic_info.max_tx_bw = np_cfg[i].max_bw;
3529 ret = qlcnic_set_nic_info(adapter, &nic_info);
3530 if (ret)
3531 return ret;
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003532 adapter->npars[i].min_bw = nic_info.min_tx_bw;
3533 adapter->npars[i].max_bw = nic_info.max_tx_bw;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003534 }
3535
3536 return size;
3537
3538}
3539static ssize_t
3540qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
3541 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3542{
3543 struct device *dev = container_of(kobj, struct device, kobj);
3544 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3545 struct qlcnic_info nic_info;
3546 struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
3547 int i, ret;
3548
3549 if (size != sizeof(np_cfg))
3550 return QL_STATUS_INVALID_PARAM;
3551
3552 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3553 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3554 continue;
3555 ret = qlcnic_get_nic_info(adapter, &nic_info, i);
3556 if (ret)
3557 return ret;
3558
3559 np_cfg[i].pci_func = i;
3560 np_cfg[i].op_mode = nic_info.op_mode;
3561 np_cfg[i].port_num = nic_info.phys_port;
3562 np_cfg[i].fw_capab = nic_info.capabilities;
3563 np_cfg[i].min_bw = nic_info.min_tx_bw ;
3564 np_cfg[i].max_bw = nic_info.max_tx_bw;
3565 np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
3566 np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
3567 }
3568 memcpy(buf, &np_cfg, size);
3569 return size;
3570}
3571
3572static ssize_t
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003573qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
3574 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3575{
3576 struct device *dev = container_of(kobj, struct device, kobj);
3577 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3578 struct qlcnic_esw_statistics port_stats;
3579 int ret;
3580
3581 if (size != sizeof(struct qlcnic_esw_statistics))
3582 return QL_STATUS_INVALID_PARAM;
3583
3584 if (offset >= QLCNIC_MAX_PCI_FUNC)
3585 return QL_STATUS_INVALID_PARAM;
3586
3587 memset(&port_stats, 0, size);
3588 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3589 &port_stats.rx);
3590 if (ret)
3591 return ret;
3592
3593 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3594 &port_stats.tx);
3595 if (ret)
3596 return ret;
3597
3598 memcpy(buf, &port_stats, size);
3599 return size;
3600}
3601
3602static ssize_t
3603qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
3604 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3605{
3606 struct device *dev = container_of(kobj, struct device, kobj);
3607 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3608 struct qlcnic_esw_statistics esw_stats;
3609 int ret;
3610
3611 if (size != sizeof(struct qlcnic_esw_statistics))
3612 return QL_STATUS_INVALID_PARAM;
3613
3614 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3615 return QL_STATUS_INVALID_PARAM;
3616
3617 memset(&esw_stats, 0, size);
3618 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3619 &esw_stats.rx);
3620 if (ret)
3621 return ret;
3622
3623 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3624 &esw_stats.tx);
3625 if (ret)
3626 return ret;
3627
3628 memcpy(buf, &esw_stats, size);
3629 return size;
3630}
3631
3632static ssize_t
3633qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
3634 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3635{
3636 struct device *dev = container_of(kobj, struct device, kobj);
3637 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3638 int ret;
3639
3640 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3641 return QL_STATUS_INVALID_PARAM;
3642
3643 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3644 QLCNIC_QUERY_RX_COUNTER);
3645 if (ret)
3646 return ret;
3647
3648 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3649 QLCNIC_QUERY_TX_COUNTER);
3650 if (ret)
3651 return ret;
3652
3653 return size;
3654}
3655
3656static ssize_t
3657qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
3658 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3659{
3660
3661 struct device *dev = container_of(kobj, struct device, kobj);
3662 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3663 int ret;
3664
3665 if (offset >= QLCNIC_MAX_PCI_FUNC)
3666 return QL_STATUS_INVALID_PARAM;
3667
3668 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3669 QLCNIC_QUERY_RX_COUNTER);
3670 if (ret)
3671 return ret;
3672
3673 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3674 QLCNIC_QUERY_TX_COUNTER);
3675 if (ret)
3676 return ret;
3677
3678 return size;
3679}
3680
3681static ssize_t
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003682qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
3683 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3684{
3685 struct device *dev = container_of(kobj, struct device, kobj);
3686 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3687 struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
Dan Carpentere88db3b2010-08-09 21:49:36 +00003688 struct qlcnic_pci_info *pci_info;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003689 int i, ret;
3690
3691 if (size != sizeof(pci_cfg))
3692 return QL_STATUS_INVALID_PARAM;
3693
Dan Carpentere88db3b2010-08-09 21:49:36 +00003694 pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
3695 if (!pci_info)
3696 return -ENOMEM;
3697
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003698 ret = qlcnic_get_pci_info(adapter, pci_info);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003699 if (ret) {
3700 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003701 return ret;
Dan Carpentere88db3b2010-08-09 21:49:36 +00003702 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003703
3704 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3705 pci_cfg[i].pci_func = pci_info[i].id;
3706 pci_cfg[i].func_type = pci_info[i].type;
3707 pci_cfg[i].port_num = pci_info[i].default_port;
3708 pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
3709 pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
3710 memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
3711 }
3712 memcpy(buf, &pci_cfg, size);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003713 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003714 return size;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003715}
3716static struct bin_attribute bin_attr_npar_config = {
3717 .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
3718 .size = 0,
3719 .read = qlcnic_sysfs_read_npar_config,
3720 .write = qlcnic_sysfs_write_npar_config,
3721};
3722
3723static struct bin_attribute bin_attr_pci_config = {
3724 .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
3725 .size = 0,
3726 .read = qlcnic_sysfs_read_pci_config,
3727 .write = NULL,
3728};
3729
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003730static struct bin_attribute bin_attr_port_stats = {
3731 .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
3732 .size = 0,
3733 .read = qlcnic_sysfs_get_port_stats,
3734 .write = qlcnic_sysfs_clear_port_stats,
3735};
3736
3737static struct bin_attribute bin_attr_esw_stats = {
3738 .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
3739 .size = 0,
3740 .read = qlcnic_sysfs_get_esw_stats,
3741 .write = qlcnic_sysfs_clear_esw_stats,
3742};
3743
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003744static struct bin_attribute bin_attr_esw_config = {
3745 .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
3746 .size = 0,
3747 .read = qlcnic_sysfs_read_esw_config,
3748 .write = qlcnic_sysfs_write_esw_config,
3749};
3750
3751static struct bin_attribute bin_attr_pm_config = {
3752 .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
3753 .size = 0,
3754 .read = qlcnic_sysfs_read_pm_config,
3755 .write = qlcnic_sysfs_write_pm_config,
3756};
3757
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003758static void
3759qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
3760{
3761 struct device *dev = &adapter->pdev->dev;
3762
3763 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3764 if (device_create_file(dev, &dev_attr_bridged_mode))
3765 dev_warn(dev,
3766 "failed to create bridged_mode sysfs entry\n");
3767}
3768
3769static void
3770qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
3771{
3772 struct device *dev = &adapter->pdev->dev;
3773
3774 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3775 device_remove_file(dev, &dev_attr_bridged_mode);
3776}
3777
3778static void
3779qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
3780{
3781 struct device *dev = &adapter->pdev->dev;
3782
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003783 if (device_create_bin_file(dev, &bin_attr_port_stats))
3784 dev_info(dev, "failed to create port stats sysfs entry");
3785
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003786 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3787 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003788 if (device_create_file(dev, &dev_attr_diag_mode))
3789 dev_info(dev, "failed to create diag_mode sysfs entry\n");
3790 if (device_create_bin_file(dev, &bin_attr_crb))
3791 dev_info(dev, "failed to create crb sysfs entry\n");
3792 if (device_create_bin_file(dev, &bin_attr_mem))
3793 dev_info(dev, "failed to create mem sysfs entry\n");
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003794 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
3795 return;
3796 if (device_create_bin_file(dev, &bin_attr_esw_config))
3797 dev_info(dev, "failed to create esw config sysfs entry");
3798 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003799 return;
3800 if (device_create_bin_file(dev, &bin_attr_pci_config))
3801 dev_info(dev, "failed to create pci config sysfs entry");
3802 if (device_create_bin_file(dev, &bin_attr_npar_config))
3803 dev_info(dev, "failed to create npar config sysfs entry");
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003804 if (device_create_bin_file(dev, &bin_attr_pm_config))
3805 dev_info(dev, "failed to create pm config sysfs entry");
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003806 if (device_create_bin_file(dev, &bin_attr_esw_stats))
3807 dev_info(dev, "failed to create eswitch stats sysfs entry");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003808}
3809
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003810static void
3811qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
3812{
3813 struct device *dev = &adapter->pdev->dev;
3814
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003815 device_remove_bin_file(dev, &bin_attr_port_stats);
3816
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003817 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3818 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003819 device_remove_file(dev, &dev_attr_diag_mode);
3820 device_remove_bin_file(dev, &bin_attr_crb);
3821 device_remove_bin_file(dev, &bin_attr_mem);
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003822 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
3823 return;
3824 device_remove_bin_file(dev, &bin_attr_esw_config);
3825 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003826 return;
3827 device_remove_bin_file(dev, &bin_attr_pci_config);
3828 device_remove_bin_file(dev, &bin_attr_npar_config);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003829 device_remove_bin_file(dev, &bin_attr_pm_config);
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003830 device_remove_bin_file(dev, &bin_attr_esw_stats);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003831}
3832
3833#ifdef CONFIG_INET
3834
3835#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
3836
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003837static void
3838qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
3839{
3840 struct in_device *indev;
3841 struct qlcnic_adapter *adapter = netdev_priv(dev);
3842
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003843 indev = in_dev_get(dev);
3844 if (!indev)
3845 return;
3846
3847 for_ifa(indev) {
3848 switch (event) {
3849 case NETDEV_UP:
3850 qlcnic_config_ipaddr(adapter,
3851 ifa->ifa_address, QLCNIC_IP_UP);
3852 break;
3853 case NETDEV_DOWN:
3854 qlcnic_config_ipaddr(adapter,
3855 ifa->ifa_address, QLCNIC_IP_DOWN);
3856 break;
3857 default:
3858 break;
3859 }
3860 } endfor_ifa(indev);
3861
3862 in_dev_put(indev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003863}
3864
3865static int qlcnic_netdev_event(struct notifier_block *this,
3866 unsigned long event, void *ptr)
3867{
3868 struct qlcnic_adapter *adapter;
3869 struct net_device *dev = (struct net_device *)ptr;
3870
3871recheck:
3872 if (dev == NULL)
3873 goto done;
3874
3875 if (dev->priv_flags & IFF_802_1Q_VLAN) {
3876 dev = vlan_dev_real_dev(dev);
3877 goto recheck;
3878 }
3879
3880 if (!is_qlcnic_netdev(dev))
3881 goto done;
3882
3883 adapter = netdev_priv(dev);
3884
3885 if (!adapter)
3886 goto done;
3887
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003888 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003889 goto done;
3890
3891 qlcnic_config_indev_addr(dev, event);
3892done:
3893 return NOTIFY_DONE;
3894}
3895
3896static int
3897qlcnic_inetaddr_event(struct notifier_block *this,
3898 unsigned long event, void *ptr)
3899{
3900 struct qlcnic_adapter *adapter;
3901 struct net_device *dev;
3902
3903 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
3904
3905 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
3906
3907recheck:
3908 if (dev == NULL || !netif_running(dev))
3909 goto done;
3910
3911 if (dev->priv_flags & IFF_802_1Q_VLAN) {
3912 dev = vlan_dev_real_dev(dev);
3913 goto recheck;
3914 }
3915
3916 if (!is_qlcnic_netdev(dev))
3917 goto done;
3918
3919 adapter = netdev_priv(dev);
3920
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +00003921 if (!adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003922 goto done;
3923
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003924 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003925 goto done;
3926
3927 switch (event) {
3928 case NETDEV_UP:
3929 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
3930 break;
3931 case NETDEV_DOWN:
3932 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
3933 break;
3934 default:
3935 break;
3936 }
3937
3938done:
3939 return NOTIFY_DONE;
3940}
3941
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003942static struct notifier_block qlcnic_netdev_cb = {
3943 .notifier_call = qlcnic_netdev_event,
3944};
3945
3946static struct notifier_block qlcnic_inetaddr_cb = {
3947 .notifier_call = qlcnic_inetaddr_event,
3948};
3949#else
3950static void
3951qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
3952{ }
3953#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003954static struct pci_error_handlers qlcnic_err_handler = {
3955 .error_detected = qlcnic_io_error_detected,
3956 .slot_reset = qlcnic_io_slot_reset,
3957 .resume = qlcnic_io_resume,
3958};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003959
3960static struct pci_driver qlcnic_driver = {
3961 .name = qlcnic_driver_name,
3962 .id_table = qlcnic_pci_tbl,
3963 .probe = qlcnic_probe,
3964 .remove = __devexit_p(qlcnic_remove),
3965#ifdef CONFIG_PM
3966 .suspend = qlcnic_suspend,
3967 .resume = qlcnic_resume,
3968#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003969 .shutdown = qlcnic_shutdown,
3970 .err_handler = &qlcnic_err_handler
3971
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003972};
3973
3974static int __init qlcnic_init_module(void)
3975{
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00003976 int ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003977
3978 printk(KERN_INFO "%s\n", qlcnic_driver_string);
3979
3980#ifdef CONFIG_INET
3981 register_netdevice_notifier(&qlcnic_netdev_cb);
3982 register_inetaddr_notifier(&qlcnic_inetaddr_cb);
3983#endif
3984
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00003985 ret = pci_register_driver(&qlcnic_driver);
3986 if (ret) {
3987#ifdef CONFIG_INET
3988 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
3989 unregister_netdevice_notifier(&qlcnic_netdev_cb);
3990#endif
3991 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003992
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00003993 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003994}
3995
3996module_init(qlcnic_init_module);
3997
3998static void __exit qlcnic_exit_module(void)
3999{
4000
4001 pci_unregister_driver(&qlcnic_driver);
4002
4003#ifdef CONFIG_INET
4004 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
4005 unregister_netdevice_notifier(&qlcnic_netdev_cb);
4006#endif
4007}
4008
4009module_exit(qlcnic_exit_module);