blob: 5fd2abd1eb6710a6ea3f08d54edf553ef643a775 [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{
Yinglin Luanbf827912010-08-22 21:57:56 +00002516 int ring;
2517 struct qlcnic_host_sds_ring *sds_ring;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002518 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Yinglin Luanbf827912010-08-22 21:57:56 +00002519 struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
2520
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002521 disable_irq(adapter->irq);
Yinglin Luanbf827912010-08-22 21:57:56 +00002522 for (ring = 0; ring < adapter->max_sds_rings; ring++) {
2523 sds_ring = &recv_ctx->sds_rings[ring];
2524 qlcnic_intr(adapter->irq, sds_ring);
2525 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002526 enable_irq(adapter->irq);
2527}
2528#endif
2529
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002530static void
2531qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
2532{
2533 u32 val;
2534
2535 val = adapter->portnum & 0xf;
2536 val |= encoding << 7;
2537 val |= (jiffies - adapter->dev_rst_time) << 8;
2538
2539 QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
2540 adapter->dev_rst_time = jiffies;
2541}
2542
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002543static int
2544qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002545{
2546 u32 val;
2547
2548 WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
2549 state != QLCNIC_DEV_NEED_QUISCENT);
2550
2551 if (qlcnic_api_lock(adapter))
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002552 return -EIO;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002553
2554 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
2555
2556 if (state == QLCNIC_DEV_NEED_RESET)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002557 QLC_DEV_SET_RST_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002558 else if (state == QLCNIC_DEV_NEED_QUISCENT)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002559 QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002560
2561 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2562
2563 qlcnic_api_unlock(adapter);
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002564
2565 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002566}
2567
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002568static int
2569qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
2570{
2571 u32 val;
2572
2573 if (qlcnic_api_lock(adapter))
2574 return -EBUSY;
2575
2576 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002577 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002578 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2579
2580 qlcnic_api_unlock(adapter);
2581
2582 return 0;
2583}
2584
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002585static void
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002586qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002587{
2588 u32 val;
2589
2590 if (qlcnic_api_lock(adapter))
2591 goto err;
2592
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002593 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002594 QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002595 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002596
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002597 if (failed) {
2598 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
2599 dev_info(&adapter->pdev->dev,
2600 "Device state set to Failed. Please Reboot\n");
2601 } else if (!(val & 0x11111111))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002602 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
2603
2604 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002605 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002606 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2607
2608 qlcnic_api_unlock(adapter);
2609err:
2610 adapter->fw_fail_cnt = 0;
2611 clear_bit(__QLCNIC_START_FW, &adapter->state);
2612 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2613}
2614
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002615/* Grab api lock, before checking state */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002616static int
2617qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
2618{
2619 int act, state;
2620
2621 state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002622 act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002623
2624 if (((state & 0x11111111) == (act & 0x11111111)) ||
2625 ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
2626 return 0;
2627 else
2628 return 1;
2629}
2630
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002631static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
2632{
2633 u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
2634
2635 if (val != QLCNIC_DRV_IDC_VER) {
2636 dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
2637 " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
2638 }
2639
2640 return 0;
2641}
2642
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002643static int
2644qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
2645{
2646 u32 val, prev_state;
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002647 u8 dev_init_timeo = adapter->dev_init_timeo;
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002648 u8 portnum = adapter->portnum;
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002649 u8 ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002650
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002651 if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
2652 return 1;
2653
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002654 if (qlcnic_api_lock(adapter))
2655 return -1;
2656
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002657 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002658 if (!(val & (1 << (portnum * 4)))) {
2659 QLC_DEV_SET_REF_CNT(val, portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002660 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002661 }
2662
2663 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002664 QLCDB(adapter, HW, "Device state = %u\n", prev_state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002665
2666 switch (prev_state) {
2667 case QLCNIC_DEV_COLD:
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002668 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002669 QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002670 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002671 qlcnic_api_unlock(adapter);
2672 return 1;
2673
2674 case QLCNIC_DEV_READY:
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002675 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002676 qlcnic_api_unlock(adapter);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002677 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002678
2679 case QLCNIC_DEV_NEED_RESET:
2680 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002681 QLC_DEV_SET_RST_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002682 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2683 break;
2684
2685 case QLCNIC_DEV_NEED_QUISCENT:
2686 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002687 QLC_DEV_SET_QSCNT_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002688 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2689 break;
2690
2691 case QLCNIC_DEV_FAILED:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00002692 dev_err(&adapter->pdev->dev, "Device in failed state.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002693 qlcnic_api_unlock(adapter);
2694 return -1;
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002695
2696 case QLCNIC_DEV_INITIALIZING:
2697 case QLCNIC_DEV_QUISCENT:
2698 break;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002699 }
2700
2701 qlcnic_api_unlock(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002702
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002703 do {
2704 msleep(1000);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002705 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2706
2707 if (prev_state == QLCNIC_DEV_QUISCENT)
2708 continue;
2709 } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002710
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002711 if (!dev_init_timeo) {
2712 dev_err(&adapter->pdev->dev,
2713 "Waiting for device to initialize timeout\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002714 return -1;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002715 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002716
2717 if (qlcnic_api_lock(adapter))
2718 return -1;
2719
2720 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002721 QLC_DEV_CLR_RST_QSCNT(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002722 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2723
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002724 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002725 qlcnic_api_unlock(adapter);
2726
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002727 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002728}
2729
2730static void
2731qlcnic_fwinit_work(struct work_struct *work)
2732{
2733 struct qlcnic_adapter *adapter = container_of(work,
2734 struct qlcnic_adapter, fw_work.work);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002735 u32 dev_state = 0xf;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002736
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002737 if (qlcnic_api_lock(adapter))
2738 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002739
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002740 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2741 if (dev_state == QLCNIC_DEV_QUISCENT) {
2742 qlcnic_api_unlock(adapter);
2743 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2744 FW_POLL_DELAY * 2);
2745 return;
2746 }
2747
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002748 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002749 qlcnic_api_unlock(adapter);
2750 goto wait_npar;
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002751 }
2752
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002753 if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
2754 dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
2755 adapter->reset_ack_timeo);
2756 goto skip_ack_check;
2757 }
2758
2759 if (!qlcnic_check_drv_state(adapter)) {
2760skip_ack_check:
2761 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002762
2763 if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2764 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2765 QLCNIC_DEV_QUISCENT);
2766 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2767 FW_POLL_DELAY * 2);
2768 QLCDB(adapter, DRV, "Quiscing the driver\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002769 qlcnic_idc_debug_info(adapter, 0);
2770
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002771 qlcnic_api_unlock(adapter);
2772 return;
2773 }
2774
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002775 if (dev_state == QLCNIC_DEV_NEED_RESET) {
2776 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2777 QLCNIC_DEV_INITIALIZING);
2778 set_bit(__QLCNIC_START_FW, &adapter->state);
2779 QLCDB(adapter, DRV, "Restarting fw\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002780 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002781 }
2782
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002783 qlcnic_api_unlock(adapter);
2784
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002785 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002786 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002787 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002788 return;
2789 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002790 goto err_ret;
2791 }
2792
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002793 qlcnic_api_unlock(adapter);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002794
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002795wait_npar:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002796 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002797 QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002798
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002799 switch (dev_state) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002800 case QLCNIC_DEV_READY:
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002801 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002802 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002803 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002804 return;
2805 }
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002806 case QLCNIC_DEV_FAILED:
2807 break;
2808 default:
2809 qlcnic_schedule_work(adapter,
2810 qlcnic_fwinit_work, FW_POLL_DELAY);
2811 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002812 }
2813
2814err_ret:
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002815 dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
2816 "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002817 netif_device_attach(adapter->netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002818 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002819}
2820
2821static void
2822qlcnic_detach_work(struct work_struct *work)
2823{
2824 struct qlcnic_adapter *adapter = container_of(work,
2825 struct qlcnic_adapter, fw_work.work);
2826 struct net_device *netdev = adapter->netdev;
2827 u32 status;
2828
2829 netif_device_detach(netdev);
2830
2831 qlcnic_down(adapter, netdev);
2832
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002833 status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
2834
2835 if (status & QLCNIC_RCODE_FATAL_ERROR)
2836 goto err_ret;
2837
2838 if (adapter->temp == QLCNIC_TEMP_PANIC)
2839 goto err_ret;
2840
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002841 if (qlcnic_set_drv_state(adapter, adapter->dev_state))
2842 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002843
2844 adapter->fw_wait_cnt = 0;
2845
2846 qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
2847
2848 return;
2849
2850err_ret:
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002851 dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
2852 status, adapter->temp);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002853 netif_device_attach(netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002854 qlcnic_clr_all_drv_state(adapter, 1);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002855}
2856
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002857/*Transit NPAR state to NON Operational */
2858static void
2859qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
2860{
2861 u32 state;
2862
2863 state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2864 if (state == QLCNIC_DEV_NPAR_NON_OPER)
2865 return;
2866
2867 if (qlcnic_api_lock(adapter))
2868 return;
2869 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
2870 qlcnic_api_unlock(adapter);
2871}
2872
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002873/*Transit to RESET state from READY state only */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002874static void
2875qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
2876{
2877 u32 state;
2878
Anirban Chakrabortycea89752010-07-13 20:33:35 +00002879 adapter->need_fw_reset = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002880 if (qlcnic_api_lock(adapter))
2881 return;
2882
2883 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2884
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002885 if (state == QLCNIC_DEV_READY) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002886 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002887 QLCDB(adapter, DRV, "NEED_RESET state set\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002888 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002889 }
2890
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002891 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002892 qlcnic_api_unlock(adapter);
2893}
2894
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002895/* Transit to NPAR READY state from NPAR NOT READY state */
2896static void
2897qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
2898{
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002899 if (qlcnic_api_lock(adapter))
2900 return;
2901
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002902 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
2903 QLCDB(adapter, DRV, "NPAR operational state set\n");
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002904
2905 qlcnic_api_unlock(adapter);
2906}
2907
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002908static void
2909qlcnic_schedule_work(struct qlcnic_adapter *adapter,
2910 work_func_t func, int delay)
2911{
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002912 if (test_bit(__QLCNIC_AER, &adapter->state))
2913 return;
2914
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002915 INIT_DELAYED_WORK(&adapter->fw_work, func);
2916 schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
2917}
2918
2919static void
2920qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
2921{
2922 while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
2923 msleep(10);
2924
2925 cancel_delayed_work_sync(&adapter->fw_work);
2926}
2927
2928static void
2929qlcnic_attach_work(struct work_struct *work)
2930{
2931 struct qlcnic_adapter *adapter = container_of(work,
2932 struct qlcnic_adapter, fw_work.work);
2933 struct net_device *netdev = adapter->netdev;
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002934 u32 npar_state;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002935
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002936 if (adapter->op_mode != QLCNIC_MGMT_FUNC) {
2937 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2938 if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
2939 qlcnic_clr_all_drv_state(adapter, 0);
2940 else if (npar_state != QLCNIC_DEV_NPAR_OPER)
2941 qlcnic_schedule_work(adapter, qlcnic_attach_work,
2942 FW_POLL_DELAY);
2943 else
2944 goto attach;
2945 QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n");
2946 return;
2947 }
2948attach:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002949 if (netif_running(netdev)) {
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00002950 if (qlcnic_up(adapter, netdev))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002951 goto done;
2952
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002953 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2954 }
2955
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002956done:
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002957 netif_device_attach(netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002958 adapter->fw_fail_cnt = 0;
2959 clear_bit(__QLCNIC_RESETTING, &adapter->state);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002960
2961 if (!qlcnic_clr_drv_state(adapter))
2962 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2963 FW_POLL_DELAY);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002964}
2965
2966static int
2967qlcnic_check_health(struct qlcnic_adapter *adapter)
2968{
Sony Chacko4e708122010-08-31 17:17:44 +00002969 u32 state = 0, heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002970 struct net_device *netdev = adapter->netdev;
2971
2972 if (qlcnic_check_temp(adapter))
2973 goto detach;
2974
Amit Kumar Salecha2372a5f2010-05-13 03:07:42 +00002975 if (adapter->need_fw_reset)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002976 qlcnic_dev_request_reset(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002977
2978 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002979 if (state == QLCNIC_DEV_NEED_RESET ||
2980 state == QLCNIC_DEV_NEED_QUISCENT) {
2981 qlcnic_set_npar_non_operational(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002982 adapter->need_fw_reset = 1;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002983 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002984
Sony Chacko4e708122010-08-31 17:17:44 +00002985 heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
2986 if (heartbeat != adapter->heartbeat) {
2987 adapter->heartbeat = heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002988 adapter->fw_fail_cnt = 0;
2989 if (adapter->need_fw_reset)
2990 goto detach;
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002991
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002992 if (adapter->reset_context &&
2993 auto_fw_reset == AUTO_FW_RESET_ENABLED) {
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002994 qlcnic_reset_hw_context(adapter);
2995 adapter->netdev->trans_start = jiffies;
2996 }
2997
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002998 return 0;
2999 }
3000
3001 if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
3002 return 0;
3003
3004 qlcnic_dev_request_reset(adapter);
3005
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00003006 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED))
3007 clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003008
3009 dev_info(&netdev->dev, "firmware hang detected\n");
3010
3011detach:
3012 adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
3013 QLCNIC_DEV_NEED_RESET;
3014
3015 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00003016 !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) {
3017
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003018 qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00003019 QLCDB(adapter, DRV, "fw recovery scheduled.\n");
3020 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003021
3022 return 1;
3023}
3024
3025static void
3026qlcnic_fw_poll_work(struct work_struct *work)
3027{
3028 struct qlcnic_adapter *adapter = container_of(work,
3029 struct qlcnic_adapter, fw_work.work);
3030
3031 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
3032 goto reschedule;
3033
3034
3035 if (qlcnic_check_health(adapter))
3036 return;
3037
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00003038 if (adapter->fhash.fnum)
3039 qlcnic_prune_lb_filters(adapter);
3040
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003041reschedule:
3042 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
3043}
3044
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003045static int qlcnic_is_first_func(struct pci_dev *pdev)
3046{
3047 struct pci_dev *oth_pdev;
3048 int val = pdev->devfn;
3049
3050 while (val-- > 0) {
3051 oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
3052 (pdev->bus), pdev->bus->number,
3053 PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003054 if (!oth_pdev)
3055 continue;
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003056
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003057 if (oth_pdev->current_state != PCI_D3cold) {
3058 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003059 return 0;
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003060 }
3061 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003062 }
3063 return 1;
3064}
3065
3066static int qlcnic_attach_func(struct pci_dev *pdev)
3067{
3068 int err, first_func;
3069 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3070 struct net_device *netdev = adapter->netdev;
3071
3072 pdev->error_state = pci_channel_io_normal;
3073
3074 err = pci_enable_device(pdev);
3075 if (err)
3076 return err;
3077
3078 pci_set_power_state(pdev, PCI_D0);
3079 pci_set_master(pdev);
3080 pci_restore_state(pdev);
3081
3082 first_func = qlcnic_is_first_func(pdev);
3083
3084 if (qlcnic_api_lock(adapter))
3085 return -EINVAL;
3086
Amit Kumar Salecha933fce122010-08-17 00:34:19 +00003087 if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003088 adapter->need_fw_reset = 1;
3089 set_bit(__QLCNIC_START_FW, &adapter->state);
3090 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
3091 QLCDB(adapter, DRV, "Restarting fw\n");
3092 }
3093 qlcnic_api_unlock(adapter);
3094
3095 err = adapter->nic_ops->start_firmware(adapter);
3096 if (err)
3097 return err;
3098
3099 qlcnic_clr_drv_state(adapter);
3100 qlcnic_setup_intr(adapter);
3101
3102 if (netif_running(netdev)) {
3103 err = qlcnic_attach(adapter);
3104 if (err) {
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00003105 qlcnic_clr_all_drv_state(adapter, 1);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003106 clear_bit(__QLCNIC_AER, &adapter->state);
3107 netif_device_attach(netdev);
3108 return err;
3109 }
3110
3111 err = qlcnic_up(adapter, netdev);
3112 if (err)
3113 goto done;
3114
3115 qlcnic_config_indev_addr(netdev, NETDEV_UP);
3116 }
3117 done:
3118 netif_device_attach(netdev);
3119 return err;
3120}
3121
3122static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
3123 pci_channel_state_t state)
3124{
3125 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3126 struct net_device *netdev = adapter->netdev;
3127
3128 if (state == pci_channel_io_perm_failure)
3129 return PCI_ERS_RESULT_DISCONNECT;
3130
3131 if (state == pci_channel_io_normal)
3132 return PCI_ERS_RESULT_RECOVERED;
3133
3134 set_bit(__QLCNIC_AER, &adapter->state);
3135 netif_device_detach(netdev);
3136
3137 cancel_delayed_work_sync(&adapter->fw_work);
3138
3139 if (netif_running(netdev))
3140 qlcnic_down(adapter, netdev);
3141
3142 qlcnic_detach(adapter);
3143 qlcnic_teardown_intr(adapter);
3144
3145 clear_bit(__QLCNIC_RESETTING, &adapter->state);
3146
3147 pci_save_state(pdev);
3148 pci_disable_device(pdev);
3149
3150 return PCI_ERS_RESULT_NEED_RESET;
3151}
3152
3153static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
3154{
3155 return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
3156 PCI_ERS_RESULT_RECOVERED;
3157}
3158
3159static void qlcnic_io_resume(struct pci_dev *pdev)
3160{
3161 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3162
3163 pci_cleanup_aer_uncorrect_error_status(pdev);
3164
3165 if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
3166 test_and_clear_bit(__QLCNIC_AER, &adapter->state))
3167 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
3168 FW_POLL_DELAY);
3169}
3170
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003171static int
3172qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
3173{
3174 int err;
3175
3176 err = qlcnic_can_start_firmware(adapter);
3177 if (err)
3178 return err;
3179
Amit Kumar Salecha78f84e12010-08-19 05:08:28 +00003180 err = qlcnic_check_npar_opertional(adapter);
3181 if (err)
3182 return err;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00003183
Rajesh Borundia174240a2010-08-31 17:17:47 +00003184 err = qlcnic_initialize_nic(adapter);
3185 if (err)
3186 return err;
3187
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003188 qlcnic_check_options(adapter);
3189
Rajesh Borundia73733732010-08-31 17:17:50 +00003190 err = qlcnic_set_eswitch_port_config(adapter);
3191 if (err)
3192 return err;
3193
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003194 adapter->need_fw_reset = 0;
3195
3196 return err;
3197}
3198
3199static int
3200qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
3201{
3202 return -EOPNOTSUPP;
3203}
3204
3205static int
3206qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
3207{
3208 return -EOPNOTSUPP;
3209}
3210
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003211static ssize_t
3212qlcnic_store_bridged_mode(struct device *dev,
3213 struct device_attribute *attr, const char *buf, size_t len)
3214{
3215 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3216 unsigned long new;
3217 int ret = -EINVAL;
3218
3219 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
3220 goto err_out;
3221
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003222 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003223 goto err_out;
3224
3225 if (strict_strtoul(buf, 2, &new))
3226 goto err_out;
3227
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00003228 if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003229 ret = len;
3230
3231err_out:
3232 return ret;
3233}
3234
3235static ssize_t
3236qlcnic_show_bridged_mode(struct device *dev,
3237 struct device_attribute *attr, char *buf)
3238{
3239 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3240 int bridged_mode = 0;
3241
3242 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3243 bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
3244
3245 return sprintf(buf, "%d\n", bridged_mode);
3246}
3247
3248static struct device_attribute dev_attr_bridged_mode = {
3249 .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
3250 .show = qlcnic_show_bridged_mode,
3251 .store = qlcnic_store_bridged_mode,
3252};
3253
3254static ssize_t
3255qlcnic_store_diag_mode(struct device *dev,
3256 struct device_attribute *attr, const char *buf, size_t len)
3257{
3258 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3259 unsigned long new;
3260
3261 if (strict_strtoul(buf, 2, &new))
3262 return -EINVAL;
3263
3264 if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
3265 adapter->flags ^= QLCNIC_DIAG_ENABLED;
3266
3267 return len;
3268}
3269
3270static ssize_t
3271qlcnic_show_diag_mode(struct device *dev,
3272 struct device_attribute *attr, char *buf)
3273{
3274 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3275
3276 return sprintf(buf, "%d\n",
3277 !!(adapter->flags & QLCNIC_DIAG_ENABLED));
3278}
3279
3280static struct device_attribute dev_attr_diag_mode = {
3281 .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
3282 .show = qlcnic_show_diag_mode,
3283 .store = qlcnic_store_diag_mode,
3284};
3285
3286static int
3287qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
3288 loff_t offset, size_t size)
3289{
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003290 size_t crb_size = 4;
3291
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003292 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3293 return -EIO;
3294
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003295 if (offset < QLCNIC_PCI_CRBSPACE) {
3296 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
3297 QLCNIC_PCI_CAMQM_END))
3298 crb_size = 8;
3299 else
3300 return -EINVAL;
3301 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003302
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003303 if ((size != crb_size) || (offset & (crb_size-1)))
3304 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003305
3306 return 0;
3307}
3308
3309static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003310qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
3311 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003312 char *buf, loff_t offset, size_t size)
3313{
3314 struct device *dev = container_of(kobj, struct device, kobj);
3315 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3316 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003317 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003318 int ret;
3319
3320 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3321 if (ret != 0)
3322 return ret;
3323
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003324 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3325 qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
3326 memcpy(buf, &qmdata, size);
3327 } else {
3328 data = QLCRD32(adapter, offset);
3329 memcpy(buf, &data, size);
3330 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003331 return size;
3332}
3333
3334static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003335qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
3336 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003337 char *buf, loff_t offset, size_t size)
3338{
3339 struct device *dev = container_of(kobj, struct device, kobj);
3340 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3341 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003342 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003343 int ret;
3344
3345 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3346 if (ret != 0)
3347 return ret;
3348
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003349 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3350 memcpy(&qmdata, buf, size);
3351 qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
3352 } else {
3353 memcpy(&data, buf, size);
3354 QLCWR32(adapter, offset, data);
3355 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003356 return size;
3357}
3358
3359static int
3360qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
3361 loff_t offset, size_t size)
3362{
3363 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3364 return -EIO;
3365
3366 if ((size != 8) || (offset & 0x7))
3367 return -EIO;
3368
3369 return 0;
3370}
3371
3372static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003373qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
3374 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003375 char *buf, loff_t offset, size_t size)
3376{
3377 struct device *dev = container_of(kobj, struct device, kobj);
3378 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3379 u64 data;
3380 int ret;
3381
3382 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3383 if (ret != 0)
3384 return ret;
3385
3386 if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
3387 return -EIO;
3388
3389 memcpy(buf, &data, size);
3390
3391 return size;
3392}
3393
3394static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003395qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
3396 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003397 char *buf, loff_t offset, size_t size)
3398{
3399 struct device *dev = container_of(kobj, struct device, kobj);
3400 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3401 u64 data;
3402 int ret;
3403
3404 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3405 if (ret != 0)
3406 return ret;
3407
3408 memcpy(&data, buf, size);
3409
3410 if (qlcnic_pci_mem_write_2M(adapter, offset, data))
3411 return -EIO;
3412
3413 return size;
3414}
3415
3416
3417static struct bin_attribute bin_attr_crb = {
3418 .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
3419 .size = 0,
3420 .read = qlcnic_sysfs_read_crb,
3421 .write = qlcnic_sysfs_write_crb,
3422};
3423
3424static struct bin_attribute bin_attr_mem = {
3425 .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
3426 .size = 0,
3427 .read = qlcnic_sysfs_read_mem,
3428 .write = qlcnic_sysfs_write_mem,
3429};
3430
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003431static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003432validate_pm_config(struct qlcnic_adapter *adapter,
3433 struct qlcnic_pm_func_cfg *pm_cfg, int count)
3434{
3435
3436 u8 src_pci_func, s_esw_id, d_esw_id;
3437 u8 dest_pci_func;
3438 int i;
3439
3440 for (i = 0; i < count; i++) {
3441 src_pci_func = pm_cfg[i].pci_func;
3442 dest_pci_func = pm_cfg[i].dest_npar;
3443 if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
3444 || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
3445 return QL_STATUS_INVALID_PARAM;
3446
3447 if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
3448 return QL_STATUS_INVALID_PARAM;
3449
3450 if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
3451 return QL_STATUS_INVALID_PARAM;
3452
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003453 s_esw_id = adapter->npars[src_pci_func].phy_port;
3454 d_esw_id = adapter->npars[dest_pci_func].phy_port;
3455
3456 if (s_esw_id != d_esw_id)
3457 return QL_STATUS_INVALID_PARAM;
3458
3459 }
3460 return 0;
3461
3462}
3463
3464static ssize_t
3465qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
3466 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3467{
3468 struct device *dev = container_of(kobj, struct device, kobj);
3469 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3470 struct qlcnic_pm_func_cfg *pm_cfg;
3471 u32 id, action, pci_func;
3472 int count, rem, i, ret;
3473
3474 count = size / sizeof(struct qlcnic_pm_func_cfg);
3475 rem = size % sizeof(struct qlcnic_pm_func_cfg);
3476 if (rem)
3477 return QL_STATUS_INVALID_PARAM;
3478
3479 pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
3480
3481 ret = validate_pm_config(adapter, pm_cfg, count);
3482 if (ret)
3483 return ret;
3484 for (i = 0; i < count; i++) {
3485 pci_func = pm_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003486 action = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003487 id = adapter->npars[pci_func].phy_port;
3488 ret = qlcnic_config_port_mirroring(adapter, id,
3489 action, pci_func);
3490 if (ret)
3491 return ret;
3492 }
3493
3494 for (i = 0; i < count; i++) {
3495 pci_func = pm_cfg[i].pci_func;
3496 id = adapter->npars[pci_func].phy_port;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003497 adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003498 adapter->npars[pci_func].dest_npar = id;
3499 }
3500 return size;
3501}
3502
3503static ssize_t
3504qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
3505 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3506{
3507 struct device *dev = container_of(kobj, struct device, kobj);
3508 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3509 struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
3510 int i;
3511
3512 if (size != sizeof(pm_cfg))
3513 return QL_STATUS_INVALID_PARAM;
3514
3515 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3516 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3517 continue;
3518 pm_cfg[i].action = adapter->npars[i].enable_pm;
3519 pm_cfg[i].dest_npar = 0;
3520 pm_cfg[i].pci_func = i;
3521 }
3522 memcpy(buf, &pm_cfg, size);
3523
3524 return size;
3525}
3526
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003527static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003528validate_esw_config(struct qlcnic_adapter *adapter,
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003529 struct qlcnic_esw_func_cfg *esw_cfg, int count)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003530{
Rajesh Borundia7613c872010-08-31 17:17:48 +00003531 u32 op_mode;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003532 u8 pci_func;
3533 int i;
Rajesh Borundia7613c872010-08-31 17:17:48 +00003534
3535 op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE);
3536
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003537 for (i = 0; i < count; i++) {
3538 pci_func = esw_cfg[i].pci_func;
3539 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3540 return QL_STATUS_INVALID_PARAM;
3541
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003542 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3543 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003544 return QL_STATUS_INVALID_PARAM;
3545
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003546 switch (esw_cfg[i].op_mode) {
3547 case QLCNIC_PORT_DEFAULTS:
Rajesh Borundia7613c872010-08-31 17:17:48 +00003548 if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
Rajesh Borundia73733732010-08-31 17:17:50 +00003549 QLCNIC_NON_PRIV_FUNC) {
Rajesh Borundia7613c872010-08-31 17:17:48 +00003550 esw_cfg[i].mac_anti_spoof = 0;
Rajesh Borundia73733732010-08-31 17:17:50 +00003551 esw_cfg[i].mac_override = 1;
3552 }
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003553 break;
3554 case QLCNIC_ADD_VLAN:
3555 if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
3556 return QL_STATUS_INVALID_PARAM;
3557 if (!esw_cfg[i].op_type)
3558 return QL_STATUS_INVALID_PARAM;
3559 break;
3560 case QLCNIC_DEL_VLAN:
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003561 if (!esw_cfg[i].op_type)
3562 return QL_STATUS_INVALID_PARAM;
3563 break;
3564 default:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003565 return QL_STATUS_INVALID_PARAM;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003566 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003567 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003568 return 0;
3569}
3570
3571static ssize_t
3572qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
3573 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3574{
3575 struct device *dev = container_of(kobj, struct device, kobj);
3576 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3577 struct qlcnic_esw_func_cfg *esw_cfg;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003578 struct qlcnic_npar_info *npar;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003579 int count, rem, i, ret;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003580 u8 pci_func, op_mode = 0;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003581
3582 count = size / sizeof(struct qlcnic_esw_func_cfg);
3583 rem = size % sizeof(struct qlcnic_esw_func_cfg);
3584 if (rem)
3585 return QL_STATUS_INVALID_PARAM;
3586
3587 esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
3588 ret = validate_esw_config(adapter, esw_cfg, count);
3589 if (ret)
3590 return ret;
3591
3592 for (i = 0; i < count; i++) {
Rajesh Borundia0325d692010-08-19 05:08:26 +00003593 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3594 if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
3595 return QL_STATUS_INVALID_PARAM;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003596
3597 if (adapter->ahw.pci_func != esw_cfg[i].pci_func)
3598 continue;
3599
3600 op_mode = esw_cfg[i].op_mode;
3601 qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
3602 esw_cfg[i].op_mode = op_mode;
3603 esw_cfg[i].pci_func = adapter->ahw.pci_func;
3604
3605 switch (esw_cfg[i].op_mode) {
3606 case QLCNIC_PORT_DEFAULTS:
3607 qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
3608 break;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00003609 case QLCNIC_ADD_VLAN:
3610 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3611 break;
3612 case QLCNIC_DEL_VLAN:
3613 esw_cfg[i].vlan_id = 0;
3614 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3615 break;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003616 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003617 }
3618
Rajesh Borundia0325d692010-08-19 05:08:26 +00003619 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
3620 goto out;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003621
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003622 for (i = 0; i < count; i++) {
3623 pci_func = esw_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003624 npar = &adapter->npars[pci_func];
3625 switch (esw_cfg[i].op_mode) {
3626 case QLCNIC_PORT_DEFAULTS:
3627 npar->promisc_mode = esw_cfg[i].promisc_mode;
Rajesh Borundia73733732010-08-31 17:17:50 +00003628 npar->mac_override = esw_cfg[i].mac_override;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003629 npar->offload_flags = esw_cfg[i].offload_flags;
3630 npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
3631 npar->discard_tagged = esw_cfg[i].discard_tagged;
3632 break;
3633 case QLCNIC_ADD_VLAN:
3634 npar->pvid = esw_cfg[i].vlan_id;
3635 break;
3636 case QLCNIC_DEL_VLAN:
3637 npar->pvid = 0;
3638 break;
3639 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003640 }
Rajesh Borundia0325d692010-08-19 05:08:26 +00003641out:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003642 return size;
3643}
3644
3645static ssize_t
3646qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
3647 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3648{
3649 struct device *dev = container_of(kobj, struct device, kobj);
3650 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3651 struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003652 u8 i;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003653
3654 if (size != sizeof(esw_cfg))
3655 return QL_STATUS_INVALID_PARAM;
3656
3657 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3658 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3659 continue;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003660 esw_cfg[i].pci_func = i;
3661 if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
3662 return QL_STATUS_INVALID_PARAM;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003663 }
3664 memcpy(buf, &esw_cfg, size);
3665
3666 return size;
3667}
3668
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003669static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003670validate_npar_config(struct qlcnic_adapter *adapter,
3671 struct qlcnic_npar_func_cfg *np_cfg, int count)
3672{
3673 u8 pci_func, i;
3674
3675 for (i = 0; i < count; i++) {
3676 pci_func = np_cfg[i].pci_func;
3677 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3678 return QL_STATUS_INVALID_PARAM;
3679
3680 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
3681 return QL_STATUS_INVALID_PARAM;
3682
3683 if (!IS_VALID_BW(np_cfg[i].min_bw)
3684 || !IS_VALID_BW(np_cfg[i].max_bw)
3685 || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
3686 || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
3687 return QL_STATUS_INVALID_PARAM;
3688 }
3689 return 0;
3690}
3691
3692static ssize_t
3693qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
3694 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3695{
3696 struct device *dev = container_of(kobj, struct device, kobj);
3697 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3698 struct qlcnic_info nic_info;
3699 struct qlcnic_npar_func_cfg *np_cfg;
3700 int i, count, rem, ret;
3701 u8 pci_func;
3702
3703 count = size / sizeof(struct qlcnic_npar_func_cfg);
3704 rem = size % sizeof(struct qlcnic_npar_func_cfg);
3705 if (rem)
3706 return QL_STATUS_INVALID_PARAM;
3707
3708 np_cfg = (struct qlcnic_npar_func_cfg *) buf;
3709 ret = validate_npar_config(adapter, np_cfg, count);
3710 if (ret)
3711 return ret;
3712
3713 for (i = 0; i < count ; i++) {
3714 pci_func = np_cfg[i].pci_func;
3715 ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
3716 if (ret)
3717 return ret;
3718 nic_info.pci_func = pci_func;
3719 nic_info.min_tx_bw = np_cfg[i].min_bw;
3720 nic_info.max_tx_bw = np_cfg[i].max_bw;
3721 ret = qlcnic_set_nic_info(adapter, &nic_info);
3722 if (ret)
3723 return ret;
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003724 adapter->npars[i].min_bw = nic_info.min_tx_bw;
3725 adapter->npars[i].max_bw = nic_info.max_tx_bw;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003726 }
3727
3728 return size;
3729
3730}
3731static ssize_t
3732qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
3733 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3734{
3735 struct device *dev = container_of(kobj, struct device, kobj);
3736 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3737 struct qlcnic_info nic_info;
3738 struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
3739 int i, ret;
3740
3741 if (size != sizeof(np_cfg))
3742 return QL_STATUS_INVALID_PARAM;
3743
3744 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3745 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3746 continue;
3747 ret = qlcnic_get_nic_info(adapter, &nic_info, i);
3748 if (ret)
3749 return ret;
3750
3751 np_cfg[i].pci_func = i;
3752 np_cfg[i].op_mode = nic_info.op_mode;
3753 np_cfg[i].port_num = nic_info.phys_port;
3754 np_cfg[i].fw_capab = nic_info.capabilities;
3755 np_cfg[i].min_bw = nic_info.min_tx_bw ;
3756 np_cfg[i].max_bw = nic_info.max_tx_bw;
3757 np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
3758 np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
3759 }
3760 memcpy(buf, &np_cfg, size);
3761 return size;
3762}
3763
3764static ssize_t
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003765qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
3766 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3767{
3768 struct device *dev = container_of(kobj, struct device, kobj);
3769 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3770 struct qlcnic_esw_statistics port_stats;
3771 int ret;
3772
3773 if (size != sizeof(struct qlcnic_esw_statistics))
3774 return QL_STATUS_INVALID_PARAM;
3775
3776 if (offset >= QLCNIC_MAX_PCI_FUNC)
3777 return QL_STATUS_INVALID_PARAM;
3778
3779 memset(&port_stats, 0, size);
3780 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3781 &port_stats.rx);
3782 if (ret)
3783 return ret;
3784
3785 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3786 &port_stats.tx);
3787 if (ret)
3788 return ret;
3789
3790 memcpy(buf, &port_stats, size);
3791 return size;
3792}
3793
3794static ssize_t
3795qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
3796 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3797{
3798 struct device *dev = container_of(kobj, struct device, kobj);
3799 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3800 struct qlcnic_esw_statistics esw_stats;
3801 int ret;
3802
3803 if (size != sizeof(struct qlcnic_esw_statistics))
3804 return QL_STATUS_INVALID_PARAM;
3805
3806 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3807 return QL_STATUS_INVALID_PARAM;
3808
3809 memset(&esw_stats, 0, size);
3810 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3811 &esw_stats.rx);
3812 if (ret)
3813 return ret;
3814
3815 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3816 &esw_stats.tx);
3817 if (ret)
3818 return ret;
3819
3820 memcpy(buf, &esw_stats, size);
3821 return size;
3822}
3823
3824static ssize_t
3825qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
3826 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3827{
3828 struct device *dev = container_of(kobj, struct device, kobj);
3829 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3830 int ret;
3831
3832 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3833 return QL_STATUS_INVALID_PARAM;
3834
3835 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3836 QLCNIC_QUERY_RX_COUNTER);
3837 if (ret)
3838 return ret;
3839
3840 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3841 QLCNIC_QUERY_TX_COUNTER);
3842 if (ret)
3843 return ret;
3844
3845 return size;
3846}
3847
3848static ssize_t
3849qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
3850 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3851{
3852
3853 struct device *dev = container_of(kobj, struct device, kobj);
3854 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3855 int ret;
3856
3857 if (offset >= QLCNIC_MAX_PCI_FUNC)
3858 return QL_STATUS_INVALID_PARAM;
3859
3860 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3861 QLCNIC_QUERY_RX_COUNTER);
3862 if (ret)
3863 return ret;
3864
3865 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3866 QLCNIC_QUERY_TX_COUNTER);
3867 if (ret)
3868 return ret;
3869
3870 return size;
3871}
3872
3873static ssize_t
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003874qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
3875 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3876{
3877 struct device *dev = container_of(kobj, struct device, kobj);
3878 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3879 struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
Dan Carpentere88db3b2010-08-09 21:49:36 +00003880 struct qlcnic_pci_info *pci_info;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003881 int i, ret;
3882
3883 if (size != sizeof(pci_cfg))
3884 return QL_STATUS_INVALID_PARAM;
3885
Dan Carpentere88db3b2010-08-09 21:49:36 +00003886 pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
3887 if (!pci_info)
3888 return -ENOMEM;
3889
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003890 ret = qlcnic_get_pci_info(adapter, pci_info);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003891 if (ret) {
3892 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003893 return ret;
Dan Carpentere88db3b2010-08-09 21:49:36 +00003894 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003895
3896 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3897 pci_cfg[i].pci_func = pci_info[i].id;
3898 pci_cfg[i].func_type = pci_info[i].type;
3899 pci_cfg[i].port_num = pci_info[i].default_port;
3900 pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
3901 pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
3902 memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
3903 }
3904 memcpy(buf, &pci_cfg, size);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003905 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003906 return size;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003907}
3908static struct bin_attribute bin_attr_npar_config = {
3909 .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
3910 .size = 0,
3911 .read = qlcnic_sysfs_read_npar_config,
3912 .write = qlcnic_sysfs_write_npar_config,
3913};
3914
3915static struct bin_attribute bin_attr_pci_config = {
3916 .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
3917 .size = 0,
3918 .read = qlcnic_sysfs_read_pci_config,
3919 .write = NULL,
3920};
3921
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003922static struct bin_attribute bin_attr_port_stats = {
3923 .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
3924 .size = 0,
3925 .read = qlcnic_sysfs_get_port_stats,
3926 .write = qlcnic_sysfs_clear_port_stats,
3927};
3928
3929static struct bin_attribute bin_attr_esw_stats = {
3930 .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
3931 .size = 0,
3932 .read = qlcnic_sysfs_get_esw_stats,
3933 .write = qlcnic_sysfs_clear_esw_stats,
3934};
3935
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003936static struct bin_attribute bin_attr_esw_config = {
3937 .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
3938 .size = 0,
3939 .read = qlcnic_sysfs_read_esw_config,
3940 .write = qlcnic_sysfs_write_esw_config,
3941};
3942
3943static struct bin_attribute bin_attr_pm_config = {
3944 .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
3945 .size = 0,
3946 .read = qlcnic_sysfs_read_pm_config,
3947 .write = qlcnic_sysfs_write_pm_config,
3948};
3949
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003950static void
3951qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
3952{
3953 struct device *dev = &adapter->pdev->dev;
3954
3955 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3956 if (device_create_file(dev, &dev_attr_bridged_mode))
3957 dev_warn(dev,
3958 "failed to create bridged_mode sysfs entry\n");
3959}
3960
3961static void
3962qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
3963{
3964 struct device *dev = &adapter->pdev->dev;
3965
3966 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3967 device_remove_file(dev, &dev_attr_bridged_mode);
3968}
3969
3970static void
3971qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
3972{
3973 struct device *dev = &adapter->pdev->dev;
3974
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003975 if (device_create_bin_file(dev, &bin_attr_port_stats))
3976 dev_info(dev, "failed to create port stats sysfs entry");
3977
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003978 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3979 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003980 if (device_create_file(dev, &dev_attr_diag_mode))
3981 dev_info(dev, "failed to create diag_mode sysfs entry\n");
3982 if (device_create_bin_file(dev, &bin_attr_crb))
3983 dev_info(dev, "failed to create crb sysfs entry\n");
3984 if (device_create_bin_file(dev, &bin_attr_mem))
3985 dev_info(dev, "failed to create mem sysfs entry\n");
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003986 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
3987 return;
3988 if (device_create_bin_file(dev, &bin_attr_esw_config))
3989 dev_info(dev, "failed to create esw config sysfs entry");
3990 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003991 return;
3992 if (device_create_bin_file(dev, &bin_attr_pci_config))
3993 dev_info(dev, "failed to create pci config sysfs entry");
3994 if (device_create_bin_file(dev, &bin_attr_npar_config))
3995 dev_info(dev, "failed to create npar config sysfs entry");
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003996 if (device_create_bin_file(dev, &bin_attr_pm_config))
3997 dev_info(dev, "failed to create pm config sysfs entry");
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003998 if (device_create_bin_file(dev, &bin_attr_esw_stats))
3999 dev_info(dev, "failed to create eswitch stats sysfs entry");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004000}
4001
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004002static void
4003qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
4004{
4005 struct device *dev = &adapter->pdev->dev;
4006
Amit Kumar Salechab6021212010-08-17 00:34:22 +00004007 device_remove_bin_file(dev, &bin_attr_port_stats);
4008
Anirban Chakraborty132ff002010-07-09 13:15:05 +00004009 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
4010 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004011 device_remove_file(dev, &dev_attr_diag_mode);
4012 device_remove_bin_file(dev, &bin_attr_crb);
4013 device_remove_bin_file(dev, &bin_attr_mem);
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00004014 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
4015 return;
4016 device_remove_bin_file(dev, &bin_attr_esw_config);
4017 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00004018 return;
4019 device_remove_bin_file(dev, &bin_attr_pci_config);
4020 device_remove_bin_file(dev, &bin_attr_npar_config);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00004021 device_remove_bin_file(dev, &bin_attr_pm_config);
Amit Kumar Salechab6021212010-08-17 00:34:22 +00004022 device_remove_bin_file(dev, &bin_attr_esw_stats);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004023}
4024
4025#ifdef CONFIG_INET
4026
4027#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
4028
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004029static void
4030qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
4031{
4032 struct in_device *indev;
4033 struct qlcnic_adapter *adapter = netdev_priv(dev);
4034
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004035 indev = in_dev_get(dev);
4036 if (!indev)
4037 return;
4038
4039 for_ifa(indev) {
4040 switch (event) {
4041 case NETDEV_UP:
4042 qlcnic_config_ipaddr(adapter,
4043 ifa->ifa_address, QLCNIC_IP_UP);
4044 break;
4045 case NETDEV_DOWN:
4046 qlcnic_config_ipaddr(adapter,
4047 ifa->ifa_address, QLCNIC_IP_DOWN);
4048 break;
4049 default:
4050 break;
4051 }
4052 } endfor_ifa(indev);
4053
4054 in_dev_put(indev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004055}
4056
4057static int qlcnic_netdev_event(struct notifier_block *this,
4058 unsigned long event, void *ptr)
4059{
4060 struct qlcnic_adapter *adapter;
4061 struct net_device *dev = (struct net_device *)ptr;
4062
4063recheck:
4064 if (dev == NULL)
4065 goto done;
4066
4067 if (dev->priv_flags & IFF_802_1Q_VLAN) {
4068 dev = vlan_dev_real_dev(dev);
4069 goto recheck;
4070 }
4071
4072 if (!is_qlcnic_netdev(dev))
4073 goto done;
4074
4075 adapter = netdev_priv(dev);
4076
4077 if (!adapter)
4078 goto done;
4079
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00004080 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004081 goto done;
4082
4083 qlcnic_config_indev_addr(dev, event);
4084done:
4085 return NOTIFY_DONE;
4086}
4087
4088static int
4089qlcnic_inetaddr_event(struct notifier_block *this,
4090 unsigned long event, void *ptr)
4091{
4092 struct qlcnic_adapter *adapter;
4093 struct net_device *dev;
4094
4095 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
4096
4097 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
4098
4099recheck:
4100 if (dev == NULL || !netif_running(dev))
4101 goto done;
4102
4103 if (dev->priv_flags & IFF_802_1Q_VLAN) {
4104 dev = vlan_dev_real_dev(dev);
4105 goto recheck;
4106 }
4107
4108 if (!is_qlcnic_netdev(dev))
4109 goto done;
4110
4111 adapter = netdev_priv(dev);
4112
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +00004113 if (!adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004114 goto done;
4115
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00004116 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004117 goto done;
4118
4119 switch (event) {
4120 case NETDEV_UP:
4121 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
4122 break;
4123 case NETDEV_DOWN:
4124 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
4125 break;
4126 default:
4127 break;
4128 }
4129
4130done:
4131 return NOTIFY_DONE;
4132}
4133
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004134static struct notifier_block qlcnic_netdev_cb = {
4135 .notifier_call = qlcnic_netdev_event,
4136};
4137
4138static struct notifier_block qlcnic_inetaddr_cb = {
4139 .notifier_call = qlcnic_inetaddr_event,
4140};
4141#else
4142static void
4143qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
4144{ }
4145#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00004146static struct pci_error_handlers qlcnic_err_handler = {
4147 .error_detected = qlcnic_io_error_detected,
4148 .slot_reset = qlcnic_io_slot_reset,
4149 .resume = qlcnic_io_resume,
4150};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004151
4152static struct pci_driver qlcnic_driver = {
4153 .name = qlcnic_driver_name,
4154 .id_table = qlcnic_pci_tbl,
4155 .probe = qlcnic_probe,
4156 .remove = __devexit_p(qlcnic_remove),
4157#ifdef CONFIG_PM
4158 .suspend = qlcnic_suspend,
4159 .resume = qlcnic_resume,
4160#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00004161 .shutdown = qlcnic_shutdown,
4162 .err_handler = &qlcnic_err_handler
4163
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004164};
4165
4166static int __init qlcnic_init_module(void)
4167{
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004168 int ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004169
4170 printk(KERN_INFO "%s\n", qlcnic_driver_string);
4171
4172#ifdef CONFIG_INET
4173 register_netdevice_notifier(&qlcnic_netdev_cb);
4174 register_inetaddr_notifier(&qlcnic_inetaddr_cb);
4175#endif
4176
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004177 ret = pci_register_driver(&qlcnic_driver);
4178 if (ret) {
4179#ifdef CONFIG_INET
4180 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
4181 unregister_netdevice_notifier(&qlcnic_netdev_cb);
4182#endif
4183 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004184
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004185 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004186}
4187
4188module_init(qlcnic_init_module);
4189
4190static void __exit qlcnic_exit_module(void)
4191{
4192
4193 pci_unregister_driver(&qlcnic_driver);
4194
4195#ifdef CONFIG_INET
4196 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
4197 unregister_netdevice_notifier(&qlcnic_netdev_cb);
4198#endif
4199}
4200
4201module_exit(qlcnic_exit_module);