blob: 5a6445a691b3f1e9cf2a3e60c5d5bcf37484de4c [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
Amit Kumar Salechab5e54922010-08-31 17:17:51 +000053static int qlcnic_mac_learn;
54module_param(qlcnic_mac_learn, int, 0644);
55MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
56
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000057static int use_msi = 1;
58module_param(use_msi, int, 0644);
59MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
60
61static int use_msi_x = 1;
62module_param(use_msi_x, int, 0644);
63MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
64
65static int auto_fw_reset = AUTO_FW_RESET_ENABLED;
66module_param(auto_fw_reset, int, 0644);
67MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
68
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +000069static int load_fw_file;
70module_param(load_fw_file, int, 0644);
71MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
72
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +000073static int qlcnic_config_npars;
74module_param(qlcnic_config_npars, int, 0644);
75MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
76
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000077static int __devinit qlcnic_probe(struct pci_dev *pdev,
78 const struct pci_device_id *ent);
79static void __devexit qlcnic_remove(struct pci_dev *pdev);
80static int qlcnic_open(struct net_device *netdev);
81static int qlcnic_close(struct net_device *netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000082static void qlcnic_tx_timeout(struct net_device *netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000083static void qlcnic_attach_work(struct work_struct *work);
84static void qlcnic_fwinit_work(struct work_struct *work);
85static void qlcnic_fw_poll_work(struct work_struct *work);
86static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
87 work_func_t func, int delay);
88static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
89static int qlcnic_poll(struct napi_struct *napi, int budget);
schacko8f891382010-06-17 02:56:40 +000090static int qlcnic_rx_poll(struct napi_struct *napi, int budget);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +000091#ifdef CONFIG_NET_POLL_CONTROLLER
92static void qlcnic_poll_controller(struct net_device *netdev);
93#endif
94
95static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
96static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
97static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
98static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
99
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +0000100static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +0000101static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000102static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
103
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +0000104static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000105static irqreturn_t qlcnic_intr(int irq, void *data);
106static irqreturn_t qlcnic_msi_intr(int irq, void *data);
107static irqreturn_t qlcnic_msix_intr(int irq, void *data);
108
109static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
110static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000111static int qlcnic_start_firmware(struct qlcnic_adapter *);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000112
Amit Kumar Salechab5e54922010-08-31 17:17:51 +0000113static void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
114static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000115static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000116static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
117static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
118static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
Rajesh Borundia0325d692010-08-19 05:08:26 +0000119static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
120 struct qlcnic_esw_func_cfg *);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000121/* PCI Device ID Table */
122#define ENTRY(device) \
123 {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
124 .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
125
126#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020
127
Amit Kumar Salecha6a902882010-02-01 05:24:54 +0000128static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000129 ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
130 {0,}
131};
132
133MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl);
134
135
136void
137qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
138 struct qlcnic_host_tx_ring *tx_ring)
139{
140 writel(tx_ring->producer, tx_ring->crb_cmd_producer);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000141}
142
143static const u32 msi_tgt_status[8] = {
144 ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
145 ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
146 ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
147 ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
148};
149
150static const
151struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
152
153static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
154{
155 writel(0, sds_ring->crb_intr_mask);
156}
157
158static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
159{
160 struct qlcnic_adapter *adapter = sds_ring->adapter;
161
162 writel(0x1, sds_ring->crb_intr_mask);
163
164 if (!QLCNIC_IS_MSI_FAMILY(adapter))
165 writel(0xfbff, adapter->tgt_mask_reg);
166}
167
168static int
169qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
170{
171 int size = sizeof(struct qlcnic_host_sds_ring) * count;
172
173 recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL);
174
175 return (recv_ctx->sds_rings == NULL);
176}
177
178static void
179qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
180{
181 if (recv_ctx->sds_rings != NULL)
182 kfree(recv_ctx->sds_rings);
183
184 recv_ctx->sds_rings = NULL;
185}
186
187static int
188qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
189{
190 int ring;
191 struct qlcnic_host_sds_ring *sds_ring;
192 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
193
194 if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
195 return -ENOMEM;
196
197 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
198 sds_ring = &recv_ctx->sds_rings[ring];
schacko8f891382010-06-17 02:56:40 +0000199
200 if (ring == adapter->max_sds_rings - 1)
201 netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
202 QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
203 else
204 netif_napi_add(netdev, &sds_ring->napi,
205 qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000206 }
207
208 return 0;
209}
210
211static void
212qlcnic_napi_del(struct qlcnic_adapter *adapter)
213{
214 int ring;
215 struct qlcnic_host_sds_ring *sds_ring;
216 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
217
218 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
219 sds_ring = &recv_ctx->sds_rings[ring];
220 netif_napi_del(&sds_ring->napi);
221 }
222
223 qlcnic_free_sds_rings(&adapter->recv_ctx);
224}
225
226static void
227qlcnic_napi_enable(struct qlcnic_adapter *adapter)
228{
229 int ring;
230 struct qlcnic_host_sds_ring *sds_ring;
231 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
232
Amit Kumar Salecha780ab792010-04-22 02:51:41 +0000233 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
234 return;
235
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000236 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
237 sds_ring = &recv_ctx->sds_rings[ring];
238 napi_enable(&sds_ring->napi);
239 qlcnic_enable_int(sds_ring);
240 }
241}
242
243static void
244qlcnic_napi_disable(struct qlcnic_adapter *adapter)
245{
246 int ring;
247 struct qlcnic_host_sds_ring *sds_ring;
248 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
249
Amit Kumar Salecha780ab792010-04-22 02:51:41 +0000250 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
251 return;
252
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000253 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
254 sds_ring = &recv_ctx->sds_rings[ring];
255 qlcnic_disable_int(sds_ring);
256 napi_synchronize(&sds_ring->napi);
257 napi_disable(&sds_ring->napi);
258 }
259}
260
261static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
262{
263 memset(&adapter->stats, 0, sizeof(adapter->stats));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000264}
265
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000266static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter)
267{
268 u32 val, data;
269
270 val = adapter->ahw.board_type;
271 if ((val == QLCNIC_BRDTYPE_P3_HMEZ) ||
272 (val == QLCNIC_BRDTYPE_P3_XG_LOM)) {
273 if (port_mode == QLCNIC_PORT_MODE_802_3_AP) {
274 data = QLCNIC_PORT_MODE_802_3_AP;
275 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
276 } else if (port_mode == QLCNIC_PORT_MODE_XG) {
277 data = QLCNIC_PORT_MODE_XG;
278 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
279 } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_1G) {
280 data = QLCNIC_PORT_MODE_AUTO_NEG_1G;
281 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
282 } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_XG) {
283 data = QLCNIC_PORT_MODE_AUTO_NEG_XG;
284 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
285 } else {
286 data = QLCNIC_PORT_MODE_AUTO_NEG;
287 QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
288 }
289
290 if ((wol_port_mode != QLCNIC_PORT_MODE_802_3_AP) &&
291 (wol_port_mode != QLCNIC_PORT_MODE_XG) &&
292 (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_1G) &&
293 (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_XG)) {
294 wol_port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
295 }
296 QLCWR32(adapter, QLCNIC_WOL_PORT_MODE, wol_port_mode);
297 }
298}
299
300static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
301{
302 u32 control;
303 int pos;
304
305 pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
306 if (pos) {
307 pci_read_config_dword(pdev, pos, &control);
308 if (enable)
309 control |= PCI_MSIX_FLAGS_ENABLE;
310 else
311 control = 0;
312 pci_write_config_dword(pdev, pos, control);
313 }
314}
315
316static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
317{
318 int i;
319
320 for (i = 0; i < count; i++)
321 adapter->msix_entries[i].entry = i;
322}
323
324static int
325qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
326{
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000327 u8 mac_addr[ETH_ALEN];
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000328 struct net_device *netdev = adapter->netdev;
329 struct pci_dev *pdev = adapter->pdev;
330
Rajesh Borundiada48e6c2010-08-31 17:17:46 +0000331 if (qlcnic_get_mac_address(adapter, mac_addr) != 0)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000332 return -EIO;
333
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000334 memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000335 memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
336 memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
337
338 /* set station address */
339
340 if (!is_valid_ether_addr(netdev->perm_addr))
341 dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
342 netdev->dev_addr);
343
344 return 0;
345}
346
347static int qlcnic_set_mac(struct net_device *netdev, void *p)
348{
349 struct qlcnic_adapter *adapter = netdev_priv(netdev);
350 struct sockaddr *addr = p;
351
Rajesh Borundia73733732010-08-31 17:17:50 +0000352 if ((adapter->flags & QLCNIC_MAC_OVERRIDE_DISABLED))
353 return -EOPNOTSUPP;
354
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000355 if (!is_valid_ether_addr(addr->sa_data))
356 return -EINVAL;
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_detach(netdev);
360 qlcnic_napi_disable(adapter);
361 }
362
363 memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len);
364 memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
365 qlcnic_set_multi(adapter->netdev);
366
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +0000367 if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000368 netif_device_attach(netdev);
369 qlcnic_napi_enable(adapter);
370 }
371 return 0;
372}
373
374static const struct net_device_ops qlcnic_netdev_ops = {
375 .ndo_open = qlcnic_open,
376 .ndo_stop = qlcnic_close,
377 .ndo_start_xmit = qlcnic_xmit_frame,
378 .ndo_get_stats = qlcnic_get_stats,
379 .ndo_validate_addr = eth_validate_addr,
380 .ndo_set_multicast_list = qlcnic_set_multi,
381 .ndo_set_mac_address = qlcnic_set_mac,
382 .ndo_change_mtu = qlcnic_change_mtu,
383 .ndo_tx_timeout = qlcnic_tx_timeout,
384#ifdef CONFIG_NET_POLL_CONTROLLER
385 .ndo_poll_controller = qlcnic_poll_controller,
386#endif
387};
388
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000389static struct qlcnic_nic_template qlcnic_ops = {
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000390 .config_bridged_mode = qlcnic_config_bridged_mode,
391 .config_led = qlcnic_config_led,
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000392 .start_firmware = qlcnic_start_firmware
393};
394
395static struct qlcnic_nic_template qlcnic_vf_ops = {
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000396 .config_bridged_mode = qlcnicvf_config_bridged_mode,
397 .config_led = qlcnicvf_config_led,
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000398 .start_firmware = qlcnicvf_start_firmware
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000399};
400
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000401static void
402qlcnic_setup_intr(struct qlcnic_adapter *adapter)
403{
404 const struct qlcnic_legacy_intr_set *legacy_intrp;
405 struct pci_dev *pdev = adapter->pdev;
406 int err, num_msix;
407
408 if (adapter->rss_supported) {
409 num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
410 MSIX_ENTRIES_PER_ADAPTER : 2;
411 } else
412 num_msix = 1;
413
414 adapter->max_sds_rings = 1;
415
416 adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
417
418 legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
419
420 adapter->int_vec_bit = legacy_intrp->int_vec_bit;
421 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
422 legacy_intrp->tgt_status_reg);
423 adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
424 legacy_intrp->tgt_mask_reg);
425 adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
426
427 adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
428 ISR_INT_STATE_REG);
429
430 qlcnic_set_msix_bit(pdev, 0);
431
432 if (adapter->msix_supported) {
433
434 qlcnic_init_msix_entries(adapter, num_msix);
435 err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
436 if (err == 0) {
437 adapter->flags |= QLCNIC_MSIX_ENABLED;
438 qlcnic_set_msix_bit(pdev, 1);
439
440 if (adapter->rss_supported)
441 adapter->max_sds_rings = num_msix;
442
443 dev_info(&pdev->dev, "using msi-x interrupts\n");
444 return;
445 }
446
447 if (err > 0)
448 pci_disable_msix(pdev);
449
450 /* fall through for msi */
451 }
452
453 if (use_msi && !pci_enable_msi(pdev)) {
454 adapter->flags |= QLCNIC_MSI_ENABLED;
455 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
456 msi_tgt_status[adapter->ahw.pci_func]);
457 dev_info(&pdev->dev, "using msi interrupts\n");
458 adapter->msix_entries[0].vector = pdev->irq;
459 return;
460 }
461
462 dev_info(&pdev->dev, "using legacy interrupts\n");
463 adapter->msix_entries[0].vector = pdev->irq;
464}
465
466static void
467qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
468{
469 if (adapter->flags & QLCNIC_MSIX_ENABLED)
470 pci_disable_msix(adapter->pdev);
471 if (adapter->flags & QLCNIC_MSI_ENABLED)
472 pci_disable_msi(adapter->pdev);
473}
474
475static void
476qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
477{
478 if (adapter->ahw.pci_base0 != NULL)
479 iounmap(adapter->ahw.pci_base0);
480}
481
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000482static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000483qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
484{
Dan Carpentere88db3b2010-08-09 21:49:36 +0000485 struct qlcnic_pci_info *pci_info;
Julia Lawall900853a2010-08-16 10:23:51 +0000486 int i, ret = 0;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000487 u8 pfn;
488
Dan Carpentere88db3b2010-08-09 21:49:36 +0000489 pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
490 if (!pci_info)
491 return -ENOMEM;
492
Dan Carpenterca315ac2010-08-09 21:47:56 +0000493 adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000494 QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
Dan Carpentere88db3b2010-08-09 21:49:36 +0000495 if (!adapter->npars) {
Julia Lawall900853a2010-08-16 10:23:51 +0000496 ret = -ENOMEM;
Dan Carpentere88db3b2010-08-09 21:49:36 +0000497 goto err_pci_info;
498 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000499
Dan Carpenterca315ac2010-08-09 21:47:56 +0000500 adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000501 QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
502 if (!adapter->eswitch) {
Julia Lawall900853a2010-08-16 10:23:51 +0000503 ret = -ENOMEM;
Dan Carpenterca315ac2010-08-09 21:47:56 +0000504 goto err_npars;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000505 }
506
507 ret = qlcnic_get_pci_info(adapter, pci_info);
Dan Carpenterca315ac2010-08-09 21:47:56 +0000508 if (ret)
509 goto err_eswitch;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000510
Dan Carpenterca315ac2010-08-09 21:47:56 +0000511 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
512 pfn = pci_info[i].id;
513 if (pfn > QLCNIC_MAX_PCI_FUNC)
514 return QL_STATUS_INVALID_PARAM;
515 adapter->npars[pfn].active = pci_info[i].active;
516 adapter->npars[pfn].type = pci_info[i].type;
517 adapter->npars[pfn].phy_port = pci_info[i].default_port;
Dan Carpenterca315ac2010-08-09 21:47:56 +0000518 adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
519 adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000520 }
521
Dan Carpenterca315ac2010-08-09 21:47:56 +0000522 for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
523 adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
524
Dan Carpentere88db3b2010-08-09 21:49:36 +0000525 kfree(pci_info);
Dan Carpenterca315ac2010-08-09 21:47:56 +0000526 return 0;
527
528err_eswitch:
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000529 kfree(adapter->eswitch);
530 adapter->eswitch = NULL;
Dan Carpenterca315ac2010-08-09 21:47:56 +0000531err_npars:
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000532 kfree(adapter->npars);
Dan Carpenterca315ac2010-08-09 21:47:56 +0000533 adapter->npars = NULL;
Dan Carpentere88db3b2010-08-09 21:49:36 +0000534err_pci_info:
535 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000536
537 return ret;
538}
539
540static int
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000541qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
542{
543 u8 id;
544 u32 ref_count;
545 int i, ret = 1;
546 u32 data = QLCNIC_MGMT_FUNC;
547 void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
548
549 /* If other drivers are not in use set their privilege level */
Amit Kumar Salecha31018e02010-08-25 04:03:05 +0000550 ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000551 ret = qlcnic_api_lock(adapter);
552 if (ret)
553 goto err_lock;
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000554
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000555 if (qlcnic_config_npars) {
556 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
Rajesh K Borundia346fe762010-06-29 08:01:20 +0000557 id = i;
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000558 if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
559 id == adapter->ahw.pci_func)
560 continue;
561 data |= (qlcnic_config_npars &
562 QLC_DEV_SET_DRV(0xf, id));
563 }
564 } else {
565 data = readl(priv_op);
566 data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) |
567 (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
568 adapter->ahw.pci_func));
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000569 }
570 writel(data, priv_op);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000571 qlcnic_api_unlock(adapter);
572err_lock:
573 return ret;
574}
575
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000576static void
577qlcnic_check_vf(struct qlcnic_adapter *adapter)
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000578{
579 void __iomem *msix_base_addr;
580 void __iomem *priv_op;
581 u32 func;
582 u32 msix_base;
583 u32 op_mode, priv_level;
584
585 /* Determine FW API version */
586 adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000587
588 /* Find PCI function number */
589 pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
590 msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
591 msix_base = readl(msix_base_addr);
592 func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
593 adapter->ahw.pci_func = func;
594
595 /* Determine function privilege level */
596 priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
597 op_mode = readl(priv_op);
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000598 if (op_mode == QLC_DEV_DRV_DEFAULT)
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000599 priv_level = QLCNIC_MGMT_FUNC;
Anirban Chakraborty0e33c662010-06-16 09:07:27 +0000600 else
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000601 priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
602
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000603 if (priv_level == QLCNIC_NON_PRIV_FUNC) {
Anirban Chakraborty9f26f542010-06-01 11:33:09 +0000604 adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
605 dev_info(&adapter->pdev->dev,
606 "HAL Version: %d Non Privileged function\n",
607 adapter->fw_hal_version);
608 adapter->nic_ops = &qlcnic_vf_ops;
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000609 } else
610 adapter->nic_ops = &qlcnic_ops;
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000611}
612
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000613static int
614qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
615{
616 void __iomem *mem_ptr0 = NULL;
617 resource_size_t mem_base;
618 unsigned long mem_len, pci_len0 = 0;
619
620 struct pci_dev *pdev = adapter->pdev;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000621
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000622 /* remap phys address */
623 mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
624 mem_len = pci_resource_len(pdev, 0);
625
626 if (mem_len == QLCNIC_PCI_2MB_SIZE) {
627
628 mem_ptr0 = pci_ioremap_bar(pdev, 0);
629 if (mem_ptr0 == NULL) {
630 dev_err(&pdev->dev, "failed to map PCI bar 0\n");
631 return -EIO;
632 }
633 pci_len0 = mem_len;
634 } else {
635 return -EIO;
636 }
637
638 dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
639
640 adapter->ahw.pci_base0 = mem_ptr0;
641 adapter->ahw.pci_len0 = pci_len0;
642
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000643 qlcnic_check_vf(adapter);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000644
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000645 adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +0000646 QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000647
648 return 0;
649}
650
651static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
652{
653 struct pci_dev *pdev = adapter->pdev;
654 int i, found = 0;
655
656 for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
657 if (qlcnic_boards[i].vendor == pdev->vendor &&
658 qlcnic_boards[i].device == pdev->device &&
659 qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
660 qlcnic_boards[i].sub_device == pdev->subsystem_device) {
Sucheta Chakraborty02f6e462010-05-17 01:22:09 +0000661 sprintf(name, "%pM: %s" ,
662 adapter->mac_addr,
663 qlcnic_boards[i].short_name);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000664 found = 1;
665 break;
666 }
667
668 }
669
670 if (!found)
Sritej Velaga7f9a0c32010-06-17 02:56:39 +0000671 sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000672}
673
674static void
675qlcnic_check_options(struct qlcnic_adapter *adapter)
676{
677 u32 fw_major, fw_minor, fw_build;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000678 struct pci_dev *pdev = adapter->pdev;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000679
680 fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
681 fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
682 fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
683
684 adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
685
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +0000686 dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
687 fw_major, fw_minor, fw_build);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000688
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000689 adapter->flags &= ~QLCNIC_LRO_ENABLED;
690
691 if (adapter->ahw.port_type == QLCNIC_XGBE) {
692 adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
693 adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
694 } else if (adapter->ahw.port_type == QLCNIC_GBE) {
695 adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
696 adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
697 }
698
699 adapter->msix_supported = !!use_msi_x;
700 adapter->rss_supported = !!use_msi_x;
701
702 adapter->num_txd = MAX_CMD_DESCRIPTORS;
703
Sony Chacko251b0362010-08-19 05:08:24 +0000704 adapter->max_rds_rings = MAX_RDS_RINGS;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000705}
706
Rajesh Borundia174240a2010-08-31 17:17:47 +0000707static int
708qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
709{
710 int err;
711 struct qlcnic_info nic_info;
712
713 err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func);
714 if (err)
715 return err;
716
717 adapter->physical_port = nic_info.phys_port;
718 adapter->switch_mode = nic_info.switch_mode;
719 adapter->max_tx_ques = nic_info.max_tx_ques;
720 adapter->max_rx_ques = nic_info.max_rx_ques;
721 adapter->capabilities = nic_info.capabilities;
722 adapter->max_mac_filters = nic_info.max_mac_filters;
723 adapter->max_mtu = nic_info.max_mtu;
724
725 if (adapter->capabilities & BIT_6)
726 adapter->flags |= QLCNIC_ESWITCH_ENABLED;
727 else
728 adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
729
730 return err;
731}
732
Rajesh Borundia0325d692010-08-19 05:08:26 +0000733static void
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +0000734qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
735 struct qlcnic_esw_func_cfg *esw_cfg)
736{
737 if (esw_cfg->discard_tagged)
738 adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
739 else
740 adapter->flags |= QLCNIC_TAGGING_ENABLED;
741
742 if (esw_cfg->vlan_id)
743 adapter->pvid = esw_cfg->vlan_id;
744 else
745 adapter->pvid = 0;
746}
747
748static void
Rajesh Borundia0325d692010-08-19 05:08:26 +0000749qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
750 struct qlcnic_esw_func_cfg *esw_cfg)
751{
Sony Chackofe4d4342010-08-19 05:08:27 +0000752 adapter->flags &= ~QLCNIC_MACSPOOF;
Rajesh Borundia73733732010-08-31 17:17:50 +0000753 adapter->flags &= ~QLCNIC_MAC_OVERRIDE_DISABLED;
Rajesh Borundia7613c872010-08-31 17:17:48 +0000754
755 if (esw_cfg->mac_anti_spoof)
756 adapter->flags |= QLCNIC_MACSPOOF;
Sony Chackofe4d4342010-08-19 05:08:27 +0000757
Rajesh Borundia73733732010-08-31 17:17:50 +0000758 if (!esw_cfg->mac_override)
759 adapter->flags |= QLCNIC_MAC_OVERRIDE_DISABLED;
760
Rajesh Borundia0325d692010-08-19 05:08:26 +0000761 qlcnic_set_netdev_features(adapter, esw_cfg);
762}
763
764static int
765qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
766{
767 struct qlcnic_esw_func_cfg esw_cfg;
768
769 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
770 return 0;
771
772 esw_cfg.pci_func = adapter->ahw.pci_func;
773 if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg))
774 return -EIO;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +0000775 qlcnic_set_vlan_config(adapter, &esw_cfg);
Rajesh Borundia0325d692010-08-19 05:08:26 +0000776 qlcnic_set_eswitch_port_features(adapter, &esw_cfg);
777
778 return 0;
779}
780
781static void
782qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
783 struct qlcnic_esw_func_cfg *esw_cfg)
784{
785 struct net_device *netdev = adapter->netdev;
786 unsigned long features, vlan_features;
787
788 features = (NETIF_F_SG | NETIF_F_IP_CSUM |
789 NETIF_F_IPV6_CSUM | NETIF_F_GRO);
790 vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
791 NETIF_F_IPV6_CSUM);
792
793 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
794 features |= (NETIF_F_TSO | NETIF_F_TSO6);
795 vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
796 }
797 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
798 features |= NETIF_F_LRO;
799
800 if (esw_cfg->offload_flags & BIT_0) {
801 netdev->features |= features;
802 adapter->rx_csum = 1;
803 if (!(esw_cfg->offload_flags & BIT_1))
804 netdev->features &= ~NETIF_F_TSO;
805 if (!(esw_cfg->offload_flags & BIT_2))
806 netdev->features &= ~NETIF_F_TSO6;
807 } else {
808 netdev->features &= ~features;
809 adapter->rx_csum = 0;
810 }
811
812 netdev->vlan_features = (features & vlan_features);
813}
814
815static int
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000816qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
817{
818 void __iomem *priv_op;
819 u32 op_mode, priv_level;
820 int err = 0;
821
Rajesh Borundia174240a2010-08-31 17:17:47 +0000822 err = qlcnic_initialize_nic(adapter);
823 if (err)
824 return err;
825
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000826 if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
827 return 0;
828
829 priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
830 op_mode = readl(priv_op);
831 priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
832
833 if (op_mode == QLC_DEV_DRV_DEFAULT)
834 priv_level = QLCNIC_MGMT_FUNC;
835 else
836 priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
837
Rajesh Borundia174240a2010-08-31 17:17:47 +0000838 if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000839 if (priv_level == QLCNIC_MGMT_FUNC) {
840 adapter->op_mode = QLCNIC_MGMT_FUNC;
841 err = qlcnic_init_pci_info(adapter);
842 if (err)
843 return err;
844 /* Set privilege level for other functions */
845 qlcnic_set_function_modes(adapter);
846 dev_info(&adapter->pdev->dev,
847 "HAL Version: %d, Management function\n",
848 adapter->fw_hal_version);
849 } else if (priv_level == QLCNIC_PRIV_FUNC) {
850 adapter->op_mode = QLCNIC_PRIV_FUNC;
851 dev_info(&adapter->pdev->dev,
852 "HAL Version: %d, Privileged function\n",
853 adapter->fw_hal_version);
854 }
Rajesh Borundia174240a2010-08-31 17:17:47 +0000855 }
Anirban Chakraborty0866d962010-08-26 14:02:52 +0000856
857 adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
858
859 return err;
860}
861
862static int
Rajesh Borundia0325d692010-08-19 05:08:26 +0000863qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
864{
865 struct qlcnic_esw_func_cfg esw_cfg;
866 struct qlcnic_npar_info *npar;
867 u8 i;
868
Rajesh Borundia174240a2010-08-31 17:17:47 +0000869 if (adapter->need_fw_reset)
Rajesh Borundia0325d692010-08-19 05:08:26 +0000870 return 0;
871
872 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
873 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
874 continue;
875 memset(&esw_cfg, 0, sizeof(struct qlcnic_esw_func_cfg));
876 esw_cfg.pci_func = i;
877 esw_cfg.offload_flags = BIT_0;
Rajesh Borundia73733732010-08-31 17:17:50 +0000878 esw_cfg.mac_override = BIT_0;
Rajesh Borundia0325d692010-08-19 05:08:26 +0000879 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
880 esw_cfg.offload_flags |= (BIT_1 | BIT_2);
881 if (qlcnic_config_switch_port(adapter, &esw_cfg))
882 return -EIO;
883 npar = &adapter->npars[i];
884 npar->pvid = esw_cfg.vlan_id;
Rajesh Borundia73733732010-08-31 17:17:50 +0000885 npar->mac_override = esw_cfg.mac_override;
Rajesh Borundia0325d692010-08-19 05:08:26 +0000886 npar->mac_anti_spoof = esw_cfg.mac_anti_spoof;
887 npar->discard_tagged = esw_cfg.discard_tagged;
888 npar->promisc_mode = esw_cfg.promisc_mode;
889 npar->offload_flags = esw_cfg.offload_flags;
890 }
891
892 return 0;
893}
894
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000895static int
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000896qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
897 struct qlcnic_npar_info *npar, int pci_func)
898{
899 struct qlcnic_esw_func_cfg esw_cfg;
900 esw_cfg.op_mode = QLCNIC_PORT_DEFAULTS;
901 esw_cfg.pci_func = pci_func;
902 esw_cfg.vlan_id = npar->pvid;
Rajesh Borundia73733732010-08-31 17:17:50 +0000903 esw_cfg.mac_override = npar->mac_override;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000904 esw_cfg.discard_tagged = npar->discard_tagged;
905 esw_cfg.mac_anti_spoof = npar->mac_anti_spoof;
906 esw_cfg.offload_flags = npar->offload_flags;
907 esw_cfg.promisc_mode = npar->promisc_mode;
908 if (qlcnic_config_switch_port(adapter, &esw_cfg))
909 return -EIO;
910
911 esw_cfg.op_mode = QLCNIC_ADD_VLAN;
912 if (qlcnic_config_switch_port(adapter, &esw_cfg))
913 return -EIO;
914
915 return 0;
916}
917
918static int
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000919qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
920{
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000921 int i, err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000922 struct qlcnic_npar_info *npar;
923 struct qlcnic_info nic_info;
924
Rajesh Borundia174240a2010-08-31 17:17:47 +0000925 if (!adapter->need_fw_reset)
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000926 return 0;
927
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000928 /* Set the NPAR config data after FW reset */
929 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
930 npar = &adapter->npars[i];
931 if (npar->type != QLCNIC_TYPE_NIC)
932 continue;
933 err = qlcnic_get_nic_info(adapter, &nic_info, i);
934 if (err)
935 return err;
936 nic_info.min_tx_bw = npar->min_bw;
937 nic_info.max_tx_bw = npar->max_bw;
938 err = qlcnic_set_nic_info(adapter, &nic_info);
939 if (err)
940 return err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000941
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000942 if (npar->enable_pm) {
943 err = qlcnic_config_port_mirroring(adapter,
944 npar->dest_npar, 1, i);
945 if (err)
946 return err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000947 }
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000948 err = qlcnic_reset_eswitch_config(adapter, npar, i);
949 if (err)
950 return err;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000951 }
Rajesh Borundia4e8acb02010-08-19 05:08:25 +0000952 return 0;
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000953}
954
Amit Kumar Salecha78f84e12010-08-19 05:08:28 +0000955static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
956{
957 u8 npar_opt_timeo = QLCNIC_DEV_NPAR_OPER_TIMEO;
958 u32 npar_state;
959
960 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
961 return 0;
962
963 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
964 while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
965 msleep(1000);
966 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
967 }
968 if (!npar_opt_timeo) {
969 dev_err(&adapter->pdev->dev,
970 "Waiting for NPAR state to opertional timeout\n");
971 return -EIO;
972 }
973 return 0;
974}
975
Anirban Chakrabortycea89752010-07-13 20:33:35 +0000976static int
Rajesh Borundia174240a2010-08-31 17:17:47 +0000977qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)
978{
979 int err;
980
981 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
982 adapter->op_mode != QLCNIC_MGMT_FUNC)
983 return 0;
984
985 err = qlcnic_set_default_offload_settings(adapter);
986 if (err)
987 return err;
988
989 err = qlcnic_reset_npar_config(adapter);
990 if (err)
991 return err;
992
993 qlcnic_dev_set_npar_ready(adapter);
994
995 return err;
996}
997
998static int
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +0000999qlcnic_start_firmware(struct qlcnic_adapter *adapter)
1000{
Sony Chackod4066832010-08-19 05:08:31 +00001001 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001002
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00001003 err = qlcnic_can_start_firmware(adapter);
1004 if (err < 0)
1005 return err;
1006 else if (!err)
Sony Chackod4066832010-08-19 05:08:31 +00001007 goto check_fw_status;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001008
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +00001009 if (load_fw_file)
1010 qlcnic_request_firmware(adapter);
schacko8f891382010-06-17 02:56:40 +00001011 else {
Sony Chacko8cfdce02010-08-26 14:02:41 +00001012 err = qlcnic_check_flash_fw_ver(adapter);
1013 if (err)
schacko8f891382010-06-17 02:56:40 +00001014 goto err_out;
1015
Amit Kumar Salecha4d5bdb32010-05-17 01:22:11 +00001016 adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
schacko8f891382010-06-17 02:56:40 +00001017 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001018
1019 err = qlcnic_need_fw_reset(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001020 if (err == 0)
Sony Chacko4e708122010-08-31 17:17:44 +00001021 goto check_fw_status;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001022
Sony Chackod4066832010-08-19 05:08:31 +00001023 err = qlcnic_pinit_from_rom(adapter);
1024 if (err)
1025 goto err_out;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001026 qlcnic_set_port_mode(adapter);
1027
1028 err = qlcnic_load_firmware(adapter);
1029 if (err)
1030 goto err_out;
1031
1032 qlcnic_release_firmware(adapter);
Sony Chackod4066832010-08-19 05:08:31 +00001033 QLCWR32(adapter, CRB_DRIVER_VERSION, QLCNIC_DRIVER_VERSION);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001034
Sony Chackod4066832010-08-19 05:08:31 +00001035check_fw_status:
1036 err = qlcnic_check_fw_status(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001037 if (err)
1038 goto err_out;
1039
1040 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00001041 qlcnic_idc_debug_info(adapter, 1);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00001042
Anirban Chakraborty0866d962010-08-26 14:02:52 +00001043 err = qlcnic_check_eswitch_mode(adapter);
1044 if (err) {
1045 dev_err(&adapter->pdev->dev,
1046 "Memory allocation failed for eswitch\n");
1047 goto err_out;
1048 }
Rajesh Borundia174240a2010-08-31 17:17:47 +00001049 err = qlcnic_set_mgmt_operations(adapter);
1050 if (err)
1051 goto err_out;
1052
1053 qlcnic_check_options(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001054 adapter->need_fw_reset = 0;
1055
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001056 qlcnic_release_firmware(adapter);
1057 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001058
1059err_out:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001060 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
1061 dev_err(&adapter->pdev->dev, "Device state set to failed\n");
Anirban Chakraborty0866d962010-08-26 14:02:52 +00001062
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001063 qlcnic_release_firmware(adapter);
1064 return err;
1065}
1066
1067static int
1068qlcnic_request_irq(struct qlcnic_adapter *adapter)
1069{
1070 irq_handler_t handler;
1071 struct qlcnic_host_sds_ring *sds_ring;
1072 int err, ring;
1073
1074 unsigned long flags = 0;
1075 struct net_device *netdev = adapter->netdev;
1076 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
1077
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001078 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1079 handler = qlcnic_tmp_intr;
1080 if (!QLCNIC_IS_MSI_FAMILY(adapter))
1081 flags |= IRQF_SHARED;
1082
1083 } else {
1084 if (adapter->flags & QLCNIC_MSIX_ENABLED)
1085 handler = qlcnic_msix_intr;
1086 else if (adapter->flags & QLCNIC_MSI_ENABLED)
1087 handler = qlcnic_msi_intr;
1088 else {
1089 flags |= IRQF_SHARED;
1090 handler = qlcnic_intr;
1091 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001092 }
1093 adapter->irq = netdev->irq;
1094
1095 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1096 sds_ring = &recv_ctx->sds_rings[ring];
1097 sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
1098 err = request_irq(sds_ring->irq, handler,
1099 flags, sds_ring->name, sds_ring);
1100 if (err)
1101 return err;
1102 }
1103
1104 return 0;
1105}
1106
1107static void
1108qlcnic_free_irq(struct qlcnic_adapter *adapter)
1109{
1110 int ring;
1111 struct qlcnic_host_sds_ring *sds_ring;
1112
1113 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
1114
1115 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1116 sds_ring = &recv_ctx->sds_rings[ring];
1117 free_irq(sds_ring->irq, sds_ring);
1118 }
1119}
1120
1121static void
1122qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter)
1123{
1124 adapter->coal.flags = QLCNIC_INTR_DEFAULT;
1125 adapter->coal.normal.data.rx_time_us =
1126 QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
1127 adapter->coal.normal.data.rx_packets =
1128 QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
1129 adapter->coal.normal.data.tx_time_us =
1130 QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US;
1131 adapter->coal.normal.data.tx_packets =
1132 QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS;
1133}
1134
1135static int
1136__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
1137{
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001138 int ring;
1139 struct qlcnic_host_rds_ring *rds_ring;
1140
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001141 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1142 return -EIO;
1143
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001144 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
1145 return 0;
Rajesh Borundia0325d692010-08-19 05:08:26 +00001146 if (qlcnic_set_eswitch_port_config(adapter))
1147 return -EIO;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001148
1149 if (qlcnic_fw_create_ctx(adapter))
1150 return -EIO;
1151
1152 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1153 rds_ring = &adapter->recv_ctx.rds_rings[ring];
1154 qlcnic_post_rx_buffers(adapter, ring, rds_ring);
1155 }
1156
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001157 qlcnic_set_multi(netdev);
1158 qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
1159
1160 adapter->ahw.linkup = 0;
1161
1162 if (adapter->max_sds_rings > 1)
1163 qlcnic_config_rss(adapter, 1);
1164
1165 qlcnic_config_intr_coalesce(adapter);
1166
Sucheta Chakraborty24763d82010-08-17 00:34:25 +00001167 if (netdev->features & NETIF_F_LRO)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001168 qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
1169
1170 qlcnic_napi_enable(adapter);
1171
1172 qlcnic_linkevent_request(adapter, 1);
1173
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00001174 adapter->reset_context = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001175 set_bit(__QLCNIC_DEV_UP, &adapter->state);
1176 return 0;
1177}
1178
1179/* Usage: During resume and firmware recovery module.*/
1180
1181static int
1182qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
1183{
1184 int err = 0;
1185
1186 rtnl_lock();
1187 if (netif_running(netdev))
1188 err = __qlcnic_up(adapter, netdev);
1189 rtnl_unlock();
1190
1191 return err;
1192}
1193
1194static void
1195__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
1196{
1197 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1198 return;
1199
1200 if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))
1201 return;
1202
1203 smp_mb();
1204 spin_lock(&adapter->tx_clean_lock);
1205 netif_carrier_off(netdev);
1206 netif_tx_disable(netdev);
1207
1208 qlcnic_free_mac_list(adapter);
1209
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001210 if (adapter->fhash.fnum)
1211 qlcnic_delete_lb_filters(adapter);
1212
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001213 qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
1214
1215 qlcnic_napi_disable(adapter);
1216
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001217 qlcnic_fw_destroy_ctx(adapter);
1218
1219 qlcnic_reset_rx_buffers_list(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001220 qlcnic_release_tx_buffers(adapter);
1221 spin_unlock(&adapter->tx_clean_lock);
1222}
1223
1224/* Usage: During suspend and firmware recovery module */
1225
1226static void
1227qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
1228{
1229 rtnl_lock();
1230 if (netif_running(netdev))
1231 __qlcnic_down(adapter, netdev);
1232 rtnl_unlock();
1233
1234}
1235
1236static int
1237qlcnic_attach(struct qlcnic_adapter *adapter)
1238{
1239 struct net_device *netdev = adapter->netdev;
1240 struct pci_dev *pdev = adapter->pdev;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001241 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001242
1243 if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
1244 return 0;
1245
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001246 err = qlcnic_napi_add(adapter, netdev);
1247 if (err)
1248 return err;
1249
1250 err = qlcnic_alloc_sw_resources(adapter);
1251 if (err) {
1252 dev_err(&pdev->dev, "Error in setting sw resources\n");
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001253 goto err_out_napi_del;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001254 }
1255
1256 err = qlcnic_alloc_hw_resources(adapter);
1257 if (err) {
1258 dev_err(&pdev->dev, "Error in setting hw resources\n");
1259 goto err_out_free_sw;
1260 }
1261
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001262 err = qlcnic_request_irq(adapter);
1263 if (err) {
1264 dev_err(&pdev->dev, "failed to setup interrupt\n");
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001265 goto err_out_free_hw;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001266 }
1267
1268 qlcnic_init_coalesce_defaults(adapter);
1269
1270 qlcnic_create_sysfs_entries(adapter);
1271
1272 adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
1273 return 0;
1274
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001275err_out_free_hw:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001276 qlcnic_free_hw_resources(adapter);
1277err_out_free_sw:
1278 qlcnic_free_sw_resources(adapter);
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001279err_out_napi_del:
1280 qlcnic_napi_del(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001281 return err;
1282}
1283
1284static void
1285qlcnic_detach(struct qlcnic_adapter *adapter)
1286{
1287 if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
1288 return;
1289
1290 qlcnic_remove_sysfs_entries(adapter);
1291
1292 qlcnic_free_hw_resources(adapter);
1293 qlcnic_release_rx_buffers(adapter);
1294 qlcnic_free_irq(adapter);
1295 qlcnic_napi_del(adapter);
1296 qlcnic_free_sw_resources(adapter);
1297
1298 adapter->is_up = 0;
1299}
1300
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001301void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
1302{
1303 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1304 struct qlcnic_host_sds_ring *sds_ring;
1305 int ring;
1306
Sucheta Chakraborty78ad3892010-05-17 01:22:12 +00001307 clear_bit(__QLCNIC_DEV_UP, &adapter->state);
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001308 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1309 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1310 sds_ring = &adapter->recv_ctx.sds_rings[ring];
1311 qlcnic_disable_int(sds_ring);
1312 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001313 }
1314
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001315 qlcnic_fw_destroy_ctx(adapter);
1316
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001317 qlcnic_detach(adapter);
1318
1319 adapter->diag_test = 0;
1320 adapter->max_sds_rings = max_sds_rings;
1321
1322 if (qlcnic_attach(adapter))
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001323 goto out;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001324
1325 if (netif_running(netdev))
1326 __qlcnic_up(adapter, netdev);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001327out:
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001328 netif_device_attach(netdev);
1329}
1330
1331int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
1332{
1333 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1334 struct qlcnic_host_sds_ring *sds_ring;
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001335 struct qlcnic_host_rds_ring *rds_ring;
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001336 int ring;
1337 int ret;
1338
1339 netif_device_detach(netdev);
1340
1341 if (netif_running(netdev))
1342 __qlcnic_down(adapter, netdev);
1343
1344 qlcnic_detach(adapter);
1345
1346 adapter->max_sds_rings = 1;
1347 adapter->diag_test = test;
1348
1349 ret = qlcnic_attach(adapter);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001350 if (ret) {
1351 netif_device_attach(netdev);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001352 return ret;
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001353 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001354
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001355 ret = qlcnic_fw_create_ctx(adapter);
1356 if (ret) {
1357 qlcnic_detach(adapter);
Sony Chacko57e46242010-07-24 18:32:18 +00001358 netif_device_attach(netdev);
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00001359 return ret;
1360 }
1361
1362 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1363 rds_ring = &adapter->recv_ctx.rds_rings[ring];
1364 qlcnic_post_rx_buffers(adapter, ring, rds_ring);
1365 }
1366
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00001367 if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
1368 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
1369 sds_ring = &adapter->recv_ctx.sds_rings[ring];
1370 qlcnic_enable_int(sds_ring);
1371 }
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001372 }
Sucheta Chakraborty78ad3892010-05-17 01:22:12 +00001373 set_bit(__QLCNIC_DEV_UP, &adapter->state);
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00001374
1375 return 0;
1376}
1377
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00001378/* Reset context in hardware only */
1379static int
1380qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
1381{
1382 struct net_device *netdev = adapter->netdev;
1383
1384 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1385 return -EBUSY;
1386
1387 netif_device_detach(netdev);
1388
1389 qlcnic_down(adapter, netdev);
1390
1391 qlcnic_up(adapter, netdev);
1392
1393 netif_device_attach(netdev);
1394
1395 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1396 return 0;
1397}
1398
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001399int
1400qlcnic_reset_context(struct qlcnic_adapter *adapter)
1401{
1402 int err = 0;
1403 struct net_device *netdev = adapter->netdev;
1404
1405 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1406 return -EBUSY;
1407
1408 if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) {
1409
1410 netif_device_detach(netdev);
1411
1412 if (netif_running(netdev))
1413 __qlcnic_down(adapter, netdev);
1414
1415 qlcnic_detach(adapter);
1416
1417 if (netif_running(netdev)) {
1418 err = qlcnic_attach(adapter);
1419 if (!err)
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00001420 __qlcnic_up(adapter, netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001421 }
1422
1423 netif_device_attach(netdev);
1424 }
1425
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001426 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1427 return err;
1428}
1429
1430static int
1431qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001432 struct net_device *netdev, u8 pci_using_dac)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001433{
1434 int err;
1435 struct pci_dev *pdev = adapter->pdev;
1436
1437 adapter->rx_csum = 1;
1438 adapter->mc_enabled = 0;
1439 adapter->max_mc_count = 38;
1440
1441 netdev->netdev_ops = &qlcnic_netdev_ops;
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00001442 netdev->watchdog_timeo = 5*HZ;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001443
1444 qlcnic_change_mtu(netdev, netdev->mtu);
1445
1446 SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
1447
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001448 netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +00001449 NETIF_F_IPV6_CSUM | NETIF_F_GRO);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001450 netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
Anirban Chakrabortyac8d0c42010-07-09 13:14:58 +00001451 NETIF_F_IPV6_CSUM);
1452
1453 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
1454 netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
1455 netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
1456 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001457
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001458 if (pci_using_dac) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001459 netdev->features |= NETIF_F_HIGHDMA;
1460 netdev->vlan_features |= NETIF_F_HIGHDMA;
1461 }
1462
1463 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
1464 netdev->features |= (NETIF_F_HW_VLAN_TX);
1465
1466 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
1467 netdev->features |= NETIF_F_LRO;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001468 netdev->irq = adapter->msix_entries[0].vector;
1469
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001470 netif_carrier_off(netdev);
1471 netif_stop_queue(netdev);
1472
1473 err = register_netdev(netdev);
1474 if (err) {
1475 dev_err(&pdev->dev, "failed to register net device\n");
1476 return err;
1477 }
1478
1479 return 0;
1480}
1481
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001482static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
1483{
1484 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
1485 !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
1486 *pci_using_dac = 1;
1487 else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) &&
1488 !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
1489 *pci_using_dac = 0;
1490 else {
1491 dev_err(&pdev->dev, "Unable to set DMA mask, aborting\n");
1492 return -EIO;
1493 }
1494
1495 return 0;
1496}
1497
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001498static int __devinit
1499qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1500{
1501 struct net_device *netdev = NULL;
1502 struct qlcnic_adapter *adapter = NULL;
1503 int err;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001504 uint8_t revision_id;
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001505 uint8_t pci_using_dac;
Rajesh Borundiada48e6c2010-08-31 17:17:46 +00001506 char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001507
1508 err = pci_enable_device(pdev);
1509 if (err)
1510 return err;
1511
1512 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
1513 err = -ENODEV;
1514 goto err_out_disable_pdev;
1515 }
1516
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001517 err = qlcnic_set_dma_mask(pdev, &pci_using_dac);
1518 if (err)
1519 goto err_out_disable_pdev;
1520
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001521 err = pci_request_regions(pdev, qlcnic_driver_name);
1522 if (err)
1523 goto err_out_disable_pdev;
1524
1525 pci_set_master(pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00001526 pci_enable_pcie_error_reporting(pdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001527
1528 netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
1529 if (!netdev) {
1530 dev_err(&pdev->dev, "failed to allocate net_device\n");
1531 err = -ENOMEM;
1532 goto err_out_free_res;
1533 }
1534
1535 SET_NETDEV_DEV(netdev, &pdev->dev);
1536
1537 adapter = netdev_priv(netdev);
1538 adapter->netdev = netdev;
1539 adapter->pdev = pdev;
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00001540 adapter->dev_rst_time = jiffies;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001541
1542 revision_id = pdev->revision;
1543 adapter->ahw.revision_id = revision_id;
1544
1545 rwlock_init(&adapter->ahw.crb_lock);
1546 mutex_init(&adapter->ahw.mem_lock);
1547
1548 spin_lock_init(&adapter->tx_clean_lock);
1549 INIT_LIST_HEAD(&adapter->mac_list);
1550
1551 err = qlcnic_setup_pci_map(adapter);
1552 if (err)
1553 goto err_out_free_netdev;
1554
1555 /* This will be reset for mezz cards */
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001556 adapter->portnum = adapter->ahw.pci_func;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001557
1558 err = qlcnic_get_board_info(adapter);
1559 if (err) {
1560 dev_err(&pdev->dev, "Error getting board config info.\n");
1561 goto err_out_iounmap;
1562 }
1563
Sony Chacko8cfdce02010-08-26 14:02:41 +00001564 err = qlcnic_setup_idc_param(adapter);
1565 if (err)
Sucheta Chakrabortyb3a24642010-05-13 03:07:48 +00001566 goto err_out_iounmap;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001567
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00001568 err = adapter->nic_ops->start_firmware(adapter);
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001569 if (err) {
1570 dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001571 goto err_out_decr_ref;
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00001572 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001573
Rajesh Borundiada48e6c2010-08-31 17:17:46 +00001574 if (qlcnic_read_mac_addr(adapter))
1575 dev_warn(&pdev->dev, "failed to read mac addr\n");
1576
1577 if (adapter->portnum == 0) {
1578 get_brd_name(adapter, brd_name);
1579
1580 pr_info("%s: %s Board Chip rev 0x%x\n",
1581 module_name(THIS_MODULE),
1582 brd_name, adapter->ahw.revision_id);
1583 }
1584
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001585 qlcnic_clear_stats(adapter);
1586
1587 qlcnic_setup_intr(adapter);
1588
Amit Kumar Salecha1bb09fb2010-05-14 03:07:46 -07001589 err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001590 if (err)
1591 goto err_out_disable_msi;
1592
1593 pci_set_drvdata(pdev, adapter);
1594
1595 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
1596
1597 switch (adapter->ahw.port_type) {
1598 case QLCNIC_GBE:
1599 dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
1600 adapter->netdev->name);
1601 break;
1602 case QLCNIC_XGBE:
1603 dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
1604 adapter->netdev->name);
1605 break;
1606 }
1607
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001608 qlcnic_alloc_lb_filters_mem(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001609 qlcnic_create_diag_entries(adapter);
1610
1611 return 0;
1612
1613err_out_disable_msi:
1614 qlcnic_teardown_intr(adapter);
1615
1616err_out_decr_ref:
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00001617 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001618
1619err_out_iounmap:
1620 qlcnic_cleanup_pci_map(adapter);
1621
1622err_out_free_netdev:
1623 free_netdev(netdev);
1624
1625err_out_free_res:
1626 pci_release_regions(pdev);
1627
1628err_out_disable_pdev:
1629 pci_set_drvdata(pdev, NULL);
1630 pci_disable_device(pdev);
1631 return err;
1632}
1633
1634static void __devexit qlcnic_remove(struct pci_dev *pdev)
1635{
1636 struct qlcnic_adapter *adapter;
1637 struct net_device *netdev;
1638
1639 adapter = pci_get_drvdata(pdev);
1640 if (adapter == NULL)
1641 return;
1642
1643 netdev = adapter->netdev;
1644
1645 qlcnic_cancel_fw_work(adapter);
1646
1647 unregister_netdev(netdev);
1648
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001649 qlcnic_detach(adapter);
1650
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001651 if (adapter->npars != NULL)
1652 kfree(adapter->npars);
1653 if (adapter->eswitch != NULL)
1654 kfree(adapter->eswitch);
1655
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00001656 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001657
1658 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1659
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001660 qlcnic_free_lb_filters_mem(adapter);
1661
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001662 qlcnic_teardown_intr(adapter);
1663
1664 qlcnic_remove_diag_entries(adapter);
1665
1666 qlcnic_cleanup_pci_map(adapter);
1667
1668 qlcnic_release_firmware(adapter);
1669
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00001670 pci_disable_pcie_error_reporting(pdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001671 pci_release_regions(pdev);
1672 pci_disable_device(pdev);
1673 pci_set_drvdata(pdev, NULL);
1674
1675 free_netdev(netdev);
1676}
1677static int __qlcnic_shutdown(struct pci_dev *pdev)
1678{
1679 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
1680 struct net_device *netdev = adapter->netdev;
1681 int retval;
1682
1683 netif_device_detach(netdev);
1684
1685 qlcnic_cancel_fw_work(adapter);
1686
1687 if (netif_running(netdev))
1688 qlcnic_down(adapter, netdev);
1689
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00001690 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001691
1692 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1693
1694 retval = pci_save_state(pdev);
1695 if (retval)
1696 return retval;
1697
1698 if (qlcnic_wol_supported(adapter)) {
1699 pci_enable_wake(pdev, PCI_D3cold, 1);
1700 pci_enable_wake(pdev, PCI_D3hot, 1);
1701 }
1702
1703 return 0;
1704}
1705
1706static void qlcnic_shutdown(struct pci_dev *pdev)
1707{
1708 if (__qlcnic_shutdown(pdev))
1709 return;
1710
1711 pci_disable_device(pdev);
1712}
1713
1714#ifdef CONFIG_PM
1715static int
1716qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
1717{
1718 int retval;
1719
1720 retval = __qlcnic_shutdown(pdev);
1721 if (retval)
1722 return retval;
1723
1724 pci_set_power_state(pdev, pci_choose_state(pdev, state));
1725 return 0;
1726}
1727
1728static int
1729qlcnic_resume(struct pci_dev *pdev)
1730{
1731 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
1732 struct net_device *netdev = adapter->netdev;
1733 int err;
1734
1735 err = pci_enable_device(pdev);
1736 if (err)
1737 return err;
1738
1739 pci_set_power_state(pdev, PCI_D0);
1740 pci_set_master(pdev);
1741 pci_restore_state(pdev);
1742
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00001743 err = adapter->nic_ops->start_firmware(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001744 if (err) {
1745 dev_err(&pdev->dev, "failed to start firmware\n");
1746 return err;
1747 }
1748
1749 if (netif_running(netdev)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001750 err = qlcnic_up(adapter, netdev);
1751 if (err)
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00001752 goto done;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001753
1754 qlcnic_config_indev_addr(netdev, NETDEV_UP);
1755 }
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00001756done:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001757 netif_device_attach(netdev);
1758 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
1759 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001760}
1761#endif
1762
1763static int qlcnic_open(struct net_device *netdev)
1764{
1765 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1766 int err;
1767
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001768 err = qlcnic_attach(adapter);
1769 if (err)
1770 return err;
1771
1772 err = __qlcnic_up(adapter, netdev);
1773 if (err)
1774 goto err_out;
1775
1776 netif_start_queue(netdev);
1777
1778 return 0;
1779
1780err_out:
1781 qlcnic_detach(adapter);
1782 return err;
1783}
1784
1785/*
1786 * qlcnic_close - Disables a network interface entry point
1787 */
1788static int qlcnic_close(struct net_device *netdev)
1789{
1790 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1791
1792 __qlcnic_down(adapter, netdev);
1793 return 0;
1794}
1795
1796static void
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001797qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
1798{
1799 void *head;
1800 int i;
1801
1802 if (!qlcnic_mac_learn)
1803 return;
1804
1805 spin_lock_init(&adapter->mac_learn_lock);
1806
1807 head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
1808 GFP_KERNEL);
1809 if (!head)
1810 return;
1811
1812 adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
1813 adapter->fhash.fhead = (struct hlist_head *)head;
1814
1815 for (i = 0; i < adapter->fhash.fmax; i++)
1816 INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
1817}
1818
1819static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
1820{
1821 if (adapter->fhash.fmax && adapter->fhash.fhead)
1822 kfree(adapter->fhash.fhead);
1823
1824 adapter->fhash.fhead = NULL;
1825 adapter->fhash.fmax = 0;
1826}
1827
1828static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001829 u64 uaddr, u16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001830{
1831 struct cmd_desc_type0 *hwdesc;
1832 struct qlcnic_nic_req *req;
1833 struct qlcnic_mac_req *mac_req;
1834 u32 producer;
1835 u64 word;
1836
1837 producer = tx_ring->producer;
1838 hwdesc = &tx_ring->desc_head[tx_ring->producer];
1839
1840 req = (struct qlcnic_nic_req *)hwdesc;
1841 memset(req, 0, sizeof(struct qlcnic_nic_req));
1842 req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
1843
1844 word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
1845 req->req_hdr = cpu_to_le64(word);
1846
1847 mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001848 mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001849 memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
1850
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001851 req->words[1] = cpu_to_le64(vlan_id);
1852
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001853 tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
1854}
1855
1856#define QLCNIC_MAC_HASH(MAC)\
1857 ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
1858
1859static void
1860qlcnic_send_filter(struct qlcnic_adapter *adapter,
1861 struct qlcnic_host_tx_ring *tx_ring,
1862 struct cmd_desc_type0 *first_desc,
1863 struct sk_buff *skb)
1864{
1865 struct ethhdr *phdr = (struct ethhdr *)(skb->data);
1866 struct qlcnic_filter *fil, *tmp_fil;
1867 struct hlist_node *tmp_hnode, *n;
1868 struct hlist_head *head;
1869 u64 src_addr = 0;
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001870 u16 vlan_id = 0;
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001871 u8 hindex;
1872
1873 if (!compare_ether_addr(phdr->h_source, adapter->mac_addr))
1874 return;
1875
1876 if (adapter->fhash.fnum >= adapter->fhash.fmax)
1877 return;
1878
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001879 /* Only NPAR capable devices support vlan based learning*/
1880 if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
1881 vlan_id = first_desc->vlan_TCI;
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001882 memcpy(&src_addr, phdr->h_source, ETH_ALEN);
1883 hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
1884 head = &(adapter->fhash.fhead[hindex]);
1885
1886 hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001887 if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
1888 tmp_fil->vlan_id == vlan_id) {
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001889 tmp_fil->ftime = jiffies;
1890 return;
1891 }
1892 }
1893
1894 fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
1895 if (!fil)
1896 return;
1897
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001898 qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001899
1900 fil->ftime = jiffies;
Amit Kumar Salecha03c5d772010-08-31 17:17:52 +00001901 fil->vlan_id = vlan_id;
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00001902 memcpy(fil->faddr, &src_addr, ETH_ALEN);
1903 spin_lock(&adapter->mac_learn_lock);
1904 hlist_add_head(&(fil->fnode), head);
1905 adapter->fhash.fnum++;
1906 spin_unlock(&adapter->mac_learn_lock);
1907}
1908
1909static void
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001910qlcnic_tso_check(struct net_device *netdev,
1911 struct qlcnic_host_tx_ring *tx_ring,
1912 struct cmd_desc_type0 *first_desc,
1913 struct sk_buff *skb)
1914{
1915 u8 opcode = TX_ETHER_PKT;
1916 __be16 protocol = skb->protocol;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001917 u16 flags = 0;
1918 int copied, offset, copy_len, hdr_len = 0, tso = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001919 struct cmd_desc_type0 *hwdesc;
1920 struct vlan_ethhdr *vh;
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00001921 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001922 u32 producer = tx_ring->producer;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001923 int vlan_oob = first_desc->flags_opcode & cpu_to_le16(FLAGS_VLAN_OOB);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001924
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001925 if (*(skb->data) & BIT_0) {
1926 flags |= BIT_0;
1927 memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
1928 }
1929
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001930 if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
1931 skb_shinfo(skb)->gso_size > 0) {
1932
1933 hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1934
1935 first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
1936 first_desc->total_hdr_length = hdr_len;
1937 if (vlan_oob) {
1938 first_desc->total_hdr_length += VLAN_HLEN;
1939 first_desc->tcp_hdr_offset = VLAN_HLEN;
1940 first_desc->ip_hdr_offset = VLAN_HLEN;
1941 /* Only in case of TSO on vlan device */
1942 flags |= FLAGS_VLAN_TAGGED;
1943 }
1944
1945 opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
1946 TX_TCP_LSO6 : TX_TCP_LSO;
1947 tso = 1;
1948
1949 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
1950 u8 l4proto;
1951
1952 if (protocol == cpu_to_be16(ETH_P_IP)) {
1953 l4proto = ip_hdr(skb)->protocol;
1954
1955 if (l4proto == IPPROTO_TCP)
1956 opcode = TX_TCP_PKT;
1957 else if (l4proto == IPPROTO_UDP)
1958 opcode = TX_UDP_PKT;
1959 } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
1960 l4proto = ipv6_hdr(skb)->nexthdr;
1961
1962 if (l4proto == IPPROTO_TCP)
1963 opcode = TX_TCPV6_PKT;
1964 else if (l4proto == IPPROTO_UDP)
1965 opcode = TX_UDPV6_PKT;
1966 }
1967 }
1968
1969 first_desc->tcp_hdr_offset += skb_transport_offset(skb);
1970 first_desc->ip_hdr_offset += skb_network_offset(skb);
1971 qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
1972
1973 if (!tso)
1974 return;
1975
1976 /* For LSO, we need to copy the MAC/IP/TCP headers into
1977 * the descriptor ring
1978 */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001979 copied = 0;
1980 offset = 2;
1981
1982 if (vlan_oob) {
1983 /* Create a TSO vlan header template for firmware */
1984
1985 hwdesc = &tx_ring->desc_head[producer];
1986 tx_ring->cmd_buf_arr[producer].skb = NULL;
1987
1988 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
1989 hdr_len + VLAN_HLEN);
1990
1991 vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
1992 skb_copy_from_linear_data(skb, vh, 12);
1993 vh->h_vlan_proto = htons(ETH_P_8021Q);
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001994 vh->h_vlan_TCI = htons(first_desc->vlan_TCI);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001995 skb_copy_from_linear_data_offset(skb, 12,
1996 (char *)vh + 16, copy_len - 16);
1997
1998 copied = copy_len - VLAN_HLEN;
1999 offset = 0;
2000
2001 producer = get_next_index(producer, tx_ring->num_desc);
2002 }
2003
2004 while (copied < hdr_len) {
2005
2006 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
2007 (hdr_len - copied));
2008
2009 hwdesc = &tx_ring->desc_head[producer];
2010 tx_ring->cmd_buf_arr[producer].skb = NULL;
2011
2012 skb_copy_from_linear_data_offset(skb, copied,
2013 (char *)hwdesc + offset, copy_len);
2014
2015 copied += copy_len;
2016 offset = 0;
2017
2018 producer = get_next_index(producer, tx_ring->num_desc);
2019 }
2020
2021 tx_ring->producer = producer;
2022 barrier();
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00002023 adapter->stats.lso_frames++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002024}
2025
2026static int
2027qlcnic_map_tx_skb(struct pci_dev *pdev,
2028 struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
2029{
2030 struct qlcnic_skb_frag *nf;
2031 struct skb_frag_struct *frag;
2032 int i, nr_frags;
2033 dma_addr_t map;
2034
2035 nr_frags = skb_shinfo(skb)->nr_frags;
2036 nf = &pbuf->frag_array[0];
2037
2038 map = pci_map_single(pdev, skb->data,
2039 skb_headlen(skb), PCI_DMA_TODEVICE);
2040 if (pci_dma_mapping_error(pdev, map))
2041 goto out_err;
2042
2043 nf->dma = map;
2044 nf->length = skb_headlen(skb);
2045
2046 for (i = 0; i < nr_frags; i++) {
2047 frag = &skb_shinfo(skb)->frags[i];
2048 nf = &pbuf->frag_array[i+1];
2049
2050 map = pci_map_page(pdev, frag->page, frag->page_offset,
2051 frag->size, PCI_DMA_TODEVICE);
2052 if (pci_dma_mapping_error(pdev, map))
2053 goto unwind;
2054
2055 nf->dma = map;
2056 nf->length = frag->size;
2057 }
2058
2059 return 0;
2060
2061unwind:
2062 while (--i >= 0) {
2063 nf = &pbuf->frag_array[i+1];
2064 pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
2065 }
2066
2067 nf = &pbuf->frag_array[0];
2068 pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
2069
2070out_err:
2071 return -ENOMEM;
2072}
2073
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00002074static int
2075qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter,
2076 struct sk_buff *skb,
2077 struct cmd_desc_type0 *first_desc)
2078{
2079 u8 opcode = 0;
2080 u16 flags = 0;
2081 __be16 protocol = skb->protocol;
2082 struct vlan_ethhdr *vh;
2083
2084 if (protocol == cpu_to_be16(ETH_P_8021Q)) {
2085 vh = (struct vlan_ethhdr *)skb->data;
2086 protocol = vh->h_vlan_encapsulated_proto;
2087 flags = FLAGS_VLAN_TAGGED;
2088 qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI));
2089 } else if (vlan_tx_tag_present(skb)) {
2090 flags = FLAGS_VLAN_OOB;
2091 qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb));
2092 }
2093 if (unlikely(adapter->pvid)) {
2094 if (first_desc->vlan_TCI &&
2095 !(adapter->flags & QLCNIC_TAGGING_ENABLED))
2096 return -EIO;
2097 if (first_desc->vlan_TCI &&
2098 (adapter->flags & QLCNIC_TAGGING_ENABLED))
2099 goto set_flags;
2100
2101 flags = FLAGS_VLAN_OOB;
2102 qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid);
2103 }
2104set_flags:
2105 qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
2106 return 0;
2107}
2108
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002109static inline void
2110qlcnic_clear_cmddesc(u64 *desc)
2111{
2112 desc[0] = 0ULL;
2113 desc[2] = 0ULL;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00002114 desc[7] = 0ULL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002115}
2116
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00002117netdev_tx_t
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002118qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
2119{
2120 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2121 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
2122 struct qlcnic_cmd_buffer *pbuf;
2123 struct qlcnic_skb_frag *buffrag;
2124 struct cmd_desc_type0 *hwdesc, *first_desc;
2125 struct pci_dev *pdev;
Rajesh Borundiadcb50af2010-08-31 17:17:49 +00002126 struct ethhdr *phdr;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002127 int i, k;
2128
2129 u32 producer;
2130 int frag_count, no_of_desc;
2131 u32 num_txd = tx_ring->num_desc;
2132
Amit Kumar Salecha780ab792010-04-22 02:51:41 +00002133 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
2134 netif_stop_queue(netdev);
2135 return NETDEV_TX_BUSY;
2136 }
2137
Sony Chackofe4d4342010-08-19 05:08:27 +00002138 if (adapter->flags & QLCNIC_MACSPOOF) {
Rajesh Borundiadcb50af2010-08-31 17:17:49 +00002139 phdr = (struct ethhdr *)skb->data;
2140 if (compare_ether_addr(phdr->h_source,
Sony Chackofe4d4342010-08-19 05:08:27 +00002141 adapter->mac_addr))
2142 goto drop_packet;
2143 }
2144
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002145 frag_count = skb_shinfo(skb)->nr_frags + 1;
2146
2147 /* 4 fragments per cmd des */
2148 no_of_desc = (frag_count + 3) >> 2;
2149
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002150 if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002151 netif_stop_queue(netdev);
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002152 smp_mb();
2153 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
2154 netif_start_queue(netdev);
2155 else {
2156 adapter->stats.xmit_off++;
2157 return NETDEV_TX_BUSY;
2158 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002159 }
2160
2161 producer = tx_ring->producer;
2162 pbuf = &tx_ring->cmd_buf_arr[producer];
2163
2164 pdev = adapter->pdev;
2165
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00002166 first_desc = hwdesc = &tx_ring->desc_head[producer];
2167 qlcnic_clear_cmddesc((u64 *)hwdesc);
2168
2169 if (qlcnic_check_tx_tagging(adapter, skb, first_desc))
2170 goto drop_packet;
2171
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00002172 if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
2173 adapter->stats.tx_dma_map_error++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002174 goto drop_packet;
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00002175 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002176
2177 pbuf->skb = skb;
2178 pbuf->frag_count = frag_count;
2179
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002180 qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
2181 qlcnic_set_tx_port(first_desc, adapter->portnum);
2182
2183 for (i = 0; i < frag_count; i++) {
2184
2185 k = i % 4;
2186
2187 if ((k == 0) && (i > 0)) {
2188 /* move to next desc.*/
2189 producer = get_next_index(producer, num_txd);
2190 hwdesc = &tx_ring->desc_head[producer];
2191 qlcnic_clear_cmddesc((u64 *)hwdesc);
2192 tx_ring->cmd_buf_arr[producer].skb = NULL;
2193 }
2194
2195 buffrag = &pbuf->frag_array[i];
2196
2197 hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
2198 switch (k) {
2199 case 0:
2200 hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
2201 break;
2202 case 1:
2203 hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
2204 break;
2205 case 2:
2206 hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
2207 break;
2208 case 3:
2209 hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
2210 break;
2211 }
2212 }
2213
2214 tx_ring->producer = get_next_index(producer, num_txd);
2215
2216 qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
2217
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00002218 if (qlcnic_mac_learn)
2219 qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
2220
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002221 qlcnic_update_cmd_producer(adapter, tx_ring);
2222
2223 adapter->stats.txbytes += skb->len;
2224 adapter->stats.xmitcalled++;
2225
2226 return NETDEV_TX_OK;
2227
2228drop_packet:
2229 adapter->stats.txdropped++;
2230 dev_kfree_skb_any(skb);
2231 return NETDEV_TX_OK;
2232}
2233
2234static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
2235{
2236 struct net_device *netdev = adapter->netdev;
2237 u32 temp, temp_state, temp_val;
2238 int rv = 0;
2239
2240 temp = QLCRD32(adapter, CRB_TEMP_STATE);
2241
2242 temp_state = qlcnic_get_temp_state(temp);
2243 temp_val = qlcnic_get_temp_val(temp);
2244
2245 if (temp_state == QLCNIC_TEMP_PANIC) {
2246 dev_err(&netdev->dev,
2247 "Device temperature %d degrees C exceeds"
2248 " maximum allowed. Hardware has been shut down.\n",
2249 temp_val);
2250 rv = 1;
2251 } else if (temp_state == QLCNIC_TEMP_WARN) {
2252 if (adapter->temp == QLCNIC_TEMP_NORMAL) {
2253 dev_err(&netdev->dev,
2254 "Device temperature %d degrees C "
2255 "exceeds operating range."
2256 " Immediate action needed.\n",
2257 temp_val);
2258 }
2259 } else {
2260 if (adapter->temp == QLCNIC_TEMP_WARN) {
2261 dev_info(&netdev->dev,
2262 "Device temperature is now %d degrees C"
2263 " in normal range.\n", temp_val);
2264 }
2265 }
2266 adapter->temp = temp_state;
2267 return rv;
2268}
2269
2270void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
2271{
2272 struct net_device *netdev = adapter->netdev;
2273
2274 if (adapter->ahw.linkup && !linkup) {
Sony Chacko69324272010-08-17 00:34:23 +00002275 netdev_info(netdev, "NIC Link is down\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002276 adapter->ahw.linkup = 0;
2277 if (netif_running(netdev)) {
2278 netif_carrier_off(netdev);
2279 netif_stop_queue(netdev);
2280 }
2281 } else if (!adapter->ahw.linkup && linkup) {
Sony Chacko69324272010-08-17 00:34:23 +00002282 netdev_info(netdev, "NIC Link is up\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002283 adapter->ahw.linkup = 1;
2284 if (netif_running(netdev)) {
2285 netif_carrier_on(netdev);
2286 netif_wake_queue(netdev);
2287 }
2288 }
2289}
2290
2291static void qlcnic_tx_timeout(struct net_device *netdev)
2292{
2293 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2294
2295 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
2296 return;
2297
2298 dev_err(&netdev->dev, "transmit timeout, resetting.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002299
2300 if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002301 adapter->need_fw_reset = 1;
2302 else
2303 adapter->reset_context = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002304}
2305
2306static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
2307{
2308 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2309 struct net_device_stats *stats = &netdev->stats;
2310
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002311 stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
2312 stats->tx_packets = adapter->stats.xmitfinished;
Sucheta Chakraborty7e382592010-05-17 01:22:10 +00002313 stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002314 stats->tx_bytes = adapter->stats.txbytes;
2315 stats->rx_dropped = adapter->stats.rxdropped;
2316 stats->tx_dropped = adapter->stats.txdropped;
2317
2318 return stats;
2319}
2320
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00002321static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002322{
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002323 u32 status;
2324
2325 status = readl(adapter->isr_int_vec);
2326
2327 if (!(status & adapter->int_vec_bit))
2328 return IRQ_NONE;
2329
2330 /* check interrupt state machine, to be sure */
2331 status = readl(adapter->crb_int_state_reg);
2332 if (!ISR_LEGACY_INT_TRIGGERED(status))
2333 return IRQ_NONE;
2334
2335 writel(0xffffffff, adapter->tgt_status_reg);
2336 /* read twice to ensure write is flushed */
2337 readl(adapter->isr_int_vec);
2338 readl(adapter->isr_int_vec);
2339
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00002340 return IRQ_HANDLED;
2341}
2342
2343static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
2344{
2345 struct qlcnic_host_sds_ring *sds_ring = data;
2346 struct qlcnic_adapter *adapter = sds_ring->adapter;
2347
2348 if (adapter->flags & QLCNIC_MSIX_ENABLED)
2349 goto done;
2350 else if (adapter->flags & QLCNIC_MSI_ENABLED) {
2351 writel(0xffffffff, adapter->tgt_status_reg);
2352 goto done;
2353 }
2354
2355 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
2356 return IRQ_NONE;
2357
2358done:
2359 adapter->diag_cnt++;
2360 qlcnic_enable_int(sds_ring);
2361 return IRQ_HANDLED;
2362}
2363
2364static irqreturn_t qlcnic_intr(int irq, void *data)
2365{
2366 struct qlcnic_host_sds_ring *sds_ring = data;
2367 struct qlcnic_adapter *adapter = sds_ring->adapter;
2368
2369 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
2370 return IRQ_NONE;
2371
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002372 napi_schedule(&sds_ring->napi);
2373
2374 return IRQ_HANDLED;
2375}
2376
2377static irqreturn_t qlcnic_msi_intr(int irq, void *data)
2378{
2379 struct qlcnic_host_sds_ring *sds_ring = data;
2380 struct qlcnic_adapter *adapter = sds_ring->adapter;
2381
2382 /* clear interrupt */
2383 writel(0xffffffff, adapter->tgt_status_reg);
2384
2385 napi_schedule(&sds_ring->napi);
2386 return IRQ_HANDLED;
2387}
2388
2389static irqreturn_t qlcnic_msix_intr(int irq, void *data)
2390{
2391 struct qlcnic_host_sds_ring *sds_ring = data;
2392
2393 napi_schedule(&sds_ring->napi);
2394 return IRQ_HANDLED;
2395}
2396
2397static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
2398{
2399 u32 sw_consumer, hw_consumer;
2400 int count = 0, i;
2401 struct qlcnic_cmd_buffer *buffer;
2402 struct pci_dev *pdev = adapter->pdev;
2403 struct net_device *netdev = adapter->netdev;
2404 struct qlcnic_skb_frag *frag;
2405 int done;
2406 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
2407
2408 if (!spin_trylock(&adapter->tx_clean_lock))
2409 return 1;
2410
2411 sw_consumer = tx_ring->sw_consumer;
2412 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2413
2414 while (sw_consumer != hw_consumer) {
2415 buffer = &tx_ring->cmd_buf_arr[sw_consumer];
2416 if (buffer->skb) {
2417 frag = &buffer->frag_array[0];
2418 pci_unmap_single(pdev, frag->dma, frag->length,
2419 PCI_DMA_TODEVICE);
2420 frag->dma = 0ULL;
2421 for (i = 1; i < buffer->frag_count; i++) {
2422 frag++;
2423 pci_unmap_page(pdev, frag->dma, frag->length,
2424 PCI_DMA_TODEVICE);
2425 frag->dma = 0ULL;
2426 }
2427
2428 adapter->stats.xmitfinished++;
2429 dev_kfree_skb_any(buffer->skb);
2430 buffer->skb = NULL;
2431 }
2432
2433 sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
2434 if (++count >= MAX_STATUS_HANDLE)
2435 break;
2436 }
2437
2438 if (count && netif_running(netdev)) {
2439 tx_ring->sw_consumer = sw_consumer;
2440
2441 smp_mb();
2442
2443 if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002444 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
2445 netif_wake_queue(netdev);
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00002446 adapter->stats.xmit_on++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002447 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002448 }
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002449 adapter->tx_timeo_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002450 }
2451 /*
2452 * If everything is freed up to consumer then check if the ring is full
2453 * If the ring is full then check if more needs to be freed and
2454 * schedule the call back again.
2455 *
2456 * This happens when there are 2 CPUs. One could be freeing and the
2457 * other filling it. If the ring is full when we get out of here and
2458 * the card has already interrupted the host then the host can miss the
2459 * interrupt.
2460 *
2461 * There is still a possible race condition and the host could miss an
2462 * interrupt. The card has to take care of this.
2463 */
2464 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2465 done = (sw_consumer == hw_consumer);
2466 spin_unlock(&adapter->tx_clean_lock);
2467
2468 return done;
2469}
2470
2471static int qlcnic_poll(struct napi_struct *napi, int budget)
2472{
2473 struct qlcnic_host_sds_ring *sds_ring =
2474 container_of(napi, struct qlcnic_host_sds_ring, napi);
2475
2476 struct qlcnic_adapter *adapter = sds_ring->adapter;
2477
2478 int tx_complete;
2479 int work_done;
2480
2481 tx_complete = qlcnic_process_cmd_ring(adapter);
2482
2483 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2484
2485 if ((work_done < budget) && tx_complete) {
2486 napi_complete(&sds_ring->napi);
2487 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2488 qlcnic_enable_int(sds_ring);
2489 }
2490
2491 return work_done;
2492}
2493
schacko8f891382010-06-17 02:56:40 +00002494static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
2495{
2496 struct qlcnic_host_sds_ring *sds_ring =
2497 container_of(napi, struct qlcnic_host_sds_ring, napi);
2498
2499 struct qlcnic_adapter *adapter = sds_ring->adapter;
2500 int work_done;
2501
2502 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2503
2504 if (work_done < budget) {
2505 napi_complete(&sds_ring->napi);
2506 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2507 qlcnic_enable_int(sds_ring);
2508 }
2509
2510 return work_done;
2511}
2512
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002513#ifdef CONFIG_NET_POLL_CONTROLLER
2514static void qlcnic_poll_controller(struct net_device *netdev)
2515{
2516 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2517 disable_irq(adapter->irq);
2518 qlcnic_intr(adapter->irq, adapter);
2519 enable_irq(adapter->irq);
2520}
2521#endif
2522
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002523static void
2524qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
2525{
2526 u32 val;
2527
2528 val = adapter->portnum & 0xf;
2529 val |= encoding << 7;
2530 val |= (jiffies - adapter->dev_rst_time) << 8;
2531
2532 QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
2533 adapter->dev_rst_time = jiffies;
2534}
2535
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002536static int
2537qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002538{
2539 u32 val;
2540
2541 WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
2542 state != QLCNIC_DEV_NEED_QUISCENT);
2543
2544 if (qlcnic_api_lock(adapter))
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002545 return -EIO;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002546
2547 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
2548
2549 if (state == QLCNIC_DEV_NEED_RESET)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002550 QLC_DEV_SET_RST_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002551 else if (state == QLCNIC_DEV_NEED_QUISCENT)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002552 QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002553
2554 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2555
2556 qlcnic_api_unlock(adapter);
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002557
2558 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002559}
2560
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002561static int
2562qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
2563{
2564 u32 val;
2565
2566 if (qlcnic_api_lock(adapter))
2567 return -EBUSY;
2568
2569 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002570 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002571 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2572
2573 qlcnic_api_unlock(adapter);
2574
2575 return 0;
2576}
2577
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002578static void
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002579qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002580{
2581 u32 val;
2582
2583 if (qlcnic_api_lock(adapter))
2584 goto err;
2585
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002586 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002587 QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002588 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002589
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002590 if (failed) {
2591 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
2592 dev_info(&adapter->pdev->dev,
2593 "Device state set to Failed. Please Reboot\n");
2594 } else if (!(val & 0x11111111))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002595 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
2596
2597 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002598 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002599 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2600
2601 qlcnic_api_unlock(adapter);
2602err:
2603 adapter->fw_fail_cnt = 0;
2604 clear_bit(__QLCNIC_START_FW, &adapter->state);
2605 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2606}
2607
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002608/* Grab api lock, before checking state */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002609static int
2610qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
2611{
2612 int act, state;
2613
2614 state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002615 act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002616
2617 if (((state & 0x11111111) == (act & 0x11111111)) ||
2618 ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
2619 return 0;
2620 else
2621 return 1;
2622}
2623
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002624static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
2625{
2626 u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
2627
2628 if (val != QLCNIC_DRV_IDC_VER) {
2629 dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
2630 " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
2631 }
2632
2633 return 0;
2634}
2635
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002636static int
2637qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
2638{
2639 u32 val, prev_state;
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002640 u8 dev_init_timeo = adapter->dev_init_timeo;
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002641 u8 portnum = adapter->portnum;
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002642 u8 ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002643
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002644 if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
2645 return 1;
2646
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002647 if (qlcnic_api_lock(adapter))
2648 return -1;
2649
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002650 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002651 if (!(val & (1 << (portnum * 4)))) {
2652 QLC_DEV_SET_REF_CNT(val, portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002653 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002654 }
2655
2656 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002657 QLCDB(adapter, HW, "Device state = %u\n", prev_state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002658
2659 switch (prev_state) {
2660 case QLCNIC_DEV_COLD:
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002661 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002662 QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002663 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002664 qlcnic_api_unlock(adapter);
2665 return 1;
2666
2667 case QLCNIC_DEV_READY:
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002668 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002669 qlcnic_api_unlock(adapter);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002670 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002671
2672 case QLCNIC_DEV_NEED_RESET:
2673 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002674 QLC_DEV_SET_RST_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002675 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2676 break;
2677
2678 case QLCNIC_DEV_NEED_QUISCENT:
2679 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002680 QLC_DEV_SET_QSCNT_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002681 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2682 break;
2683
2684 case QLCNIC_DEV_FAILED:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00002685 dev_err(&adapter->pdev->dev, "Device in failed state.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002686 qlcnic_api_unlock(adapter);
2687 return -1;
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002688
2689 case QLCNIC_DEV_INITIALIZING:
2690 case QLCNIC_DEV_QUISCENT:
2691 break;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002692 }
2693
2694 qlcnic_api_unlock(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002695
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002696 do {
2697 msleep(1000);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002698 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2699
2700 if (prev_state == QLCNIC_DEV_QUISCENT)
2701 continue;
2702 } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002703
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002704 if (!dev_init_timeo) {
2705 dev_err(&adapter->pdev->dev,
2706 "Waiting for device to initialize timeout\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002707 return -1;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002708 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002709
2710 if (qlcnic_api_lock(adapter))
2711 return -1;
2712
2713 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002714 QLC_DEV_CLR_RST_QSCNT(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002715 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2716
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002717 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002718 qlcnic_api_unlock(adapter);
2719
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002720 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002721}
2722
2723static void
2724qlcnic_fwinit_work(struct work_struct *work)
2725{
2726 struct qlcnic_adapter *adapter = container_of(work,
2727 struct qlcnic_adapter, fw_work.work);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002728 u32 dev_state = 0xf;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002729
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002730 if (qlcnic_api_lock(adapter))
2731 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002732
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002733 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2734 if (dev_state == QLCNIC_DEV_QUISCENT) {
2735 qlcnic_api_unlock(adapter);
2736 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2737 FW_POLL_DELAY * 2);
2738 return;
2739 }
2740
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002741 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002742 qlcnic_api_unlock(adapter);
2743 goto wait_npar;
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002744 }
2745
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002746 if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
2747 dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
2748 adapter->reset_ack_timeo);
2749 goto skip_ack_check;
2750 }
2751
2752 if (!qlcnic_check_drv_state(adapter)) {
2753skip_ack_check:
2754 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002755
2756 if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2757 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2758 QLCNIC_DEV_QUISCENT);
2759 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2760 FW_POLL_DELAY * 2);
2761 QLCDB(adapter, DRV, "Quiscing the driver\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002762 qlcnic_idc_debug_info(adapter, 0);
2763
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002764 qlcnic_api_unlock(adapter);
2765 return;
2766 }
2767
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002768 if (dev_state == QLCNIC_DEV_NEED_RESET) {
2769 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2770 QLCNIC_DEV_INITIALIZING);
2771 set_bit(__QLCNIC_START_FW, &adapter->state);
2772 QLCDB(adapter, DRV, "Restarting fw\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002773 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002774 }
2775
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002776 qlcnic_api_unlock(adapter);
2777
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002778 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002779 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002780 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002781 return;
2782 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002783 goto err_ret;
2784 }
2785
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002786 qlcnic_api_unlock(adapter);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002787
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002788wait_npar:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002789 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002790 QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002791
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002792 switch (dev_state) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002793 case QLCNIC_DEV_READY:
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002794 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002795 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002796 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002797 return;
2798 }
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002799 case QLCNIC_DEV_FAILED:
2800 break;
2801 default:
2802 qlcnic_schedule_work(adapter,
2803 qlcnic_fwinit_work, FW_POLL_DELAY);
2804 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002805 }
2806
2807err_ret:
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002808 dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
2809 "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002810 netif_device_attach(adapter->netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002811 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002812}
2813
2814static void
2815qlcnic_detach_work(struct work_struct *work)
2816{
2817 struct qlcnic_adapter *adapter = container_of(work,
2818 struct qlcnic_adapter, fw_work.work);
2819 struct net_device *netdev = adapter->netdev;
2820 u32 status;
2821
2822 netif_device_detach(netdev);
2823
2824 qlcnic_down(adapter, netdev);
2825
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002826 status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
2827
2828 if (status & QLCNIC_RCODE_FATAL_ERROR)
2829 goto err_ret;
2830
2831 if (adapter->temp == QLCNIC_TEMP_PANIC)
2832 goto err_ret;
2833
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002834 if (qlcnic_set_drv_state(adapter, adapter->dev_state))
2835 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002836
2837 adapter->fw_wait_cnt = 0;
2838
2839 qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
2840
2841 return;
2842
2843err_ret:
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002844 dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
2845 status, adapter->temp);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002846 netif_device_attach(netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002847 qlcnic_clr_all_drv_state(adapter, 1);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002848}
2849
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002850/*Transit NPAR state to NON Operational */
2851static void
2852qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
2853{
2854 u32 state;
2855
2856 state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2857 if (state == QLCNIC_DEV_NPAR_NON_OPER)
2858 return;
2859
2860 if (qlcnic_api_lock(adapter))
2861 return;
2862 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
2863 qlcnic_api_unlock(adapter);
2864}
2865
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002866/*Transit to RESET state from READY state only */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002867static void
2868qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
2869{
2870 u32 state;
2871
Anirban Chakrabortycea89752010-07-13 20:33:35 +00002872 adapter->need_fw_reset = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002873 if (qlcnic_api_lock(adapter))
2874 return;
2875
2876 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2877
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002878 if (state == QLCNIC_DEV_READY) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002879 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002880 QLCDB(adapter, DRV, "NEED_RESET state set\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002881 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002882 }
2883
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002884 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002885 qlcnic_api_unlock(adapter);
2886}
2887
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002888/* Transit to NPAR READY state from NPAR NOT READY state */
2889static void
2890qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
2891{
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002892 if (qlcnic_api_lock(adapter))
2893 return;
2894
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002895 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
2896 QLCDB(adapter, DRV, "NPAR operational state set\n");
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002897
2898 qlcnic_api_unlock(adapter);
2899}
2900
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002901static void
2902qlcnic_schedule_work(struct qlcnic_adapter *adapter,
2903 work_func_t func, int delay)
2904{
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002905 if (test_bit(__QLCNIC_AER, &adapter->state))
2906 return;
2907
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002908 INIT_DELAYED_WORK(&adapter->fw_work, func);
2909 schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
2910}
2911
2912static void
2913qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
2914{
2915 while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
2916 msleep(10);
2917
2918 cancel_delayed_work_sync(&adapter->fw_work);
2919}
2920
2921static void
2922qlcnic_attach_work(struct work_struct *work)
2923{
2924 struct qlcnic_adapter *adapter = container_of(work,
2925 struct qlcnic_adapter, fw_work.work);
2926 struct net_device *netdev = adapter->netdev;
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002927 u32 npar_state;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002928
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002929 if (adapter->op_mode != QLCNIC_MGMT_FUNC) {
2930 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2931 if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
2932 qlcnic_clr_all_drv_state(adapter, 0);
2933 else if (npar_state != QLCNIC_DEV_NPAR_OPER)
2934 qlcnic_schedule_work(adapter, qlcnic_attach_work,
2935 FW_POLL_DELAY);
2936 else
2937 goto attach;
2938 QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n");
2939 return;
2940 }
2941attach:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002942 if (netif_running(netdev)) {
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00002943 if (qlcnic_up(adapter, netdev))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002944 goto done;
2945
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002946 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2947 }
2948
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002949done:
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002950 netif_device_attach(netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002951 adapter->fw_fail_cnt = 0;
2952 clear_bit(__QLCNIC_RESETTING, &adapter->state);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002953
2954 if (!qlcnic_clr_drv_state(adapter))
2955 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2956 FW_POLL_DELAY);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002957}
2958
2959static int
2960qlcnic_check_health(struct qlcnic_adapter *adapter)
2961{
Sony Chacko4e708122010-08-31 17:17:44 +00002962 u32 state = 0, heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002963 struct net_device *netdev = adapter->netdev;
2964
2965 if (qlcnic_check_temp(adapter))
2966 goto detach;
2967
Amit Kumar Salecha2372a5f2010-05-13 03:07:42 +00002968 if (adapter->need_fw_reset)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002969 qlcnic_dev_request_reset(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002970
2971 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002972 if (state == QLCNIC_DEV_NEED_RESET ||
2973 state == QLCNIC_DEV_NEED_QUISCENT) {
2974 qlcnic_set_npar_non_operational(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002975 adapter->need_fw_reset = 1;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002976 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002977
Sony Chacko4e708122010-08-31 17:17:44 +00002978 heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
2979 if (heartbeat != adapter->heartbeat) {
2980 adapter->heartbeat = heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002981 adapter->fw_fail_cnt = 0;
2982 if (adapter->need_fw_reset)
2983 goto detach;
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002984
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002985 if (adapter->reset_context &&
2986 auto_fw_reset == AUTO_FW_RESET_ENABLED) {
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002987 qlcnic_reset_hw_context(adapter);
2988 adapter->netdev->trans_start = jiffies;
2989 }
2990
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002991 return 0;
2992 }
2993
2994 if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
2995 return 0;
2996
2997 qlcnic_dev_request_reset(adapter);
2998
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002999 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED))
3000 clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003001
3002 dev_info(&netdev->dev, "firmware hang detected\n");
3003
3004detach:
3005 adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
3006 QLCNIC_DEV_NEED_RESET;
3007
3008 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00003009 !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) {
3010
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003011 qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00003012 QLCDB(adapter, DRV, "fw recovery scheduled.\n");
3013 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003014
3015 return 1;
3016}
3017
3018static void
3019qlcnic_fw_poll_work(struct work_struct *work)
3020{
3021 struct qlcnic_adapter *adapter = container_of(work,
3022 struct qlcnic_adapter, fw_work.work);
3023
3024 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
3025 goto reschedule;
3026
3027
3028 if (qlcnic_check_health(adapter))
3029 return;
3030
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00003031 if (adapter->fhash.fnum)
3032 qlcnic_prune_lb_filters(adapter);
3033
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003034reschedule:
3035 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
3036}
3037
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003038static int qlcnic_is_first_func(struct pci_dev *pdev)
3039{
3040 struct pci_dev *oth_pdev;
3041 int val = pdev->devfn;
3042
3043 while (val-- > 0) {
3044 oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
3045 (pdev->bus), pdev->bus->number,
3046 PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003047 if (!oth_pdev)
3048 continue;
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003049
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003050 if (oth_pdev->current_state != PCI_D3cold) {
3051 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003052 return 0;
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003053 }
3054 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003055 }
3056 return 1;
3057}
3058
3059static int qlcnic_attach_func(struct pci_dev *pdev)
3060{
3061 int err, first_func;
3062 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3063 struct net_device *netdev = adapter->netdev;
3064
3065 pdev->error_state = pci_channel_io_normal;
3066
3067 err = pci_enable_device(pdev);
3068 if (err)
3069 return err;
3070
3071 pci_set_power_state(pdev, PCI_D0);
3072 pci_set_master(pdev);
3073 pci_restore_state(pdev);
3074
3075 first_func = qlcnic_is_first_func(pdev);
3076
3077 if (qlcnic_api_lock(adapter))
3078 return -EINVAL;
3079
Amit Kumar Salecha933fce122010-08-17 00:34:19 +00003080 if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003081 adapter->need_fw_reset = 1;
3082 set_bit(__QLCNIC_START_FW, &adapter->state);
3083 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
3084 QLCDB(adapter, DRV, "Restarting fw\n");
3085 }
3086 qlcnic_api_unlock(adapter);
3087
3088 err = adapter->nic_ops->start_firmware(adapter);
3089 if (err)
3090 return err;
3091
3092 qlcnic_clr_drv_state(adapter);
3093 qlcnic_setup_intr(adapter);
3094
3095 if (netif_running(netdev)) {
3096 err = qlcnic_attach(adapter);
3097 if (err) {
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00003098 qlcnic_clr_all_drv_state(adapter, 1);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003099 clear_bit(__QLCNIC_AER, &adapter->state);
3100 netif_device_attach(netdev);
3101 return err;
3102 }
3103
3104 err = qlcnic_up(adapter, netdev);
3105 if (err)
3106 goto done;
3107
3108 qlcnic_config_indev_addr(netdev, NETDEV_UP);
3109 }
3110 done:
3111 netif_device_attach(netdev);
3112 return err;
3113}
3114
3115static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
3116 pci_channel_state_t state)
3117{
3118 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3119 struct net_device *netdev = adapter->netdev;
3120
3121 if (state == pci_channel_io_perm_failure)
3122 return PCI_ERS_RESULT_DISCONNECT;
3123
3124 if (state == pci_channel_io_normal)
3125 return PCI_ERS_RESULT_RECOVERED;
3126
3127 set_bit(__QLCNIC_AER, &adapter->state);
3128 netif_device_detach(netdev);
3129
3130 cancel_delayed_work_sync(&adapter->fw_work);
3131
3132 if (netif_running(netdev))
3133 qlcnic_down(adapter, netdev);
3134
3135 qlcnic_detach(adapter);
3136 qlcnic_teardown_intr(adapter);
3137
3138 clear_bit(__QLCNIC_RESETTING, &adapter->state);
3139
3140 pci_save_state(pdev);
3141 pci_disable_device(pdev);
3142
3143 return PCI_ERS_RESULT_NEED_RESET;
3144}
3145
3146static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
3147{
3148 return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
3149 PCI_ERS_RESULT_RECOVERED;
3150}
3151
3152static void qlcnic_io_resume(struct pci_dev *pdev)
3153{
3154 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3155
3156 pci_cleanup_aer_uncorrect_error_status(pdev);
3157
3158 if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
3159 test_and_clear_bit(__QLCNIC_AER, &adapter->state))
3160 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
3161 FW_POLL_DELAY);
3162}
3163
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003164static int
3165qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
3166{
3167 int err;
3168
3169 err = qlcnic_can_start_firmware(adapter);
3170 if (err)
3171 return err;
3172
Amit Kumar Salecha78f84e12010-08-19 05:08:28 +00003173 err = qlcnic_check_npar_opertional(adapter);
3174 if (err)
3175 return err;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00003176
Rajesh Borundia174240a2010-08-31 17:17:47 +00003177 err = qlcnic_initialize_nic(adapter);
3178 if (err)
3179 return err;
3180
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003181 qlcnic_check_options(adapter);
3182
Rajesh Borundia73733732010-08-31 17:17:50 +00003183 err = qlcnic_set_eswitch_port_config(adapter);
3184 if (err)
3185 return err;
3186
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003187 adapter->need_fw_reset = 0;
3188
3189 return err;
3190}
3191
3192static int
3193qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
3194{
3195 return -EOPNOTSUPP;
3196}
3197
3198static int
3199qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
3200{
3201 return -EOPNOTSUPP;
3202}
3203
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003204static ssize_t
3205qlcnic_store_bridged_mode(struct device *dev,
3206 struct device_attribute *attr, const char *buf, size_t len)
3207{
3208 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3209 unsigned long new;
3210 int ret = -EINVAL;
3211
3212 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
3213 goto err_out;
3214
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003215 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003216 goto err_out;
3217
3218 if (strict_strtoul(buf, 2, &new))
3219 goto err_out;
3220
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00003221 if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003222 ret = len;
3223
3224err_out:
3225 return ret;
3226}
3227
3228static ssize_t
3229qlcnic_show_bridged_mode(struct device *dev,
3230 struct device_attribute *attr, char *buf)
3231{
3232 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3233 int bridged_mode = 0;
3234
3235 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3236 bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
3237
3238 return sprintf(buf, "%d\n", bridged_mode);
3239}
3240
3241static struct device_attribute dev_attr_bridged_mode = {
3242 .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
3243 .show = qlcnic_show_bridged_mode,
3244 .store = qlcnic_store_bridged_mode,
3245};
3246
3247static ssize_t
3248qlcnic_store_diag_mode(struct device *dev,
3249 struct device_attribute *attr, const char *buf, size_t len)
3250{
3251 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3252 unsigned long new;
3253
3254 if (strict_strtoul(buf, 2, &new))
3255 return -EINVAL;
3256
3257 if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
3258 adapter->flags ^= QLCNIC_DIAG_ENABLED;
3259
3260 return len;
3261}
3262
3263static ssize_t
3264qlcnic_show_diag_mode(struct device *dev,
3265 struct device_attribute *attr, char *buf)
3266{
3267 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3268
3269 return sprintf(buf, "%d\n",
3270 !!(adapter->flags & QLCNIC_DIAG_ENABLED));
3271}
3272
3273static struct device_attribute dev_attr_diag_mode = {
3274 .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
3275 .show = qlcnic_show_diag_mode,
3276 .store = qlcnic_store_diag_mode,
3277};
3278
3279static int
3280qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
3281 loff_t offset, size_t size)
3282{
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003283 size_t crb_size = 4;
3284
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003285 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3286 return -EIO;
3287
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003288 if (offset < QLCNIC_PCI_CRBSPACE) {
3289 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
3290 QLCNIC_PCI_CAMQM_END))
3291 crb_size = 8;
3292 else
3293 return -EINVAL;
3294 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003295
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003296 if ((size != crb_size) || (offset & (crb_size-1)))
3297 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003298
3299 return 0;
3300}
3301
3302static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003303qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
3304 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003305 char *buf, loff_t offset, size_t size)
3306{
3307 struct device *dev = container_of(kobj, struct device, kobj);
3308 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3309 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003310 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003311 int ret;
3312
3313 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3314 if (ret != 0)
3315 return ret;
3316
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003317 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3318 qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
3319 memcpy(buf, &qmdata, size);
3320 } else {
3321 data = QLCRD32(adapter, offset);
3322 memcpy(buf, &data, size);
3323 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003324 return size;
3325}
3326
3327static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003328qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
3329 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003330 char *buf, loff_t offset, size_t size)
3331{
3332 struct device *dev = container_of(kobj, struct device, kobj);
3333 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3334 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003335 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003336 int ret;
3337
3338 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3339 if (ret != 0)
3340 return ret;
3341
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003342 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3343 memcpy(&qmdata, buf, size);
3344 qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
3345 } else {
3346 memcpy(&data, buf, size);
3347 QLCWR32(adapter, offset, data);
3348 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003349 return size;
3350}
3351
3352static int
3353qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
3354 loff_t offset, size_t size)
3355{
3356 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3357 return -EIO;
3358
3359 if ((size != 8) || (offset & 0x7))
3360 return -EIO;
3361
3362 return 0;
3363}
3364
3365static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003366qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
3367 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003368 char *buf, loff_t offset, size_t size)
3369{
3370 struct device *dev = container_of(kobj, struct device, kobj);
3371 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3372 u64 data;
3373 int ret;
3374
3375 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3376 if (ret != 0)
3377 return ret;
3378
3379 if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
3380 return -EIO;
3381
3382 memcpy(buf, &data, size);
3383
3384 return size;
3385}
3386
3387static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003388qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
3389 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003390 char *buf, loff_t offset, size_t size)
3391{
3392 struct device *dev = container_of(kobj, struct device, kobj);
3393 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3394 u64 data;
3395 int ret;
3396
3397 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3398 if (ret != 0)
3399 return ret;
3400
3401 memcpy(&data, buf, size);
3402
3403 if (qlcnic_pci_mem_write_2M(adapter, offset, data))
3404 return -EIO;
3405
3406 return size;
3407}
3408
3409
3410static struct bin_attribute bin_attr_crb = {
3411 .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
3412 .size = 0,
3413 .read = qlcnic_sysfs_read_crb,
3414 .write = qlcnic_sysfs_write_crb,
3415};
3416
3417static struct bin_attribute bin_attr_mem = {
3418 .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
3419 .size = 0,
3420 .read = qlcnic_sysfs_read_mem,
3421 .write = qlcnic_sysfs_write_mem,
3422};
3423
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003424static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003425validate_pm_config(struct qlcnic_adapter *adapter,
3426 struct qlcnic_pm_func_cfg *pm_cfg, int count)
3427{
3428
3429 u8 src_pci_func, s_esw_id, d_esw_id;
3430 u8 dest_pci_func;
3431 int i;
3432
3433 for (i = 0; i < count; i++) {
3434 src_pci_func = pm_cfg[i].pci_func;
3435 dest_pci_func = pm_cfg[i].dest_npar;
3436 if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
3437 || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
3438 return QL_STATUS_INVALID_PARAM;
3439
3440 if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
3441 return QL_STATUS_INVALID_PARAM;
3442
3443 if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
3444 return QL_STATUS_INVALID_PARAM;
3445
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003446 s_esw_id = adapter->npars[src_pci_func].phy_port;
3447 d_esw_id = adapter->npars[dest_pci_func].phy_port;
3448
3449 if (s_esw_id != d_esw_id)
3450 return QL_STATUS_INVALID_PARAM;
3451
3452 }
3453 return 0;
3454
3455}
3456
3457static ssize_t
3458qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
3459 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3460{
3461 struct device *dev = container_of(kobj, struct device, kobj);
3462 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3463 struct qlcnic_pm_func_cfg *pm_cfg;
3464 u32 id, action, pci_func;
3465 int count, rem, i, ret;
3466
3467 count = size / sizeof(struct qlcnic_pm_func_cfg);
3468 rem = size % sizeof(struct qlcnic_pm_func_cfg);
3469 if (rem)
3470 return QL_STATUS_INVALID_PARAM;
3471
3472 pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
3473
3474 ret = validate_pm_config(adapter, pm_cfg, count);
3475 if (ret)
3476 return ret;
3477 for (i = 0; i < count; i++) {
3478 pci_func = pm_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003479 action = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003480 id = adapter->npars[pci_func].phy_port;
3481 ret = qlcnic_config_port_mirroring(adapter, id,
3482 action, pci_func);
3483 if (ret)
3484 return ret;
3485 }
3486
3487 for (i = 0; i < count; i++) {
3488 pci_func = pm_cfg[i].pci_func;
3489 id = adapter->npars[pci_func].phy_port;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003490 adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003491 adapter->npars[pci_func].dest_npar = id;
3492 }
3493 return size;
3494}
3495
3496static ssize_t
3497qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
3498 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3499{
3500 struct device *dev = container_of(kobj, struct device, kobj);
3501 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3502 struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
3503 int i;
3504
3505 if (size != sizeof(pm_cfg))
3506 return QL_STATUS_INVALID_PARAM;
3507
3508 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3509 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3510 continue;
3511 pm_cfg[i].action = adapter->npars[i].enable_pm;
3512 pm_cfg[i].dest_npar = 0;
3513 pm_cfg[i].pci_func = i;
3514 }
3515 memcpy(buf, &pm_cfg, size);
3516
3517 return size;
3518}
3519
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003520static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003521validate_esw_config(struct qlcnic_adapter *adapter,
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003522 struct qlcnic_esw_func_cfg *esw_cfg, int count)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003523{
Rajesh Borundia7613c872010-08-31 17:17:48 +00003524 u32 op_mode;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003525 u8 pci_func;
3526 int i;
Rajesh Borundia7613c872010-08-31 17:17:48 +00003527
3528 op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE);
3529
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003530 for (i = 0; i < count; i++) {
3531 pci_func = esw_cfg[i].pci_func;
3532 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3533 return QL_STATUS_INVALID_PARAM;
3534
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003535 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3536 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003537 return QL_STATUS_INVALID_PARAM;
3538
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003539 switch (esw_cfg[i].op_mode) {
3540 case QLCNIC_PORT_DEFAULTS:
Rajesh Borundia7613c872010-08-31 17:17:48 +00003541 if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
Rajesh Borundia73733732010-08-31 17:17:50 +00003542 QLCNIC_NON_PRIV_FUNC) {
Rajesh Borundia7613c872010-08-31 17:17:48 +00003543 esw_cfg[i].mac_anti_spoof = 0;
Rajesh Borundia73733732010-08-31 17:17:50 +00003544 esw_cfg[i].mac_override = 1;
3545 }
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003546 break;
3547 case QLCNIC_ADD_VLAN:
3548 if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
3549 return QL_STATUS_INVALID_PARAM;
3550 if (!esw_cfg[i].op_type)
3551 return QL_STATUS_INVALID_PARAM;
3552 break;
3553 case QLCNIC_DEL_VLAN:
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003554 if (!esw_cfg[i].op_type)
3555 return QL_STATUS_INVALID_PARAM;
3556 break;
3557 default:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003558 return QL_STATUS_INVALID_PARAM;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003559 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003560 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003561 return 0;
3562}
3563
3564static ssize_t
3565qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
3566 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3567{
3568 struct device *dev = container_of(kobj, struct device, kobj);
3569 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3570 struct qlcnic_esw_func_cfg *esw_cfg;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003571 struct qlcnic_npar_info *npar;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003572 int count, rem, i, ret;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003573 u8 pci_func, op_mode = 0;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003574
3575 count = size / sizeof(struct qlcnic_esw_func_cfg);
3576 rem = size % sizeof(struct qlcnic_esw_func_cfg);
3577 if (rem)
3578 return QL_STATUS_INVALID_PARAM;
3579
3580 esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
3581 ret = validate_esw_config(adapter, esw_cfg, count);
3582 if (ret)
3583 return ret;
3584
3585 for (i = 0; i < count; i++) {
Rajesh Borundia0325d692010-08-19 05:08:26 +00003586 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3587 if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
3588 return QL_STATUS_INVALID_PARAM;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003589
3590 if (adapter->ahw.pci_func != esw_cfg[i].pci_func)
3591 continue;
3592
3593 op_mode = esw_cfg[i].op_mode;
3594 qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
3595 esw_cfg[i].op_mode = op_mode;
3596 esw_cfg[i].pci_func = adapter->ahw.pci_func;
3597
3598 switch (esw_cfg[i].op_mode) {
3599 case QLCNIC_PORT_DEFAULTS:
3600 qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
3601 break;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00003602 case QLCNIC_ADD_VLAN:
3603 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3604 break;
3605 case QLCNIC_DEL_VLAN:
3606 esw_cfg[i].vlan_id = 0;
3607 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3608 break;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003609 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003610 }
3611
Rajesh Borundia0325d692010-08-19 05:08:26 +00003612 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
3613 goto out;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003614
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003615 for (i = 0; i < count; i++) {
3616 pci_func = esw_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003617 npar = &adapter->npars[pci_func];
3618 switch (esw_cfg[i].op_mode) {
3619 case QLCNIC_PORT_DEFAULTS:
3620 npar->promisc_mode = esw_cfg[i].promisc_mode;
Rajesh Borundia73733732010-08-31 17:17:50 +00003621 npar->mac_override = esw_cfg[i].mac_override;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003622 npar->offload_flags = esw_cfg[i].offload_flags;
3623 npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
3624 npar->discard_tagged = esw_cfg[i].discard_tagged;
3625 break;
3626 case QLCNIC_ADD_VLAN:
3627 npar->pvid = esw_cfg[i].vlan_id;
3628 break;
3629 case QLCNIC_DEL_VLAN:
3630 npar->pvid = 0;
3631 break;
3632 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003633 }
Rajesh Borundia0325d692010-08-19 05:08:26 +00003634out:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003635 return size;
3636}
3637
3638static ssize_t
3639qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
3640 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3641{
3642 struct device *dev = container_of(kobj, struct device, kobj);
3643 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3644 struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003645 u8 i;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003646
3647 if (size != sizeof(esw_cfg))
3648 return QL_STATUS_INVALID_PARAM;
3649
3650 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3651 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3652 continue;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003653 esw_cfg[i].pci_func = i;
3654 if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
3655 return QL_STATUS_INVALID_PARAM;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003656 }
3657 memcpy(buf, &esw_cfg, size);
3658
3659 return size;
3660}
3661
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003662static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003663validate_npar_config(struct qlcnic_adapter *adapter,
3664 struct qlcnic_npar_func_cfg *np_cfg, int count)
3665{
3666 u8 pci_func, i;
3667
3668 for (i = 0; i < count; i++) {
3669 pci_func = np_cfg[i].pci_func;
3670 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3671 return QL_STATUS_INVALID_PARAM;
3672
3673 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
3674 return QL_STATUS_INVALID_PARAM;
3675
3676 if (!IS_VALID_BW(np_cfg[i].min_bw)
3677 || !IS_VALID_BW(np_cfg[i].max_bw)
3678 || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
3679 || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
3680 return QL_STATUS_INVALID_PARAM;
3681 }
3682 return 0;
3683}
3684
3685static ssize_t
3686qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
3687 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3688{
3689 struct device *dev = container_of(kobj, struct device, kobj);
3690 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3691 struct qlcnic_info nic_info;
3692 struct qlcnic_npar_func_cfg *np_cfg;
3693 int i, count, rem, ret;
3694 u8 pci_func;
3695
3696 count = size / sizeof(struct qlcnic_npar_func_cfg);
3697 rem = size % sizeof(struct qlcnic_npar_func_cfg);
3698 if (rem)
3699 return QL_STATUS_INVALID_PARAM;
3700
3701 np_cfg = (struct qlcnic_npar_func_cfg *) buf;
3702 ret = validate_npar_config(adapter, np_cfg, count);
3703 if (ret)
3704 return ret;
3705
3706 for (i = 0; i < count ; i++) {
3707 pci_func = np_cfg[i].pci_func;
3708 ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
3709 if (ret)
3710 return ret;
3711 nic_info.pci_func = pci_func;
3712 nic_info.min_tx_bw = np_cfg[i].min_bw;
3713 nic_info.max_tx_bw = np_cfg[i].max_bw;
3714 ret = qlcnic_set_nic_info(adapter, &nic_info);
3715 if (ret)
3716 return ret;
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003717 adapter->npars[i].min_bw = nic_info.min_tx_bw;
3718 adapter->npars[i].max_bw = nic_info.max_tx_bw;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003719 }
3720
3721 return size;
3722
3723}
3724static ssize_t
3725qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
3726 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3727{
3728 struct device *dev = container_of(kobj, struct device, kobj);
3729 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3730 struct qlcnic_info nic_info;
3731 struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
3732 int i, ret;
3733
3734 if (size != sizeof(np_cfg))
3735 return QL_STATUS_INVALID_PARAM;
3736
3737 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3738 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3739 continue;
3740 ret = qlcnic_get_nic_info(adapter, &nic_info, i);
3741 if (ret)
3742 return ret;
3743
3744 np_cfg[i].pci_func = i;
3745 np_cfg[i].op_mode = nic_info.op_mode;
3746 np_cfg[i].port_num = nic_info.phys_port;
3747 np_cfg[i].fw_capab = nic_info.capabilities;
3748 np_cfg[i].min_bw = nic_info.min_tx_bw ;
3749 np_cfg[i].max_bw = nic_info.max_tx_bw;
3750 np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
3751 np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
3752 }
3753 memcpy(buf, &np_cfg, size);
3754 return size;
3755}
3756
3757static ssize_t
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003758qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
3759 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3760{
3761 struct device *dev = container_of(kobj, struct device, kobj);
3762 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3763 struct qlcnic_esw_statistics port_stats;
3764 int ret;
3765
3766 if (size != sizeof(struct qlcnic_esw_statistics))
3767 return QL_STATUS_INVALID_PARAM;
3768
3769 if (offset >= QLCNIC_MAX_PCI_FUNC)
3770 return QL_STATUS_INVALID_PARAM;
3771
3772 memset(&port_stats, 0, size);
3773 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3774 &port_stats.rx);
3775 if (ret)
3776 return ret;
3777
3778 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3779 &port_stats.tx);
3780 if (ret)
3781 return ret;
3782
3783 memcpy(buf, &port_stats, size);
3784 return size;
3785}
3786
3787static ssize_t
3788qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
3789 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3790{
3791 struct device *dev = container_of(kobj, struct device, kobj);
3792 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3793 struct qlcnic_esw_statistics esw_stats;
3794 int ret;
3795
3796 if (size != sizeof(struct qlcnic_esw_statistics))
3797 return QL_STATUS_INVALID_PARAM;
3798
3799 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3800 return QL_STATUS_INVALID_PARAM;
3801
3802 memset(&esw_stats, 0, size);
3803 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3804 &esw_stats.rx);
3805 if (ret)
3806 return ret;
3807
3808 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3809 &esw_stats.tx);
3810 if (ret)
3811 return ret;
3812
3813 memcpy(buf, &esw_stats, size);
3814 return size;
3815}
3816
3817static ssize_t
3818qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
3819 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3820{
3821 struct device *dev = container_of(kobj, struct device, kobj);
3822 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3823 int ret;
3824
3825 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3826 return QL_STATUS_INVALID_PARAM;
3827
3828 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3829 QLCNIC_QUERY_RX_COUNTER);
3830 if (ret)
3831 return ret;
3832
3833 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3834 QLCNIC_QUERY_TX_COUNTER);
3835 if (ret)
3836 return ret;
3837
3838 return size;
3839}
3840
3841static ssize_t
3842qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
3843 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3844{
3845
3846 struct device *dev = container_of(kobj, struct device, kobj);
3847 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3848 int ret;
3849
3850 if (offset >= QLCNIC_MAX_PCI_FUNC)
3851 return QL_STATUS_INVALID_PARAM;
3852
3853 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3854 QLCNIC_QUERY_RX_COUNTER);
3855 if (ret)
3856 return ret;
3857
3858 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3859 QLCNIC_QUERY_TX_COUNTER);
3860 if (ret)
3861 return ret;
3862
3863 return size;
3864}
3865
3866static ssize_t
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003867qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
3868 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3869{
3870 struct device *dev = container_of(kobj, struct device, kobj);
3871 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3872 struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
Dan Carpentere88db3b2010-08-09 21:49:36 +00003873 struct qlcnic_pci_info *pci_info;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003874 int i, ret;
3875
3876 if (size != sizeof(pci_cfg))
3877 return QL_STATUS_INVALID_PARAM;
3878
Dan Carpentere88db3b2010-08-09 21:49:36 +00003879 pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
3880 if (!pci_info)
3881 return -ENOMEM;
3882
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003883 ret = qlcnic_get_pci_info(adapter, pci_info);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003884 if (ret) {
3885 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003886 return ret;
Dan Carpentere88db3b2010-08-09 21:49:36 +00003887 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003888
3889 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3890 pci_cfg[i].pci_func = pci_info[i].id;
3891 pci_cfg[i].func_type = pci_info[i].type;
3892 pci_cfg[i].port_num = pci_info[i].default_port;
3893 pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
3894 pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
3895 memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
3896 }
3897 memcpy(buf, &pci_cfg, size);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003898 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003899 return size;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003900}
3901static struct bin_attribute bin_attr_npar_config = {
3902 .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
3903 .size = 0,
3904 .read = qlcnic_sysfs_read_npar_config,
3905 .write = qlcnic_sysfs_write_npar_config,
3906};
3907
3908static struct bin_attribute bin_attr_pci_config = {
3909 .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
3910 .size = 0,
3911 .read = qlcnic_sysfs_read_pci_config,
3912 .write = NULL,
3913};
3914
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003915static struct bin_attribute bin_attr_port_stats = {
3916 .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
3917 .size = 0,
3918 .read = qlcnic_sysfs_get_port_stats,
3919 .write = qlcnic_sysfs_clear_port_stats,
3920};
3921
3922static struct bin_attribute bin_attr_esw_stats = {
3923 .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
3924 .size = 0,
3925 .read = qlcnic_sysfs_get_esw_stats,
3926 .write = qlcnic_sysfs_clear_esw_stats,
3927};
3928
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003929static struct bin_attribute bin_attr_esw_config = {
3930 .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
3931 .size = 0,
3932 .read = qlcnic_sysfs_read_esw_config,
3933 .write = qlcnic_sysfs_write_esw_config,
3934};
3935
3936static struct bin_attribute bin_attr_pm_config = {
3937 .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
3938 .size = 0,
3939 .read = qlcnic_sysfs_read_pm_config,
3940 .write = qlcnic_sysfs_write_pm_config,
3941};
3942
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003943static void
3944qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
3945{
3946 struct device *dev = &adapter->pdev->dev;
3947
3948 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3949 if (device_create_file(dev, &dev_attr_bridged_mode))
3950 dev_warn(dev,
3951 "failed to create bridged_mode sysfs entry\n");
3952}
3953
3954static void
3955qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
3956{
3957 struct device *dev = &adapter->pdev->dev;
3958
3959 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3960 device_remove_file(dev, &dev_attr_bridged_mode);
3961}
3962
3963static void
3964qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
3965{
3966 struct device *dev = &adapter->pdev->dev;
3967
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003968 if (device_create_bin_file(dev, &bin_attr_port_stats))
3969 dev_info(dev, "failed to create port stats sysfs entry");
3970
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003971 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3972 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003973 if (device_create_file(dev, &dev_attr_diag_mode))
3974 dev_info(dev, "failed to create diag_mode sysfs entry\n");
3975 if (device_create_bin_file(dev, &bin_attr_crb))
3976 dev_info(dev, "failed to create crb sysfs entry\n");
3977 if (device_create_bin_file(dev, &bin_attr_mem))
3978 dev_info(dev, "failed to create mem sysfs entry\n");
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003979 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
3980 return;
3981 if (device_create_bin_file(dev, &bin_attr_esw_config))
3982 dev_info(dev, "failed to create esw config sysfs entry");
3983 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003984 return;
3985 if (device_create_bin_file(dev, &bin_attr_pci_config))
3986 dev_info(dev, "failed to create pci config sysfs entry");
3987 if (device_create_bin_file(dev, &bin_attr_npar_config))
3988 dev_info(dev, "failed to create npar config sysfs entry");
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003989 if (device_create_bin_file(dev, &bin_attr_pm_config))
3990 dev_info(dev, "failed to create pm config sysfs entry");
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003991 if (device_create_bin_file(dev, &bin_attr_esw_stats))
3992 dev_info(dev, "failed to create eswitch stats sysfs entry");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003993}
3994
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003995static void
3996qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
3997{
3998 struct device *dev = &adapter->pdev->dev;
3999
Amit Kumar Salechab6021212010-08-17 00:34:22 +00004000 device_remove_bin_file(dev, &bin_attr_port_stats);
4001
Anirban Chakraborty132ff002010-07-09 13:15:05 +00004002 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
4003 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004004 device_remove_file(dev, &dev_attr_diag_mode);
4005 device_remove_bin_file(dev, &bin_attr_crb);
4006 device_remove_bin_file(dev, &bin_attr_mem);
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00004007 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
4008 return;
4009 device_remove_bin_file(dev, &bin_attr_esw_config);
4010 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00004011 return;
4012 device_remove_bin_file(dev, &bin_attr_pci_config);
4013 device_remove_bin_file(dev, &bin_attr_npar_config);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00004014 device_remove_bin_file(dev, &bin_attr_pm_config);
Amit Kumar Salechab6021212010-08-17 00:34:22 +00004015 device_remove_bin_file(dev, &bin_attr_esw_stats);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004016}
4017
4018#ifdef CONFIG_INET
4019
4020#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
4021
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004022static void
4023qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
4024{
4025 struct in_device *indev;
4026 struct qlcnic_adapter *adapter = netdev_priv(dev);
4027
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004028 indev = in_dev_get(dev);
4029 if (!indev)
4030 return;
4031
4032 for_ifa(indev) {
4033 switch (event) {
4034 case NETDEV_UP:
4035 qlcnic_config_ipaddr(adapter,
4036 ifa->ifa_address, QLCNIC_IP_UP);
4037 break;
4038 case NETDEV_DOWN:
4039 qlcnic_config_ipaddr(adapter,
4040 ifa->ifa_address, QLCNIC_IP_DOWN);
4041 break;
4042 default:
4043 break;
4044 }
4045 } endfor_ifa(indev);
4046
4047 in_dev_put(indev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004048}
4049
4050static int qlcnic_netdev_event(struct notifier_block *this,
4051 unsigned long event, void *ptr)
4052{
4053 struct qlcnic_adapter *adapter;
4054 struct net_device *dev = (struct net_device *)ptr;
4055
4056recheck:
4057 if (dev == NULL)
4058 goto done;
4059
4060 if (dev->priv_flags & IFF_802_1Q_VLAN) {
4061 dev = vlan_dev_real_dev(dev);
4062 goto recheck;
4063 }
4064
4065 if (!is_qlcnic_netdev(dev))
4066 goto done;
4067
4068 adapter = netdev_priv(dev);
4069
4070 if (!adapter)
4071 goto done;
4072
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00004073 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004074 goto done;
4075
4076 qlcnic_config_indev_addr(dev, event);
4077done:
4078 return NOTIFY_DONE;
4079}
4080
4081static int
4082qlcnic_inetaddr_event(struct notifier_block *this,
4083 unsigned long event, void *ptr)
4084{
4085 struct qlcnic_adapter *adapter;
4086 struct net_device *dev;
4087
4088 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
4089
4090 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
4091
4092recheck:
4093 if (dev == NULL || !netif_running(dev))
4094 goto done;
4095
4096 if (dev->priv_flags & IFF_802_1Q_VLAN) {
4097 dev = vlan_dev_real_dev(dev);
4098 goto recheck;
4099 }
4100
4101 if (!is_qlcnic_netdev(dev))
4102 goto done;
4103
4104 adapter = netdev_priv(dev);
4105
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +00004106 if (!adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004107 goto done;
4108
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00004109 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004110 goto done;
4111
4112 switch (event) {
4113 case NETDEV_UP:
4114 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
4115 break;
4116 case NETDEV_DOWN:
4117 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
4118 break;
4119 default:
4120 break;
4121 }
4122
4123done:
4124 return NOTIFY_DONE;
4125}
4126
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004127static struct notifier_block qlcnic_netdev_cb = {
4128 .notifier_call = qlcnic_netdev_event,
4129};
4130
4131static struct notifier_block qlcnic_inetaddr_cb = {
4132 .notifier_call = qlcnic_inetaddr_event,
4133};
4134#else
4135static void
4136qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
4137{ }
4138#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00004139static struct pci_error_handlers qlcnic_err_handler = {
4140 .error_detected = qlcnic_io_error_detected,
4141 .slot_reset = qlcnic_io_slot_reset,
4142 .resume = qlcnic_io_resume,
4143};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004144
4145static struct pci_driver qlcnic_driver = {
4146 .name = qlcnic_driver_name,
4147 .id_table = qlcnic_pci_tbl,
4148 .probe = qlcnic_probe,
4149 .remove = __devexit_p(qlcnic_remove),
4150#ifdef CONFIG_PM
4151 .suspend = qlcnic_suspend,
4152 .resume = qlcnic_resume,
4153#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00004154 .shutdown = qlcnic_shutdown,
4155 .err_handler = &qlcnic_err_handler
4156
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004157};
4158
4159static int __init qlcnic_init_module(void)
4160{
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004161 int ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004162
4163 printk(KERN_INFO "%s\n", qlcnic_driver_string);
4164
4165#ifdef CONFIG_INET
4166 register_netdevice_notifier(&qlcnic_netdev_cb);
4167 register_inetaddr_notifier(&qlcnic_inetaddr_cb);
4168#endif
4169
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004170 ret = pci_register_driver(&qlcnic_driver);
4171 if (ret) {
4172#ifdef CONFIG_INET
4173 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
4174 unregister_netdevice_notifier(&qlcnic_netdev_cb);
4175#endif
4176 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004177
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004178 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004179}
4180
4181module_init(qlcnic_init_module);
4182
4183static void __exit qlcnic_exit_module(void)
4184{
4185
4186 pci_unregister_driver(&qlcnic_driver);
4187
4188#ifdef CONFIG_INET
4189 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
4190 unregister_netdevice_notifier(&qlcnic_netdev_cb);
4191#endif
4192}
4193
4194module_exit(qlcnic_exit_module);