blob: 0fbfb53f2594f0da3f00440ad57b2396dcb03bdb [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,
1829 u64 uaddr, struct qlcnic_host_tx_ring *tx_ring)
1830{
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]);
1848 mac_req->op = QLCNIC_MAC_ADD;
1849 memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
1850
1851 tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
1852}
1853
1854#define QLCNIC_MAC_HASH(MAC)\
1855 ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
1856
1857static void
1858qlcnic_send_filter(struct qlcnic_adapter *adapter,
1859 struct qlcnic_host_tx_ring *tx_ring,
1860 struct cmd_desc_type0 *first_desc,
1861 struct sk_buff *skb)
1862{
1863 struct ethhdr *phdr = (struct ethhdr *)(skb->data);
1864 struct qlcnic_filter *fil, *tmp_fil;
1865 struct hlist_node *tmp_hnode, *n;
1866 struct hlist_head *head;
1867 u64 src_addr = 0;
1868 u8 hindex;
1869
1870 if (!compare_ether_addr(phdr->h_source, adapter->mac_addr))
1871 return;
1872
1873 if (adapter->fhash.fnum >= adapter->fhash.fmax)
1874 return;
1875
1876 memcpy(&src_addr, phdr->h_source, ETH_ALEN);
1877 hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
1878 head = &(adapter->fhash.fhead[hindex]);
1879
1880 hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
1881 if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN)) {
1882 tmp_fil->ftime = jiffies;
1883 return;
1884 }
1885 }
1886
1887 fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
1888 if (!fil)
1889 return;
1890
1891 qlcnic_change_filter(adapter, src_addr, tx_ring);
1892
1893 fil->ftime = jiffies;
1894 memcpy(fil->faddr, &src_addr, ETH_ALEN);
1895 spin_lock(&adapter->mac_learn_lock);
1896 hlist_add_head(&(fil->fnode), head);
1897 adapter->fhash.fnum++;
1898 spin_unlock(&adapter->mac_learn_lock);
1899}
1900
1901static void
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001902qlcnic_tso_check(struct net_device *netdev,
1903 struct qlcnic_host_tx_ring *tx_ring,
1904 struct cmd_desc_type0 *first_desc,
1905 struct sk_buff *skb)
1906{
1907 u8 opcode = TX_ETHER_PKT;
1908 __be16 protocol = skb->protocol;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001909 u16 flags = 0;
1910 int copied, offset, copy_len, hdr_len = 0, tso = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001911 struct cmd_desc_type0 *hwdesc;
1912 struct vlan_ethhdr *vh;
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00001913 struct qlcnic_adapter *adapter = netdev_priv(netdev);
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001914 u32 producer = tx_ring->producer;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001915 int vlan_oob = first_desc->flags_opcode & cpu_to_le16(FLAGS_VLAN_OOB);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001916
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00001917 if (*(skb->data) & BIT_0) {
1918 flags |= BIT_0;
1919 memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
1920 }
1921
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001922 if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
1923 skb_shinfo(skb)->gso_size > 0) {
1924
1925 hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
1926
1927 first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
1928 first_desc->total_hdr_length = hdr_len;
1929 if (vlan_oob) {
1930 first_desc->total_hdr_length += VLAN_HLEN;
1931 first_desc->tcp_hdr_offset = VLAN_HLEN;
1932 first_desc->ip_hdr_offset = VLAN_HLEN;
1933 /* Only in case of TSO on vlan device */
1934 flags |= FLAGS_VLAN_TAGGED;
1935 }
1936
1937 opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
1938 TX_TCP_LSO6 : TX_TCP_LSO;
1939 tso = 1;
1940
1941 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
1942 u8 l4proto;
1943
1944 if (protocol == cpu_to_be16(ETH_P_IP)) {
1945 l4proto = ip_hdr(skb)->protocol;
1946
1947 if (l4proto == IPPROTO_TCP)
1948 opcode = TX_TCP_PKT;
1949 else if (l4proto == IPPROTO_UDP)
1950 opcode = TX_UDP_PKT;
1951 } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
1952 l4proto = ipv6_hdr(skb)->nexthdr;
1953
1954 if (l4proto == IPPROTO_TCP)
1955 opcode = TX_TCPV6_PKT;
1956 else if (l4proto == IPPROTO_UDP)
1957 opcode = TX_UDPV6_PKT;
1958 }
1959 }
1960
1961 first_desc->tcp_hdr_offset += skb_transport_offset(skb);
1962 first_desc->ip_hdr_offset += skb_network_offset(skb);
1963 qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
1964
1965 if (!tso)
1966 return;
1967
1968 /* For LSO, we need to copy the MAC/IP/TCP headers into
1969 * the descriptor ring
1970 */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001971 copied = 0;
1972 offset = 2;
1973
1974 if (vlan_oob) {
1975 /* Create a TSO vlan header template for firmware */
1976
1977 hwdesc = &tx_ring->desc_head[producer];
1978 tx_ring->cmd_buf_arr[producer].skb = NULL;
1979
1980 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
1981 hdr_len + VLAN_HLEN);
1982
1983 vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
1984 skb_copy_from_linear_data(skb, vh, 12);
1985 vh->h_vlan_proto = htons(ETH_P_8021Q);
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00001986 vh->h_vlan_TCI = htons(first_desc->vlan_TCI);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00001987 skb_copy_from_linear_data_offset(skb, 12,
1988 (char *)vh + 16, copy_len - 16);
1989
1990 copied = copy_len - VLAN_HLEN;
1991 offset = 0;
1992
1993 producer = get_next_index(producer, tx_ring->num_desc);
1994 }
1995
1996 while (copied < hdr_len) {
1997
1998 copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
1999 (hdr_len - copied));
2000
2001 hwdesc = &tx_ring->desc_head[producer];
2002 tx_ring->cmd_buf_arr[producer].skb = NULL;
2003
2004 skb_copy_from_linear_data_offset(skb, copied,
2005 (char *)hwdesc + offset, copy_len);
2006
2007 copied += copy_len;
2008 offset = 0;
2009
2010 producer = get_next_index(producer, tx_ring->num_desc);
2011 }
2012
2013 tx_ring->producer = producer;
2014 barrier();
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00002015 adapter->stats.lso_frames++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002016}
2017
2018static int
2019qlcnic_map_tx_skb(struct pci_dev *pdev,
2020 struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
2021{
2022 struct qlcnic_skb_frag *nf;
2023 struct skb_frag_struct *frag;
2024 int i, nr_frags;
2025 dma_addr_t map;
2026
2027 nr_frags = skb_shinfo(skb)->nr_frags;
2028 nf = &pbuf->frag_array[0];
2029
2030 map = pci_map_single(pdev, skb->data,
2031 skb_headlen(skb), PCI_DMA_TODEVICE);
2032 if (pci_dma_mapping_error(pdev, map))
2033 goto out_err;
2034
2035 nf->dma = map;
2036 nf->length = skb_headlen(skb);
2037
2038 for (i = 0; i < nr_frags; i++) {
2039 frag = &skb_shinfo(skb)->frags[i];
2040 nf = &pbuf->frag_array[i+1];
2041
2042 map = pci_map_page(pdev, frag->page, frag->page_offset,
2043 frag->size, PCI_DMA_TODEVICE);
2044 if (pci_dma_mapping_error(pdev, map))
2045 goto unwind;
2046
2047 nf->dma = map;
2048 nf->length = frag->size;
2049 }
2050
2051 return 0;
2052
2053unwind:
2054 while (--i >= 0) {
2055 nf = &pbuf->frag_array[i+1];
2056 pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
2057 }
2058
2059 nf = &pbuf->frag_array[0];
2060 pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
2061
2062out_err:
2063 return -ENOMEM;
2064}
2065
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00002066static int
2067qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter,
2068 struct sk_buff *skb,
2069 struct cmd_desc_type0 *first_desc)
2070{
2071 u8 opcode = 0;
2072 u16 flags = 0;
2073 __be16 protocol = skb->protocol;
2074 struct vlan_ethhdr *vh;
2075
2076 if (protocol == cpu_to_be16(ETH_P_8021Q)) {
2077 vh = (struct vlan_ethhdr *)skb->data;
2078 protocol = vh->h_vlan_encapsulated_proto;
2079 flags = FLAGS_VLAN_TAGGED;
2080 qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI));
2081 } else if (vlan_tx_tag_present(skb)) {
2082 flags = FLAGS_VLAN_OOB;
2083 qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb));
2084 }
2085 if (unlikely(adapter->pvid)) {
2086 if (first_desc->vlan_TCI &&
2087 !(adapter->flags & QLCNIC_TAGGING_ENABLED))
2088 return -EIO;
2089 if (first_desc->vlan_TCI &&
2090 (adapter->flags & QLCNIC_TAGGING_ENABLED))
2091 goto set_flags;
2092
2093 flags = FLAGS_VLAN_OOB;
2094 qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid);
2095 }
2096set_flags:
2097 qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
2098 return 0;
2099}
2100
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002101static inline void
2102qlcnic_clear_cmddesc(u64 *desc)
2103{
2104 desc[0] = 0ULL;
2105 desc[2] = 0ULL;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00002106 desc[7] = 0ULL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002107}
2108
Amit Kumar Salechacdaff182010-02-01 05:25:00 +00002109netdev_tx_t
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002110qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
2111{
2112 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2113 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
2114 struct qlcnic_cmd_buffer *pbuf;
2115 struct qlcnic_skb_frag *buffrag;
2116 struct cmd_desc_type0 *hwdesc, *first_desc;
2117 struct pci_dev *pdev;
Rajesh Borundiadcb50af2010-08-31 17:17:49 +00002118 struct ethhdr *phdr;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002119 int i, k;
2120
2121 u32 producer;
2122 int frag_count, no_of_desc;
2123 u32 num_txd = tx_ring->num_desc;
2124
Amit Kumar Salecha780ab792010-04-22 02:51:41 +00002125 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
2126 netif_stop_queue(netdev);
2127 return NETDEV_TX_BUSY;
2128 }
2129
Sony Chackofe4d4342010-08-19 05:08:27 +00002130 if (adapter->flags & QLCNIC_MACSPOOF) {
Rajesh Borundiadcb50af2010-08-31 17:17:49 +00002131 phdr = (struct ethhdr *)skb->data;
2132 if (compare_ether_addr(phdr->h_source,
Sony Chackofe4d4342010-08-19 05:08:27 +00002133 adapter->mac_addr))
2134 goto drop_packet;
2135 }
2136
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002137 frag_count = skb_shinfo(skb)->nr_frags + 1;
2138
2139 /* 4 fragments per cmd des */
2140 no_of_desc = (frag_count + 3) >> 2;
2141
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002142 if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002143 netif_stop_queue(netdev);
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002144 smp_mb();
2145 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
2146 netif_start_queue(netdev);
2147 else {
2148 adapter->stats.xmit_off++;
2149 return NETDEV_TX_BUSY;
2150 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002151 }
2152
2153 producer = tx_ring->producer;
2154 pbuf = &tx_ring->cmd_buf_arr[producer];
2155
2156 pdev = adapter->pdev;
2157
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00002158 first_desc = hwdesc = &tx_ring->desc_head[producer];
2159 qlcnic_clear_cmddesc((u64 *)hwdesc);
2160
2161 if (qlcnic_check_tx_tagging(adapter, skb, first_desc))
2162 goto drop_packet;
2163
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00002164 if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
2165 adapter->stats.tx_dma_map_error++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002166 goto drop_packet;
Amit Kumar Salecha8ae6df92010-04-22 02:51:35 +00002167 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002168
2169 pbuf->skb = skb;
2170 pbuf->frag_count = frag_count;
2171
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002172 qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
2173 qlcnic_set_tx_port(first_desc, adapter->portnum);
2174
2175 for (i = 0; i < frag_count; i++) {
2176
2177 k = i % 4;
2178
2179 if ((k == 0) && (i > 0)) {
2180 /* move to next desc.*/
2181 producer = get_next_index(producer, num_txd);
2182 hwdesc = &tx_ring->desc_head[producer];
2183 qlcnic_clear_cmddesc((u64 *)hwdesc);
2184 tx_ring->cmd_buf_arr[producer].skb = NULL;
2185 }
2186
2187 buffrag = &pbuf->frag_array[i];
2188
2189 hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
2190 switch (k) {
2191 case 0:
2192 hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
2193 break;
2194 case 1:
2195 hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
2196 break;
2197 case 2:
2198 hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
2199 break;
2200 case 3:
2201 hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
2202 break;
2203 }
2204 }
2205
2206 tx_ring->producer = get_next_index(producer, num_txd);
2207
2208 qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
2209
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00002210 if (qlcnic_mac_learn)
2211 qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
2212
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002213 qlcnic_update_cmd_producer(adapter, tx_ring);
2214
2215 adapter->stats.txbytes += skb->len;
2216 adapter->stats.xmitcalled++;
2217
2218 return NETDEV_TX_OK;
2219
2220drop_packet:
2221 adapter->stats.txdropped++;
2222 dev_kfree_skb_any(skb);
2223 return NETDEV_TX_OK;
2224}
2225
2226static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
2227{
2228 struct net_device *netdev = adapter->netdev;
2229 u32 temp, temp_state, temp_val;
2230 int rv = 0;
2231
2232 temp = QLCRD32(adapter, CRB_TEMP_STATE);
2233
2234 temp_state = qlcnic_get_temp_state(temp);
2235 temp_val = qlcnic_get_temp_val(temp);
2236
2237 if (temp_state == QLCNIC_TEMP_PANIC) {
2238 dev_err(&netdev->dev,
2239 "Device temperature %d degrees C exceeds"
2240 " maximum allowed. Hardware has been shut down.\n",
2241 temp_val);
2242 rv = 1;
2243 } else if (temp_state == QLCNIC_TEMP_WARN) {
2244 if (adapter->temp == QLCNIC_TEMP_NORMAL) {
2245 dev_err(&netdev->dev,
2246 "Device temperature %d degrees C "
2247 "exceeds operating range."
2248 " Immediate action needed.\n",
2249 temp_val);
2250 }
2251 } else {
2252 if (adapter->temp == QLCNIC_TEMP_WARN) {
2253 dev_info(&netdev->dev,
2254 "Device temperature is now %d degrees C"
2255 " in normal range.\n", temp_val);
2256 }
2257 }
2258 adapter->temp = temp_state;
2259 return rv;
2260}
2261
2262void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
2263{
2264 struct net_device *netdev = adapter->netdev;
2265
2266 if (adapter->ahw.linkup && !linkup) {
Sony Chacko69324272010-08-17 00:34:23 +00002267 netdev_info(netdev, "NIC Link is down\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002268 adapter->ahw.linkup = 0;
2269 if (netif_running(netdev)) {
2270 netif_carrier_off(netdev);
2271 netif_stop_queue(netdev);
2272 }
2273 } else if (!adapter->ahw.linkup && linkup) {
Sony Chacko69324272010-08-17 00:34:23 +00002274 netdev_info(netdev, "NIC Link is up\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002275 adapter->ahw.linkup = 1;
2276 if (netif_running(netdev)) {
2277 netif_carrier_on(netdev);
2278 netif_wake_queue(netdev);
2279 }
2280 }
2281}
2282
2283static void qlcnic_tx_timeout(struct net_device *netdev)
2284{
2285 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2286
2287 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
2288 return;
2289
2290 dev_err(&netdev->dev, "transmit timeout, resetting.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002291
2292 if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002293 adapter->need_fw_reset = 1;
2294 else
2295 adapter->reset_context = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002296}
2297
2298static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
2299{
2300 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2301 struct net_device_stats *stats = &netdev->stats;
2302
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002303 stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
2304 stats->tx_packets = adapter->stats.xmitfinished;
Sucheta Chakraborty7e382592010-05-17 01:22:10 +00002305 stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002306 stats->tx_bytes = adapter->stats.txbytes;
2307 stats->rx_dropped = adapter->stats.rxdropped;
2308 stats->tx_dropped = adapter->stats.txdropped;
2309
2310 return stats;
2311}
2312
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00002313static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002314{
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002315 u32 status;
2316
2317 status = readl(adapter->isr_int_vec);
2318
2319 if (!(status & adapter->int_vec_bit))
2320 return IRQ_NONE;
2321
2322 /* check interrupt state machine, to be sure */
2323 status = readl(adapter->crb_int_state_reg);
2324 if (!ISR_LEGACY_INT_TRIGGERED(status))
2325 return IRQ_NONE;
2326
2327 writel(0xffffffff, adapter->tgt_status_reg);
2328 /* read twice to ensure write is flushed */
2329 readl(adapter->isr_int_vec);
2330 readl(adapter->isr_int_vec);
2331
Amit Kumar Salecha7eb98552010-02-01 05:24:59 +00002332 return IRQ_HANDLED;
2333}
2334
2335static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
2336{
2337 struct qlcnic_host_sds_ring *sds_ring = data;
2338 struct qlcnic_adapter *adapter = sds_ring->adapter;
2339
2340 if (adapter->flags & QLCNIC_MSIX_ENABLED)
2341 goto done;
2342 else if (adapter->flags & QLCNIC_MSI_ENABLED) {
2343 writel(0xffffffff, adapter->tgt_status_reg);
2344 goto done;
2345 }
2346
2347 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
2348 return IRQ_NONE;
2349
2350done:
2351 adapter->diag_cnt++;
2352 qlcnic_enable_int(sds_ring);
2353 return IRQ_HANDLED;
2354}
2355
2356static irqreturn_t qlcnic_intr(int irq, void *data)
2357{
2358 struct qlcnic_host_sds_ring *sds_ring = data;
2359 struct qlcnic_adapter *adapter = sds_ring->adapter;
2360
2361 if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
2362 return IRQ_NONE;
2363
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002364 napi_schedule(&sds_ring->napi);
2365
2366 return IRQ_HANDLED;
2367}
2368
2369static irqreturn_t qlcnic_msi_intr(int irq, void *data)
2370{
2371 struct qlcnic_host_sds_ring *sds_ring = data;
2372 struct qlcnic_adapter *adapter = sds_ring->adapter;
2373
2374 /* clear interrupt */
2375 writel(0xffffffff, adapter->tgt_status_reg);
2376
2377 napi_schedule(&sds_ring->napi);
2378 return IRQ_HANDLED;
2379}
2380
2381static irqreturn_t qlcnic_msix_intr(int irq, void *data)
2382{
2383 struct qlcnic_host_sds_ring *sds_ring = data;
2384
2385 napi_schedule(&sds_ring->napi);
2386 return IRQ_HANDLED;
2387}
2388
2389static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
2390{
2391 u32 sw_consumer, hw_consumer;
2392 int count = 0, i;
2393 struct qlcnic_cmd_buffer *buffer;
2394 struct pci_dev *pdev = adapter->pdev;
2395 struct net_device *netdev = adapter->netdev;
2396 struct qlcnic_skb_frag *frag;
2397 int done;
2398 struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
2399
2400 if (!spin_trylock(&adapter->tx_clean_lock))
2401 return 1;
2402
2403 sw_consumer = tx_ring->sw_consumer;
2404 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2405
2406 while (sw_consumer != hw_consumer) {
2407 buffer = &tx_ring->cmd_buf_arr[sw_consumer];
2408 if (buffer->skb) {
2409 frag = &buffer->frag_array[0];
2410 pci_unmap_single(pdev, frag->dma, frag->length,
2411 PCI_DMA_TODEVICE);
2412 frag->dma = 0ULL;
2413 for (i = 1; i < buffer->frag_count; i++) {
2414 frag++;
2415 pci_unmap_page(pdev, frag->dma, frag->length,
2416 PCI_DMA_TODEVICE);
2417 frag->dma = 0ULL;
2418 }
2419
2420 adapter->stats.xmitfinished++;
2421 dev_kfree_skb_any(buffer->skb);
2422 buffer->skb = NULL;
2423 }
2424
2425 sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
2426 if (++count >= MAX_STATUS_HANDLE)
2427 break;
2428 }
2429
2430 if (count && netif_running(netdev)) {
2431 tx_ring->sw_consumer = sw_consumer;
2432
2433 smp_mb();
2434
2435 if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002436 if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
2437 netif_wake_queue(netdev);
Sucheta Chakraborty8bfe8b92010-03-08 00:14:46 +00002438 adapter->stats.xmit_on++;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002439 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002440 }
Rajesh K Borundiaef71ff82010-06-17 02:56:41 +00002441 adapter->tx_timeo_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002442 }
2443 /*
2444 * If everything is freed up to consumer then check if the ring is full
2445 * If the ring is full then check if more needs to be freed and
2446 * schedule the call back again.
2447 *
2448 * This happens when there are 2 CPUs. One could be freeing and the
2449 * other filling it. If the ring is full when we get out of here and
2450 * the card has already interrupted the host then the host can miss the
2451 * interrupt.
2452 *
2453 * There is still a possible race condition and the host could miss an
2454 * interrupt. The card has to take care of this.
2455 */
2456 hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
2457 done = (sw_consumer == hw_consumer);
2458 spin_unlock(&adapter->tx_clean_lock);
2459
2460 return done;
2461}
2462
2463static int qlcnic_poll(struct napi_struct *napi, int budget)
2464{
2465 struct qlcnic_host_sds_ring *sds_ring =
2466 container_of(napi, struct qlcnic_host_sds_ring, napi);
2467
2468 struct qlcnic_adapter *adapter = sds_ring->adapter;
2469
2470 int tx_complete;
2471 int work_done;
2472
2473 tx_complete = qlcnic_process_cmd_ring(adapter);
2474
2475 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2476
2477 if ((work_done < budget) && tx_complete) {
2478 napi_complete(&sds_ring->napi);
2479 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2480 qlcnic_enable_int(sds_ring);
2481 }
2482
2483 return work_done;
2484}
2485
schacko8f891382010-06-17 02:56:40 +00002486static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
2487{
2488 struct qlcnic_host_sds_ring *sds_ring =
2489 container_of(napi, struct qlcnic_host_sds_ring, napi);
2490
2491 struct qlcnic_adapter *adapter = sds_ring->adapter;
2492 int work_done;
2493
2494 work_done = qlcnic_process_rcv_ring(sds_ring, budget);
2495
2496 if (work_done < budget) {
2497 napi_complete(&sds_ring->napi);
2498 if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
2499 qlcnic_enable_int(sds_ring);
2500 }
2501
2502 return work_done;
2503}
2504
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002505#ifdef CONFIG_NET_POLL_CONTROLLER
2506static void qlcnic_poll_controller(struct net_device *netdev)
2507{
2508 struct qlcnic_adapter *adapter = netdev_priv(netdev);
2509 disable_irq(adapter->irq);
2510 qlcnic_intr(adapter->irq, adapter);
2511 enable_irq(adapter->irq);
2512}
2513#endif
2514
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002515static void
2516qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
2517{
2518 u32 val;
2519
2520 val = adapter->portnum & 0xf;
2521 val |= encoding << 7;
2522 val |= (jiffies - adapter->dev_rst_time) << 8;
2523
2524 QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
2525 adapter->dev_rst_time = jiffies;
2526}
2527
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002528static int
2529qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002530{
2531 u32 val;
2532
2533 WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
2534 state != QLCNIC_DEV_NEED_QUISCENT);
2535
2536 if (qlcnic_api_lock(adapter))
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002537 return -EIO;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002538
2539 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
2540
2541 if (state == QLCNIC_DEV_NEED_RESET)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002542 QLC_DEV_SET_RST_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002543 else if (state == QLCNIC_DEV_NEED_QUISCENT)
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002544 QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002545
2546 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2547
2548 qlcnic_api_unlock(adapter);
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002549
2550 return 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002551}
2552
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002553static int
2554qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
2555{
2556 u32 val;
2557
2558 if (qlcnic_api_lock(adapter))
2559 return -EBUSY;
2560
2561 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002562 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002563 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2564
2565 qlcnic_api_unlock(adapter);
2566
2567 return 0;
2568}
2569
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002570static void
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002571qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002572{
2573 u32 val;
2574
2575 if (qlcnic_api_lock(adapter))
2576 goto err;
2577
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002578 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002579 QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002580 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002581
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002582 if (failed) {
2583 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
2584 dev_info(&adapter->pdev->dev,
2585 "Device state set to Failed. Please Reboot\n");
2586 } else if (!(val & 0x11111111))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002587 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
2588
2589 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002590 QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002591 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2592
2593 qlcnic_api_unlock(adapter);
2594err:
2595 adapter->fw_fail_cnt = 0;
2596 clear_bit(__QLCNIC_START_FW, &adapter->state);
2597 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2598}
2599
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002600/* Grab api lock, before checking state */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002601static int
2602qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
2603{
2604 int act, state;
2605
2606 state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002607 act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002608
2609 if (((state & 0x11111111) == (act & 0x11111111)) ||
2610 ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
2611 return 0;
2612 else
2613 return 1;
2614}
2615
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002616static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
2617{
2618 u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
2619
2620 if (val != QLCNIC_DRV_IDC_VER) {
2621 dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
2622 " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
2623 }
2624
2625 return 0;
2626}
2627
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002628static int
2629qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
2630{
2631 u32 val, prev_state;
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002632 u8 dev_init_timeo = adapter->dev_init_timeo;
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002633 u8 portnum = adapter->portnum;
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002634 u8 ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002635
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002636 if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
2637 return 1;
2638
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002639 if (qlcnic_api_lock(adapter))
2640 return -1;
2641
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002642 val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002643 if (!(val & (1 << (portnum * 4)))) {
2644 QLC_DEV_SET_REF_CNT(val, portnum);
Amit Kumar Salecha31018e02010-08-25 04:03:05 +00002645 QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002646 }
2647
2648 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002649 QLCDB(adapter, HW, "Device state = %u\n", prev_state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002650
2651 switch (prev_state) {
2652 case QLCNIC_DEV_COLD:
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002653 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002654 QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002655 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002656 qlcnic_api_unlock(adapter);
2657 return 1;
2658
2659 case QLCNIC_DEV_READY:
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002660 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002661 qlcnic_api_unlock(adapter);
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002662 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002663
2664 case QLCNIC_DEV_NEED_RESET:
2665 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002666 QLC_DEV_SET_RST_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002667 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2668 break;
2669
2670 case QLCNIC_DEV_NEED_QUISCENT:
2671 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002672 QLC_DEV_SET_QSCNT_RDY(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002673 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2674 break;
2675
2676 case QLCNIC_DEV_FAILED:
Amit Kumar Salechaa7fc9482010-05-17 01:22:14 +00002677 dev_err(&adapter->pdev->dev, "Device in failed state.\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002678 qlcnic_api_unlock(adapter);
2679 return -1;
Amit Kumar Salechabbd8c6a2010-04-22 02:51:36 +00002680
2681 case QLCNIC_DEV_INITIALIZING:
2682 case QLCNIC_DEV_QUISCENT:
2683 break;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002684 }
2685
2686 qlcnic_api_unlock(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002687
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002688 do {
2689 msleep(1000);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002690 prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2691
2692 if (prev_state == QLCNIC_DEV_QUISCENT)
2693 continue;
2694 } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002695
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002696 if (!dev_init_timeo) {
2697 dev_err(&adapter->pdev->dev,
2698 "Waiting for device to initialize timeout\n");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002699 return -1;
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002700 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002701
2702 if (qlcnic_api_lock(adapter))
2703 return -1;
2704
2705 val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
Amit Kumar Salecha6d2a4722010-04-22 02:51:38 +00002706 QLC_DEV_CLR_RST_QSCNT(val, portnum);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002707 QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
2708
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002709 ret = qlcnic_check_idc_ver(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002710 qlcnic_api_unlock(adapter);
2711
Sucheta Chakraborty96f81182010-05-13 03:07:47 +00002712 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002713}
2714
2715static void
2716qlcnic_fwinit_work(struct work_struct *work)
2717{
2718 struct qlcnic_adapter *adapter = container_of(work,
2719 struct qlcnic_adapter, fw_work.work);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002720 u32 dev_state = 0xf;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002721
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002722 if (qlcnic_api_lock(adapter))
2723 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002724
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002725 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2726 if (dev_state == QLCNIC_DEV_QUISCENT) {
2727 qlcnic_api_unlock(adapter);
2728 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2729 FW_POLL_DELAY * 2);
2730 return;
2731 }
2732
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002733 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002734 qlcnic_api_unlock(adapter);
2735 goto wait_npar;
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002736 }
2737
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002738 if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
2739 dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
2740 adapter->reset_ack_timeo);
2741 goto skip_ack_check;
2742 }
2743
2744 if (!qlcnic_check_drv_state(adapter)) {
2745skip_ack_check:
2746 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002747
2748 if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
2749 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2750 QLCNIC_DEV_QUISCENT);
2751 qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
2752 FW_POLL_DELAY * 2);
2753 QLCDB(adapter, DRV, "Quiscing the driver\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002754 qlcnic_idc_debug_info(adapter, 0);
2755
Sucheta Chakrabortya5e463d2010-05-13 03:07:49 +00002756 qlcnic_api_unlock(adapter);
2757 return;
2758 }
2759
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002760 if (dev_state == QLCNIC_DEV_NEED_RESET) {
2761 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
2762 QLCNIC_DEV_INITIALIZING);
2763 set_bit(__QLCNIC_START_FW, &adapter->state);
2764 QLCDB(adapter, DRV, "Restarting fw\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002765 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002766 }
2767
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002768 qlcnic_api_unlock(adapter);
2769
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002770 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002771 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002772 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002773 return;
2774 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002775 goto err_ret;
2776 }
2777
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002778 qlcnic_api_unlock(adapter);
Sucheta Chakrabortyaa5e18c2010-04-01 19:01:32 +00002779
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002780wait_npar:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002781 dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002782 QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002783
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002784 switch (dev_state) {
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002785 case QLCNIC_DEV_READY:
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002786 if (!adapter->nic_ops->start_firmware(adapter)) {
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002787 qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002788 adapter->fw_wait_cnt = 0;
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002789 return;
2790 }
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002791 case QLCNIC_DEV_FAILED:
2792 break;
2793 default:
2794 qlcnic_schedule_work(adapter,
2795 qlcnic_fwinit_work, FW_POLL_DELAY);
2796 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002797 }
2798
2799err_ret:
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002800 dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
2801 "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002802 netif_device_attach(adapter->netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002803 qlcnic_clr_all_drv_state(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002804}
2805
2806static void
2807qlcnic_detach_work(struct work_struct *work)
2808{
2809 struct qlcnic_adapter *adapter = container_of(work,
2810 struct qlcnic_adapter, fw_work.work);
2811 struct net_device *netdev = adapter->netdev;
2812 u32 status;
2813
2814 netif_device_detach(netdev);
2815
2816 qlcnic_down(adapter, netdev);
2817
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002818 status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
2819
2820 if (status & QLCNIC_RCODE_FATAL_ERROR)
2821 goto err_ret;
2822
2823 if (adapter->temp == QLCNIC_TEMP_PANIC)
2824 goto err_ret;
2825
Amit Kumar Salechaade91f82010-04-22 02:51:39 +00002826 if (qlcnic_set_drv_state(adapter, adapter->dev_state))
2827 goto err_ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002828
2829 adapter->fw_wait_cnt = 0;
2830
2831 qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
2832
2833 return;
2834
2835err_ret:
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002836 dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
2837 status, adapter->temp);
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002838 netif_device_attach(netdev);
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00002839 qlcnic_clr_all_drv_state(adapter, 1);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002840}
2841
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002842/*Transit NPAR state to NON Operational */
2843static void
2844qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
2845{
2846 u32 state;
2847
2848 state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2849 if (state == QLCNIC_DEV_NPAR_NON_OPER)
2850 return;
2851
2852 if (qlcnic_api_lock(adapter))
2853 return;
2854 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
2855 qlcnic_api_unlock(adapter);
2856}
2857
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002858/*Transit to RESET state from READY state only */
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002859static void
2860qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
2861{
2862 u32 state;
2863
Anirban Chakrabortycea89752010-07-13 20:33:35 +00002864 adapter->need_fw_reset = 1;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002865 if (qlcnic_api_lock(adapter))
2866 return;
2867
2868 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
2869
Amit Kumar Salechaf73dfc52010-04-22 02:51:37 +00002870 if (state == QLCNIC_DEV_READY) {
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002871 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00002872 QLCDB(adapter, DRV, "NEED_RESET state set\n");
Sucheta Chakraborty6df900e2010-05-13 03:07:50 +00002873 qlcnic_idc_debug_info(adapter, 0);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002874 }
2875
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002876 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002877 qlcnic_api_unlock(adapter);
2878}
2879
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002880/* Transit to NPAR READY state from NPAR NOT READY state */
2881static void
2882qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
2883{
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002884 if (qlcnic_api_lock(adapter))
2885 return;
2886
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002887 QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
2888 QLCDB(adapter, DRV, "NPAR operational state set\n");
Anirban Chakraborty9f26f542010-06-01 11:33:09 +00002889
2890 qlcnic_api_unlock(adapter);
2891}
2892
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002893static void
2894qlcnic_schedule_work(struct qlcnic_adapter *adapter,
2895 work_func_t func, int delay)
2896{
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00002897 if (test_bit(__QLCNIC_AER, &adapter->state))
2898 return;
2899
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002900 INIT_DELAYED_WORK(&adapter->fw_work, func);
2901 schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
2902}
2903
2904static void
2905qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
2906{
2907 while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
2908 msleep(10);
2909
2910 cancel_delayed_work_sync(&adapter->fw_work);
2911}
2912
2913static void
2914qlcnic_attach_work(struct work_struct *work)
2915{
2916 struct qlcnic_adapter *adapter = container_of(work,
2917 struct qlcnic_adapter, fw_work.work);
2918 struct net_device *netdev = adapter->netdev;
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002919 u32 npar_state;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002920
Amit Kumar Salechab18971d2010-08-25 04:03:04 +00002921 if (adapter->op_mode != QLCNIC_MGMT_FUNC) {
2922 npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
2923 if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
2924 qlcnic_clr_all_drv_state(adapter, 0);
2925 else if (npar_state != QLCNIC_DEV_NPAR_OPER)
2926 qlcnic_schedule_work(adapter, qlcnic_attach_work,
2927 FW_POLL_DELAY);
2928 else
2929 goto attach;
2930 QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n");
2931 return;
2932 }
2933attach:
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002934 if (netif_running(netdev)) {
Amit Kumar Salecha52486a32010-06-22 03:19:02 +00002935 if (qlcnic_up(adapter, netdev))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002936 goto done;
2937
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002938 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2939 }
2940
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002941done:
Amit Kumar Salecha34ce3622010-04-01 19:01:34 +00002942 netif_device_attach(netdev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002943 adapter->fw_fail_cnt = 0;
2944 clear_bit(__QLCNIC_RESETTING, &adapter->state);
Amit Kumar Salecha1b95a832010-02-01 05:24:56 +00002945
2946 if (!qlcnic_clr_drv_state(adapter))
2947 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2948 FW_POLL_DELAY);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002949}
2950
2951static int
2952qlcnic_check_health(struct qlcnic_adapter *adapter)
2953{
Sony Chacko4e708122010-08-31 17:17:44 +00002954 u32 state = 0, heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002955 struct net_device *netdev = adapter->netdev;
2956
2957 if (qlcnic_check_temp(adapter))
2958 goto detach;
2959
Amit Kumar Salecha2372a5f2010-05-13 03:07:42 +00002960 if (adapter->need_fw_reset)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002961 qlcnic_dev_request_reset(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002962
2963 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002964 if (state == QLCNIC_DEV_NEED_RESET ||
2965 state == QLCNIC_DEV_NEED_QUISCENT) {
2966 qlcnic_set_npar_non_operational(adapter);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002967 adapter->need_fw_reset = 1;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00002968 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002969
Sony Chacko4e708122010-08-31 17:17:44 +00002970 heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
2971 if (heartbeat != adapter->heartbeat) {
2972 adapter->heartbeat = heartbeat;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002973 adapter->fw_fail_cnt = 0;
2974 if (adapter->need_fw_reset)
2975 goto detach;
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002976
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002977 if (adapter->reset_context &&
2978 auto_fw_reset == AUTO_FW_RESET_ENABLED) {
Amit Kumar Salecha68bf1c62010-06-22 03:19:03 +00002979 qlcnic_reset_hw_context(adapter);
2980 adapter->netdev->trans_start = jiffies;
2981 }
2982
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002983 return 0;
2984 }
2985
2986 if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
2987 return 0;
2988
2989 qlcnic_dev_request_reset(adapter);
2990
Amit Kumar Salecha0df170b2010-07-13 20:33:32 +00002991 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED))
2992 clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00002993
2994 dev_info(&netdev->dev, "firmware hang detected\n");
2995
2996detach:
2997 adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
2998 QLCNIC_DEV_NEED_RESET;
2999
3000 if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00003001 !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) {
3002
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003003 qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
Amit Kumar Salecha65b5b422010-04-01 19:01:33 +00003004 QLCDB(adapter, DRV, "fw recovery scheduled.\n");
3005 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003006
3007 return 1;
3008}
3009
3010static void
3011qlcnic_fw_poll_work(struct work_struct *work)
3012{
3013 struct qlcnic_adapter *adapter = container_of(work,
3014 struct qlcnic_adapter, fw_work.work);
3015
3016 if (test_bit(__QLCNIC_RESETTING, &adapter->state))
3017 goto reschedule;
3018
3019
3020 if (qlcnic_check_health(adapter))
3021 return;
3022
Amit Kumar Salechab5e54922010-08-31 17:17:51 +00003023 if (adapter->fhash.fnum)
3024 qlcnic_prune_lb_filters(adapter);
3025
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003026reschedule:
3027 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
3028}
3029
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003030static int qlcnic_is_first_func(struct pci_dev *pdev)
3031{
3032 struct pci_dev *oth_pdev;
3033 int val = pdev->devfn;
3034
3035 while (val-- > 0) {
3036 oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
3037 (pdev->bus), pdev->bus->number,
3038 PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003039 if (!oth_pdev)
3040 continue;
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003041
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003042 if (oth_pdev->current_state != PCI_D3cold) {
3043 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003044 return 0;
Amit Kumar Salechabfc978f2010-07-18 14:51:59 -07003045 }
3046 pci_dev_put(oth_pdev);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003047 }
3048 return 1;
3049}
3050
3051static int qlcnic_attach_func(struct pci_dev *pdev)
3052{
3053 int err, first_func;
3054 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3055 struct net_device *netdev = adapter->netdev;
3056
3057 pdev->error_state = pci_channel_io_normal;
3058
3059 err = pci_enable_device(pdev);
3060 if (err)
3061 return err;
3062
3063 pci_set_power_state(pdev, PCI_D0);
3064 pci_set_master(pdev);
3065 pci_restore_state(pdev);
3066
3067 first_func = qlcnic_is_first_func(pdev);
3068
3069 if (qlcnic_api_lock(adapter))
3070 return -EINVAL;
3071
Amit Kumar Salecha933fce122010-08-17 00:34:19 +00003072 if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003073 adapter->need_fw_reset = 1;
3074 set_bit(__QLCNIC_START_FW, &adapter->state);
3075 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
3076 QLCDB(adapter, DRV, "Restarting fw\n");
3077 }
3078 qlcnic_api_unlock(adapter);
3079
3080 err = adapter->nic_ops->start_firmware(adapter);
3081 if (err)
3082 return err;
3083
3084 qlcnic_clr_drv_state(adapter);
3085 qlcnic_setup_intr(adapter);
3086
3087 if (netif_running(netdev)) {
3088 err = qlcnic_attach(adapter);
3089 if (err) {
Amit Kumar Salecha21854f02010-08-19 05:08:29 +00003090 qlcnic_clr_all_drv_state(adapter, 1);
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00003091 clear_bit(__QLCNIC_AER, &adapter->state);
3092 netif_device_attach(netdev);
3093 return err;
3094 }
3095
3096 err = qlcnic_up(adapter, netdev);
3097 if (err)
3098 goto done;
3099
3100 qlcnic_config_indev_addr(netdev, NETDEV_UP);
3101 }
3102 done:
3103 netif_device_attach(netdev);
3104 return err;
3105}
3106
3107static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
3108 pci_channel_state_t state)
3109{
3110 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3111 struct net_device *netdev = adapter->netdev;
3112
3113 if (state == pci_channel_io_perm_failure)
3114 return PCI_ERS_RESULT_DISCONNECT;
3115
3116 if (state == pci_channel_io_normal)
3117 return PCI_ERS_RESULT_RECOVERED;
3118
3119 set_bit(__QLCNIC_AER, &adapter->state);
3120 netif_device_detach(netdev);
3121
3122 cancel_delayed_work_sync(&adapter->fw_work);
3123
3124 if (netif_running(netdev))
3125 qlcnic_down(adapter, netdev);
3126
3127 qlcnic_detach(adapter);
3128 qlcnic_teardown_intr(adapter);
3129
3130 clear_bit(__QLCNIC_RESETTING, &adapter->state);
3131
3132 pci_save_state(pdev);
3133 pci_disable_device(pdev);
3134
3135 return PCI_ERS_RESULT_NEED_RESET;
3136}
3137
3138static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
3139{
3140 return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
3141 PCI_ERS_RESULT_RECOVERED;
3142}
3143
3144static void qlcnic_io_resume(struct pci_dev *pdev)
3145{
3146 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
3147
3148 pci_cleanup_aer_uncorrect_error_status(pdev);
3149
3150 if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
3151 test_and_clear_bit(__QLCNIC_AER, &adapter->state))
3152 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
3153 FW_POLL_DELAY);
3154}
3155
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003156static int
3157qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
3158{
3159 int err;
3160
3161 err = qlcnic_can_start_firmware(adapter);
3162 if (err)
3163 return err;
3164
Amit Kumar Salecha78f84e12010-08-19 05:08:28 +00003165 err = qlcnic_check_npar_opertional(adapter);
3166 if (err)
3167 return err;
Amit Kumar Salecha3c4b23b2010-08-17 00:34:20 +00003168
Rajesh Borundia174240a2010-08-31 17:17:47 +00003169 err = qlcnic_initialize_nic(adapter);
3170 if (err)
3171 return err;
3172
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003173 qlcnic_check_options(adapter);
3174
Rajesh Borundia73733732010-08-31 17:17:50 +00003175 err = qlcnic_set_eswitch_port_config(adapter);
3176 if (err)
3177 return err;
3178
Anirban Chakraborty87eb7432010-06-03 07:50:56 +00003179 adapter->need_fw_reset = 0;
3180
3181 return err;
3182}
3183
3184static int
3185qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
3186{
3187 return -EOPNOTSUPP;
3188}
3189
3190static int
3191qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
3192{
3193 return -EOPNOTSUPP;
3194}
3195
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003196static ssize_t
3197qlcnic_store_bridged_mode(struct device *dev,
3198 struct device_attribute *attr, const char *buf, size_t len)
3199{
3200 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3201 unsigned long new;
3202 int ret = -EINVAL;
3203
3204 if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
3205 goto err_out;
3206
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00003207 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003208 goto err_out;
3209
3210 if (strict_strtoul(buf, 2, &new))
3211 goto err_out;
3212
Anirban Chakraborty2e9d7222010-06-01 11:28:51 +00003213 if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003214 ret = len;
3215
3216err_out:
3217 return ret;
3218}
3219
3220static ssize_t
3221qlcnic_show_bridged_mode(struct device *dev,
3222 struct device_attribute *attr, char *buf)
3223{
3224 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3225 int bridged_mode = 0;
3226
3227 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3228 bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
3229
3230 return sprintf(buf, "%d\n", bridged_mode);
3231}
3232
3233static struct device_attribute dev_attr_bridged_mode = {
3234 .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
3235 .show = qlcnic_show_bridged_mode,
3236 .store = qlcnic_store_bridged_mode,
3237};
3238
3239static ssize_t
3240qlcnic_store_diag_mode(struct device *dev,
3241 struct device_attribute *attr, const char *buf, size_t len)
3242{
3243 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3244 unsigned long new;
3245
3246 if (strict_strtoul(buf, 2, &new))
3247 return -EINVAL;
3248
3249 if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
3250 adapter->flags ^= QLCNIC_DIAG_ENABLED;
3251
3252 return len;
3253}
3254
3255static ssize_t
3256qlcnic_show_diag_mode(struct device *dev,
3257 struct device_attribute *attr, char *buf)
3258{
3259 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3260
3261 return sprintf(buf, "%d\n",
3262 !!(adapter->flags & QLCNIC_DIAG_ENABLED));
3263}
3264
3265static struct device_attribute dev_attr_diag_mode = {
3266 .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
3267 .show = qlcnic_show_diag_mode,
3268 .store = qlcnic_store_diag_mode,
3269};
3270
3271static int
3272qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
3273 loff_t offset, size_t size)
3274{
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003275 size_t crb_size = 4;
3276
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003277 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3278 return -EIO;
3279
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003280 if (offset < QLCNIC_PCI_CRBSPACE) {
3281 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
3282 QLCNIC_PCI_CAMQM_END))
3283 crb_size = 8;
3284 else
3285 return -EINVAL;
3286 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003287
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003288 if ((size != crb_size) || (offset & (crb_size-1)))
3289 return -EINVAL;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003290
3291 return 0;
3292}
3293
3294static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003295qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
3296 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003297 char *buf, loff_t offset, size_t size)
3298{
3299 struct device *dev = container_of(kobj, struct device, kobj);
3300 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3301 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003302 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003303 int ret;
3304
3305 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3306 if (ret != 0)
3307 return ret;
3308
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003309 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3310 qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
3311 memcpy(buf, &qmdata, size);
3312 } else {
3313 data = QLCRD32(adapter, offset);
3314 memcpy(buf, &data, size);
3315 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003316 return size;
3317}
3318
3319static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003320qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
3321 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003322 char *buf, loff_t offset, size_t size)
3323{
3324 struct device *dev = container_of(kobj, struct device, kobj);
3325 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3326 u32 data;
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003327 u64 qmdata;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003328 int ret;
3329
3330 ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
3331 if (ret != 0)
3332 return ret;
3333
Dhananjay Phadke897e8c72010-04-01 19:01:29 +00003334 if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
3335 memcpy(&qmdata, buf, size);
3336 qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
3337 } else {
3338 memcpy(&data, buf, size);
3339 QLCWR32(adapter, offset, data);
3340 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003341 return size;
3342}
3343
3344static int
3345qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
3346 loff_t offset, size_t size)
3347{
3348 if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
3349 return -EIO;
3350
3351 if ((size != 8) || (offset & 0x7))
3352 return -EIO;
3353
3354 return 0;
3355}
3356
3357static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003358qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
3359 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003360 char *buf, loff_t offset, size_t size)
3361{
3362 struct device *dev = container_of(kobj, struct device, kobj);
3363 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3364 u64 data;
3365 int ret;
3366
3367 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3368 if (ret != 0)
3369 return ret;
3370
3371 if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
3372 return -EIO;
3373
3374 memcpy(buf, &data, size);
3375
3376 return size;
3377}
3378
3379static ssize_t
Chris Wright2c3c8be2010-05-12 18:28:57 -07003380qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
3381 struct bin_attribute *attr,
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003382 char *buf, loff_t offset, size_t size)
3383{
3384 struct device *dev = container_of(kobj, struct device, kobj);
3385 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3386 u64 data;
3387 int ret;
3388
3389 ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
3390 if (ret != 0)
3391 return ret;
3392
3393 memcpy(&data, buf, size);
3394
3395 if (qlcnic_pci_mem_write_2M(adapter, offset, data))
3396 return -EIO;
3397
3398 return size;
3399}
3400
3401
3402static struct bin_attribute bin_attr_crb = {
3403 .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
3404 .size = 0,
3405 .read = qlcnic_sysfs_read_crb,
3406 .write = qlcnic_sysfs_write_crb,
3407};
3408
3409static struct bin_attribute bin_attr_mem = {
3410 .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
3411 .size = 0,
3412 .read = qlcnic_sysfs_read_mem,
3413 .write = qlcnic_sysfs_write_mem,
3414};
3415
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003416static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003417validate_pm_config(struct qlcnic_adapter *adapter,
3418 struct qlcnic_pm_func_cfg *pm_cfg, int count)
3419{
3420
3421 u8 src_pci_func, s_esw_id, d_esw_id;
3422 u8 dest_pci_func;
3423 int i;
3424
3425 for (i = 0; i < count; i++) {
3426 src_pci_func = pm_cfg[i].pci_func;
3427 dest_pci_func = pm_cfg[i].dest_npar;
3428 if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
3429 || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
3430 return QL_STATUS_INVALID_PARAM;
3431
3432 if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
3433 return QL_STATUS_INVALID_PARAM;
3434
3435 if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
3436 return QL_STATUS_INVALID_PARAM;
3437
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003438 s_esw_id = adapter->npars[src_pci_func].phy_port;
3439 d_esw_id = adapter->npars[dest_pci_func].phy_port;
3440
3441 if (s_esw_id != d_esw_id)
3442 return QL_STATUS_INVALID_PARAM;
3443
3444 }
3445 return 0;
3446
3447}
3448
3449static ssize_t
3450qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
3451 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3452{
3453 struct device *dev = container_of(kobj, struct device, kobj);
3454 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3455 struct qlcnic_pm_func_cfg *pm_cfg;
3456 u32 id, action, pci_func;
3457 int count, rem, i, ret;
3458
3459 count = size / sizeof(struct qlcnic_pm_func_cfg);
3460 rem = size % sizeof(struct qlcnic_pm_func_cfg);
3461 if (rem)
3462 return QL_STATUS_INVALID_PARAM;
3463
3464 pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
3465
3466 ret = validate_pm_config(adapter, pm_cfg, count);
3467 if (ret)
3468 return ret;
3469 for (i = 0; i < count; i++) {
3470 pci_func = pm_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003471 action = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003472 id = adapter->npars[pci_func].phy_port;
3473 ret = qlcnic_config_port_mirroring(adapter, id,
3474 action, pci_func);
3475 if (ret)
3476 return ret;
3477 }
3478
3479 for (i = 0; i < count; i++) {
3480 pci_func = pm_cfg[i].pci_func;
3481 id = adapter->npars[pci_func].phy_port;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003482 adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003483 adapter->npars[pci_func].dest_npar = id;
3484 }
3485 return size;
3486}
3487
3488static ssize_t
3489qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
3490 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3491{
3492 struct device *dev = container_of(kobj, struct device, kobj);
3493 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3494 struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
3495 int i;
3496
3497 if (size != sizeof(pm_cfg))
3498 return QL_STATUS_INVALID_PARAM;
3499
3500 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3501 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3502 continue;
3503 pm_cfg[i].action = adapter->npars[i].enable_pm;
3504 pm_cfg[i].dest_npar = 0;
3505 pm_cfg[i].pci_func = i;
3506 }
3507 memcpy(buf, &pm_cfg, size);
3508
3509 return size;
3510}
3511
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003512static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003513validate_esw_config(struct qlcnic_adapter *adapter,
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003514 struct qlcnic_esw_func_cfg *esw_cfg, int count)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003515{
Rajesh Borundia7613c872010-08-31 17:17:48 +00003516 u32 op_mode;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003517 u8 pci_func;
3518 int i;
Rajesh Borundia7613c872010-08-31 17:17:48 +00003519
3520 op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE);
3521
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003522 for (i = 0; i < count; i++) {
3523 pci_func = esw_cfg[i].pci_func;
3524 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3525 return QL_STATUS_INVALID_PARAM;
3526
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003527 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3528 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003529 return QL_STATUS_INVALID_PARAM;
3530
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003531 switch (esw_cfg[i].op_mode) {
3532 case QLCNIC_PORT_DEFAULTS:
Rajesh Borundia7613c872010-08-31 17:17:48 +00003533 if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
Rajesh Borundia73733732010-08-31 17:17:50 +00003534 QLCNIC_NON_PRIV_FUNC) {
Rajesh Borundia7613c872010-08-31 17:17:48 +00003535 esw_cfg[i].mac_anti_spoof = 0;
Rajesh Borundia73733732010-08-31 17:17:50 +00003536 esw_cfg[i].mac_override = 1;
3537 }
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003538 break;
3539 case QLCNIC_ADD_VLAN:
3540 if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
3541 return QL_STATUS_INVALID_PARAM;
3542 if (!esw_cfg[i].op_type)
3543 return QL_STATUS_INVALID_PARAM;
3544 break;
3545 case QLCNIC_DEL_VLAN:
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003546 if (!esw_cfg[i].op_type)
3547 return QL_STATUS_INVALID_PARAM;
3548 break;
3549 default:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003550 return QL_STATUS_INVALID_PARAM;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003551 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003552 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003553 return 0;
3554}
3555
3556static ssize_t
3557qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
3558 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3559{
3560 struct device *dev = container_of(kobj, struct device, kobj);
3561 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3562 struct qlcnic_esw_func_cfg *esw_cfg;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003563 struct qlcnic_npar_info *npar;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003564 int count, rem, i, ret;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003565 u8 pci_func, op_mode = 0;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003566
3567 count = size / sizeof(struct qlcnic_esw_func_cfg);
3568 rem = size % sizeof(struct qlcnic_esw_func_cfg);
3569 if (rem)
3570 return QL_STATUS_INVALID_PARAM;
3571
3572 esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
3573 ret = validate_esw_config(adapter, esw_cfg, count);
3574 if (ret)
3575 return ret;
3576
3577 for (i = 0; i < count; i++) {
Rajesh Borundia0325d692010-08-19 05:08:26 +00003578 if (adapter->op_mode == QLCNIC_MGMT_FUNC)
3579 if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
3580 return QL_STATUS_INVALID_PARAM;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003581
3582 if (adapter->ahw.pci_func != esw_cfg[i].pci_func)
3583 continue;
3584
3585 op_mode = esw_cfg[i].op_mode;
3586 qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
3587 esw_cfg[i].op_mode = op_mode;
3588 esw_cfg[i].pci_func = adapter->ahw.pci_func;
3589
3590 switch (esw_cfg[i].op_mode) {
3591 case QLCNIC_PORT_DEFAULTS:
3592 qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
3593 break;
Amit Kumar Salecha8cf61f82010-08-25 04:03:03 +00003594 case QLCNIC_ADD_VLAN:
3595 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3596 break;
3597 case QLCNIC_DEL_VLAN:
3598 esw_cfg[i].vlan_id = 0;
3599 qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
3600 break;
Rajesh Borundia0325d692010-08-19 05:08:26 +00003601 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003602 }
3603
Rajesh Borundia0325d692010-08-19 05:08:26 +00003604 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
3605 goto out;
Rajesh Borundiae9a47702010-08-25 04:03:02 +00003606
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003607 for (i = 0; i < count; i++) {
3608 pci_func = esw_cfg[i].pci_func;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003609 npar = &adapter->npars[pci_func];
3610 switch (esw_cfg[i].op_mode) {
3611 case QLCNIC_PORT_DEFAULTS:
3612 npar->promisc_mode = esw_cfg[i].promisc_mode;
Rajesh Borundia73733732010-08-31 17:17:50 +00003613 npar->mac_override = esw_cfg[i].mac_override;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003614 npar->offload_flags = esw_cfg[i].offload_flags;
3615 npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
3616 npar->discard_tagged = esw_cfg[i].discard_tagged;
3617 break;
3618 case QLCNIC_ADD_VLAN:
3619 npar->pvid = esw_cfg[i].vlan_id;
3620 break;
3621 case QLCNIC_DEL_VLAN:
3622 npar->pvid = 0;
3623 break;
3624 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003625 }
Rajesh Borundia0325d692010-08-19 05:08:26 +00003626out:
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003627 return size;
3628}
3629
3630static ssize_t
3631qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
3632 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3633{
3634 struct device *dev = container_of(kobj, struct device, kobj);
3635 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3636 struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003637 u8 i;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003638
3639 if (size != sizeof(esw_cfg))
3640 return QL_STATUS_INVALID_PARAM;
3641
3642 for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
3643 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3644 continue;
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003645 esw_cfg[i].pci_func = i;
3646 if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
3647 return QL_STATUS_INVALID_PARAM;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003648 }
3649 memcpy(buf, &esw_cfg, size);
3650
3651 return size;
3652}
3653
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003654static int
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003655validate_npar_config(struct qlcnic_adapter *adapter,
3656 struct qlcnic_npar_func_cfg *np_cfg, int count)
3657{
3658 u8 pci_func, i;
3659
3660 for (i = 0; i < count; i++) {
3661 pci_func = np_cfg[i].pci_func;
3662 if (pci_func >= QLCNIC_MAX_PCI_FUNC)
3663 return QL_STATUS_INVALID_PARAM;
3664
3665 if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
3666 return QL_STATUS_INVALID_PARAM;
3667
3668 if (!IS_VALID_BW(np_cfg[i].min_bw)
3669 || !IS_VALID_BW(np_cfg[i].max_bw)
3670 || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
3671 || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
3672 return QL_STATUS_INVALID_PARAM;
3673 }
3674 return 0;
3675}
3676
3677static ssize_t
3678qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
3679 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3680{
3681 struct device *dev = container_of(kobj, struct device, kobj);
3682 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3683 struct qlcnic_info nic_info;
3684 struct qlcnic_npar_func_cfg *np_cfg;
3685 int i, count, rem, ret;
3686 u8 pci_func;
3687
3688 count = size / sizeof(struct qlcnic_npar_func_cfg);
3689 rem = size % sizeof(struct qlcnic_npar_func_cfg);
3690 if (rem)
3691 return QL_STATUS_INVALID_PARAM;
3692
3693 np_cfg = (struct qlcnic_npar_func_cfg *) buf;
3694 ret = validate_npar_config(adapter, np_cfg, count);
3695 if (ret)
3696 return ret;
3697
3698 for (i = 0; i < count ; i++) {
3699 pci_func = np_cfg[i].pci_func;
3700 ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
3701 if (ret)
3702 return ret;
3703 nic_info.pci_func = pci_func;
3704 nic_info.min_tx_bw = np_cfg[i].min_bw;
3705 nic_info.max_tx_bw = np_cfg[i].max_bw;
3706 ret = qlcnic_set_nic_info(adapter, &nic_info);
3707 if (ret)
3708 return ret;
Anirban Chakrabortycea89752010-07-13 20:33:35 +00003709 adapter->npars[i].min_bw = nic_info.min_tx_bw;
3710 adapter->npars[i].max_bw = nic_info.max_tx_bw;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003711 }
3712
3713 return size;
3714
3715}
3716static ssize_t
3717qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
3718 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3719{
3720 struct device *dev = container_of(kobj, struct device, kobj);
3721 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3722 struct qlcnic_info nic_info;
3723 struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
3724 int i, ret;
3725
3726 if (size != sizeof(np_cfg))
3727 return QL_STATUS_INVALID_PARAM;
3728
3729 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3730 if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
3731 continue;
3732 ret = qlcnic_get_nic_info(adapter, &nic_info, i);
3733 if (ret)
3734 return ret;
3735
3736 np_cfg[i].pci_func = i;
3737 np_cfg[i].op_mode = nic_info.op_mode;
3738 np_cfg[i].port_num = nic_info.phys_port;
3739 np_cfg[i].fw_capab = nic_info.capabilities;
3740 np_cfg[i].min_bw = nic_info.min_tx_bw ;
3741 np_cfg[i].max_bw = nic_info.max_tx_bw;
3742 np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
3743 np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
3744 }
3745 memcpy(buf, &np_cfg, size);
3746 return size;
3747}
3748
3749static ssize_t
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003750qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
3751 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3752{
3753 struct device *dev = container_of(kobj, struct device, kobj);
3754 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3755 struct qlcnic_esw_statistics port_stats;
3756 int ret;
3757
3758 if (size != sizeof(struct qlcnic_esw_statistics))
3759 return QL_STATUS_INVALID_PARAM;
3760
3761 if (offset >= QLCNIC_MAX_PCI_FUNC)
3762 return QL_STATUS_INVALID_PARAM;
3763
3764 memset(&port_stats, 0, size);
3765 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3766 &port_stats.rx);
3767 if (ret)
3768 return ret;
3769
3770 ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3771 &port_stats.tx);
3772 if (ret)
3773 return ret;
3774
3775 memcpy(buf, &port_stats, size);
3776 return size;
3777}
3778
3779static ssize_t
3780qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
3781 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3782{
3783 struct device *dev = container_of(kobj, struct device, kobj);
3784 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3785 struct qlcnic_esw_statistics esw_stats;
3786 int ret;
3787
3788 if (size != sizeof(struct qlcnic_esw_statistics))
3789 return QL_STATUS_INVALID_PARAM;
3790
3791 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3792 return QL_STATUS_INVALID_PARAM;
3793
3794 memset(&esw_stats, 0, size);
3795 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
3796 &esw_stats.rx);
3797 if (ret)
3798 return ret;
3799
3800 ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
3801 &esw_stats.tx);
3802 if (ret)
3803 return ret;
3804
3805 memcpy(buf, &esw_stats, size);
3806 return size;
3807}
3808
3809static ssize_t
3810qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
3811 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3812{
3813 struct device *dev = container_of(kobj, struct device, kobj);
3814 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3815 int ret;
3816
3817 if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
3818 return QL_STATUS_INVALID_PARAM;
3819
3820 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3821 QLCNIC_QUERY_RX_COUNTER);
3822 if (ret)
3823 return ret;
3824
3825 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
3826 QLCNIC_QUERY_TX_COUNTER);
3827 if (ret)
3828 return ret;
3829
3830 return size;
3831}
3832
3833static ssize_t
3834qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
3835 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3836{
3837
3838 struct device *dev = container_of(kobj, struct device, kobj);
3839 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3840 int ret;
3841
3842 if (offset >= QLCNIC_MAX_PCI_FUNC)
3843 return QL_STATUS_INVALID_PARAM;
3844
3845 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3846 QLCNIC_QUERY_RX_COUNTER);
3847 if (ret)
3848 return ret;
3849
3850 ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
3851 QLCNIC_QUERY_TX_COUNTER);
3852 if (ret)
3853 return ret;
3854
3855 return size;
3856}
3857
3858static ssize_t
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003859qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
3860 struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
3861{
3862 struct device *dev = container_of(kobj, struct device, kobj);
3863 struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
3864 struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
Dan Carpentere88db3b2010-08-09 21:49:36 +00003865 struct qlcnic_pci_info *pci_info;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003866 int i, ret;
3867
3868 if (size != sizeof(pci_cfg))
3869 return QL_STATUS_INVALID_PARAM;
3870
Dan Carpentere88db3b2010-08-09 21:49:36 +00003871 pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
3872 if (!pci_info)
3873 return -ENOMEM;
3874
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003875 ret = qlcnic_get_pci_info(adapter, pci_info);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003876 if (ret) {
3877 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003878 return ret;
Dan Carpentere88db3b2010-08-09 21:49:36 +00003879 }
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003880
3881 for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
3882 pci_cfg[i].pci_func = pci_info[i].id;
3883 pci_cfg[i].func_type = pci_info[i].type;
3884 pci_cfg[i].port_num = pci_info[i].default_port;
3885 pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
3886 pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
3887 memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
3888 }
3889 memcpy(buf, &pci_cfg, size);
Dan Carpentere88db3b2010-08-09 21:49:36 +00003890 kfree(pci_info);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003891 return size;
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003892}
3893static struct bin_attribute bin_attr_npar_config = {
3894 .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
3895 .size = 0,
3896 .read = qlcnic_sysfs_read_npar_config,
3897 .write = qlcnic_sysfs_write_npar_config,
3898};
3899
3900static struct bin_attribute bin_attr_pci_config = {
3901 .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
3902 .size = 0,
3903 .read = qlcnic_sysfs_read_pci_config,
3904 .write = NULL,
3905};
3906
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003907static struct bin_attribute bin_attr_port_stats = {
3908 .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
3909 .size = 0,
3910 .read = qlcnic_sysfs_get_port_stats,
3911 .write = qlcnic_sysfs_clear_port_stats,
3912};
3913
3914static struct bin_attribute bin_attr_esw_stats = {
3915 .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
3916 .size = 0,
3917 .read = qlcnic_sysfs_get_esw_stats,
3918 .write = qlcnic_sysfs_clear_esw_stats,
3919};
3920
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003921static struct bin_attribute bin_attr_esw_config = {
3922 .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
3923 .size = 0,
3924 .read = qlcnic_sysfs_read_esw_config,
3925 .write = qlcnic_sysfs_write_esw_config,
3926};
3927
3928static struct bin_attribute bin_attr_pm_config = {
3929 .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
3930 .size = 0,
3931 .read = qlcnic_sysfs_read_pm_config,
3932 .write = qlcnic_sysfs_write_pm_config,
3933};
3934
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003935static void
3936qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
3937{
3938 struct device *dev = &adapter->pdev->dev;
3939
3940 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3941 if (device_create_file(dev, &dev_attr_bridged_mode))
3942 dev_warn(dev,
3943 "failed to create bridged_mode sysfs entry\n");
3944}
3945
3946static void
3947qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
3948{
3949 struct device *dev = &adapter->pdev->dev;
3950
3951 if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
3952 device_remove_file(dev, &dev_attr_bridged_mode);
3953}
3954
3955static void
3956qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
3957{
3958 struct device *dev = &adapter->pdev->dev;
3959
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003960 if (device_create_bin_file(dev, &bin_attr_port_stats))
3961 dev_info(dev, "failed to create port stats sysfs entry");
3962
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003963 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3964 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003965 if (device_create_file(dev, &dev_attr_diag_mode))
3966 dev_info(dev, "failed to create diag_mode sysfs entry\n");
3967 if (device_create_bin_file(dev, &bin_attr_crb))
3968 dev_info(dev, "failed to create crb sysfs entry\n");
3969 if (device_create_bin_file(dev, &bin_attr_mem))
3970 dev_info(dev, "failed to create mem sysfs entry\n");
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003971 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
3972 return;
3973 if (device_create_bin_file(dev, &bin_attr_esw_config))
3974 dev_info(dev, "failed to create esw config sysfs entry");
3975 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003976 return;
3977 if (device_create_bin_file(dev, &bin_attr_pci_config))
3978 dev_info(dev, "failed to create pci config sysfs entry");
3979 if (device_create_bin_file(dev, &bin_attr_npar_config))
3980 dev_info(dev, "failed to create npar config sysfs entry");
Rajesh K Borundia346fe762010-06-29 08:01:20 +00003981 if (device_create_bin_file(dev, &bin_attr_pm_config))
3982 dev_info(dev, "failed to create pm config sysfs entry");
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003983 if (device_create_bin_file(dev, &bin_attr_esw_stats))
3984 dev_info(dev, "failed to create eswitch stats sysfs entry");
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003985}
3986
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003987static void
3988qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
3989{
3990 struct device *dev = &adapter->pdev->dev;
3991
Amit Kumar Salechab6021212010-08-17 00:34:22 +00003992 device_remove_bin_file(dev, &bin_attr_port_stats);
3993
Anirban Chakraborty132ff002010-07-09 13:15:05 +00003994 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
3995 return;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00003996 device_remove_file(dev, &dev_attr_diag_mode);
3997 device_remove_bin_file(dev, &bin_attr_crb);
3998 device_remove_bin_file(dev, &bin_attr_mem);
Rajesh Borundia4e8acb02010-08-19 05:08:25 +00003999 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
4000 return;
4001 device_remove_bin_file(dev, &bin_attr_esw_config);
4002 if (adapter->op_mode != QLCNIC_MGMT_FUNC)
Rajesh K Borundia346fe762010-06-29 08:01:20 +00004003 return;
4004 device_remove_bin_file(dev, &bin_attr_pci_config);
4005 device_remove_bin_file(dev, &bin_attr_npar_config);
Rajesh K Borundia346fe762010-06-29 08:01:20 +00004006 device_remove_bin_file(dev, &bin_attr_pm_config);
Amit Kumar Salechab6021212010-08-17 00:34:22 +00004007 device_remove_bin_file(dev, &bin_attr_esw_stats);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004008}
4009
4010#ifdef CONFIG_INET
4011
4012#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
4013
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004014static void
4015qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
4016{
4017 struct in_device *indev;
4018 struct qlcnic_adapter *adapter = netdev_priv(dev);
4019
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004020 indev = in_dev_get(dev);
4021 if (!indev)
4022 return;
4023
4024 for_ifa(indev) {
4025 switch (event) {
4026 case NETDEV_UP:
4027 qlcnic_config_ipaddr(adapter,
4028 ifa->ifa_address, QLCNIC_IP_UP);
4029 break;
4030 case NETDEV_DOWN:
4031 qlcnic_config_ipaddr(adapter,
4032 ifa->ifa_address, QLCNIC_IP_DOWN);
4033 break;
4034 default:
4035 break;
4036 }
4037 } endfor_ifa(indev);
4038
4039 in_dev_put(indev);
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004040}
4041
4042static int qlcnic_netdev_event(struct notifier_block *this,
4043 unsigned long event, void *ptr)
4044{
4045 struct qlcnic_adapter *adapter;
4046 struct net_device *dev = (struct net_device *)ptr;
4047
4048recheck:
4049 if (dev == NULL)
4050 goto done;
4051
4052 if (dev->priv_flags & IFF_802_1Q_VLAN) {
4053 dev = vlan_dev_real_dev(dev);
4054 goto recheck;
4055 }
4056
4057 if (!is_qlcnic_netdev(dev))
4058 goto done;
4059
4060 adapter = netdev_priv(dev);
4061
4062 if (!adapter)
4063 goto done;
4064
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00004065 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004066 goto done;
4067
4068 qlcnic_config_indev_addr(dev, event);
4069done:
4070 return NOTIFY_DONE;
4071}
4072
4073static int
4074qlcnic_inetaddr_event(struct notifier_block *this,
4075 unsigned long event, void *ptr)
4076{
4077 struct qlcnic_adapter *adapter;
4078 struct net_device *dev;
4079
4080 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
4081
4082 dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
4083
4084recheck:
4085 if (dev == NULL || !netif_running(dev))
4086 goto done;
4087
4088 if (dev->priv_flags & IFF_802_1Q_VLAN) {
4089 dev = vlan_dev_real_dev(dev);
4090 goto recheck;
4091 }
4092
4093 if (!is_qlcnic_netdev(dev))
4094 goto done;
4095
4096 adapter = netdev_priv(dev);
4097
Amit Kumar Salecha251a84c2010-05-13 03:07:46 +00004098 if (!adapter)
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004099 goto done;
4100
Amit Kumar Salecha8a15ad12010-06-22 03:19:01 +00004101 if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004102 goto done;
4103
4104 switch (event) {
4105 case NETDEV_UP:
4106 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
4107 break;
4108 case NETDEV_DOWN:
4109 qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
4110 break;
4111 default:
4112 break;
4113 }
4114
4115done:
4116 return NOTIFY_DONE;
4117}
4118
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004119static struct notifier_block qlcnic_netdev_cb = {
4120 .notifier_call = qlcnic_netdev_event,
4121};
4122
4123static struct notifier_block qlcnic_inetaddr_cb = {
4124 .notifier_call = qlcnic_inetaddr_event,
4125};
4126#else
4127static void
4128qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
4129{ }
4130#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00004131static struct pci_error_handlers qlcnic_err_handler = {
4132 .error_detected = qlcnic_io_error_detected,
4133 .slot_reset = qlcnic_io_slot_reset,
4134 .resume = qlcnic_io_resume,
4135};
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004136
4137static struct pci_driver qlcnic_driver = {
4138 .name = qlcnic_driver_name,
4139 .id_table = qlcnic_pci_tbl,
4140 .probe = qlcnic_probe,
4141 .remove = __devexit_p(qlcnic_remove),
4142#ifdef CONFIG_PM
4143 .suspend = qlcnic_suspend,
4144 .resume = qlcnic_resume,
4145#endif
Sucheta Chakraborty451724c2010-07-13 20:33:34 +00004146 .shutdown = qlcnic_shutdown,
4147 .err_handler = &qlcnic_err_handler
4148
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004149};
4150
4151static int __init qlcnic_init_module(void)
4152{
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004153 int ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004154
4155 printk(KERN_INFO "%s\n", qlcnic_driver_string);
4156
4157#ifdef CONFIG_INET
4158 register_netdevice_notifier(&qlcnic_netdev_cb);
4159 register_inetaddr_notifier(&qlcnic_inetaddr_cb);
4160#endif
4161
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004162 ret = pci_register_driver(&qlcnic_driver);
4163 if (ret) {
4164#ifdef CONFIG_INET
4165 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
4166 unregister_netdevice_notifier(&qlcnic_netdev_cb);
4167#endif
4168 }
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004169
Amit Kumar Salecha0cf3a142010-07-13 20:33:33 +00004170 return ret;
Amit Kumar Salechaaf19b492010-01-13 00:37:25 +00004171}
4172
4173module_init(qlcnic_init_module);
4174
4175static void __exit qlcnic_exit_module(void)
4176{
4177
4178 pci_unregister_driver(&qlcnic_driver);
4179
4180#ifdef CONFIG_INET
4181 unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
4182 unregister_netdevice_notifier(&qlcnic_netdev_cb);
4183#endif
4184}
4185
4186module_exit(qlcnic_exit_module);