162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic qlcnic NIC Driver
462306a36Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/vmalloc.h>
862306a36Sopenharmony_ci#include <linux/interrupt.h>
962306a36Sopenharmony_ci#include <linux/swab.h>
1062306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1162306a36Sopenharmony_ci#include <linux/if_vlan.h>
1262306a36Sopenharmony_ci#include <net/ip.h>
1362306a36Sopenharmony_ci#include <linux/ipv6.h>
1462306a36Sopenharmony_ci#include <linux/inetdevice.h>
1562306a36Sopenharmony_ci#include <linux/log2.h>
1662306a36Sopenharmony_ci#include <linux/pci.h>
1762306a36Sopenharmony_ci#include <net/vxlan.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "qlcnic.h"
2062306a36Sopenharmony_ci#include "qlcnic_sriov.h"
2162306a36Sopenharmony_ci#include "qlcnic_hw.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
2462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2562306a36Sopenharmony_ciMODULE_VERSION(QLCNIC_LINUX_VERSIONID);
2662306a36Sopenharmony_ciMODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cichar qlcnic_driver_name[] = "qlcnic";
2962306a36Sopenharmony_cistatic const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
3062306a36Sopenharmony_ci	"Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic int qlcnic_mac_learn;
3362306a36Sopenharmony_cimodule_param(qlcnic_mac_learn, int, 0444);
3462306a36Sopenharmony_ciMODULE_PARM_DESC(qlcnic_mac_learn,
3562306a36Sopenharmony_ci		 "Mac Filter (0=learning is disabled, 1=Driver learning is enabled, 2=FDB learning is enabled)");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciint qlcnic_use_msi = 1;
3862306a36Sopenharmony_ciMODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled)");
3962306a36Sopenharmony_cimodule_param_named(use_msi, qlcnic_use_msi, int, 0444);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciint qlcnic_use_msi_x = 1;
4262306a36Sopenharmony_ciMODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled)");
4362306a36Sopenharmony_cimodule_param_named(use_msi_x, qlcnic_use_msi_x, int, 0444);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciint qlcnic_auto_fw_reset = 1;
4662306a36Sopenharmony_ciMODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled)");
4762306a36Sopenharmony_cimodule_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciint qlcnic_load_fw_file;
5062306a36Sopenharmony_ciMODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file, 2=POST in fast mode, 3= POST in medium mode, 4=POST in slow mode)");
5162306a36Sopenharmony_cimodule_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
5462306a36Sopenharmony_cistatic void qlcnic_remove(struct pci_dev *pdev);
5562306a36Sopenharmony_cistatic int qlcnic_open(struct net_device *netdev);
5662306a36Sopenharmony_cistatic int qlcnic_close(struct net_device *netdev);
5762306a36Sopenharmony_cistatic void qlcnic_tx_timeout(struct net_device *netdev, unsigned int txqueue);
5862306a36Sopenharmony_cistatic void qlcnic_attach_work(struct work_struct *work);
5962306a36Sopenharmony_cistatic void qlcnic_fwinit_work(struct work_struct *work);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
6262306a36Sopenharmony_cistatic int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic irqreturn_t qlcnic_tmp_intr(int irq, void *data);
6562306a36Sopenharmony_cistatic irqreturn_t qlcnic_intr(int irq, void *data);
6662306a36Sopenharmony_cistatic irqreturn_t qlcnic_msi_intr(int irq, void *data);
6762306a36Sopenharmony_cistatic irqreturn_t qlcnic_msix_intr(int irq, void *data);
6862306a36Sopenharmony_cistatic irqreturn_t qlcnic_msix_tx_intr(int irq, void *data);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
7162306a36Sopenharmony_cistatic int qlcnic_start_firmware(struct qlcnic_adapter *);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
7462306a36Sopenharmony_cistatic void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
7562306a36Sopenharmony_cistatic int qlcnicvf_start_firmware(struct qlcnic_adapter *);
7662306a36Sopenharmony_cistatic int qlcnic_vlan_rx_add(struct net_device *, __be16, u16);
7762306a36Sopenharmony_cistatic int qlcnic_vlan_rx_del(struct net_device *, __be16, u16);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int qlcnic_82xx_setup_intr(struct qlcnic_adapter *);
8062306a36Sopenharmony_cistatic void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32);
8162306a36Sopenharmony_cistatic irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);
8262306a36Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *);
8362306a36Sopenharmony_cistatic int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);
8462306a36Sopenharmony_cistatic void qlcnic_82xx_io_resume(struct pci_dev *);
8562306a36Sopenharmony_cistatic void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
8662306a36Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *,
8762306a36Sopenharmony_ci						      pci_channel_state_t);
8862306a36Sopenharmony_cistatic u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X)
9362306a36Sopenharmony_ci		return ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX;
9462306a36Sopenharmony_ci	else
9562306a36Sopenharmony_ci		return 1;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/*  PCI Device ID Table  */
9962306a36Sopenharmony_ci#define ENTRY(device) \
10062306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
10162306a36Sopenharmony_ci	.class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic const struct pci_device_id qlcnic_pci_tbl[] = {
10462306a36Sopenharmony_ci	ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
10562306a36Sopenharmony_ci	ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
10662306a36Sopenharmony_ci	ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE834X),
10762306a36Sopenharmony_ci	ENTRY(PCI_DEVICE_ID_QLOGIC_QLE8830),
10862306a36Sopenharmony_ci	ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE8C30),
10962306a36Sopenharmony_ci	ENTRY(PCI_DEVICE_ID_QLOGIC_QLE844X),
11062306a36Sopenharmony_ci	ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE844X),
11162306a36Sopenharmony_ci	{0,}
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ciinline void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *tx_ring)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	writel(tx_ring->producer, tx_ring->crb_cmd_producer);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const u32 msi_tgt_status[8] = {
12362306a36Sopenharmony_ci	ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
12462306a36Sopenharmony_ci	ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
12562306a36Sopenharmony_ci	ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
12662306a36Sopenharmony_ci	ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic const u32 qlcnic_reg_tbl[] = {
13062306a36Sopenharmony_ci	0x1B20A8,	/* PEG_HALT_STAT1 */
13162306a36Sopenharmony_ci	0x1B20AC,	/* PEG_HALT_STAT2 */
13262306a36Sopenharmony_ci	0x1B20B0,	/* FW_HEARTBEAT */
13362306a36Sopenharmony_ci	0x1B2100,	/* LOCK ID */
13462306a36Sopenharmony_ci	0x1B2128,	/* FW_CAPABILITIES */
13562306a36Sopenharmony_ci	0x1B2138,	/* drv active */
13662306a36Sopenharmony_ci	0x1B2140,	/* dev state */
13762306a36Sopenharmony_ci	0x1B2144,	/* drv state */
13862306a36Sopenharmony_ci	0x1B2148,	/* drv scratch */
13962306a36Sopenharmony_ci	0x1B214C,	/* dev partition info */
14062306a36Sopenharmony_ci	0x1B2174,	/* drv idc ver */
14162306a36Sopenharmony_ci	0x1B2150,	/* fw version major */
14262306a36Sopenharmony_ci	0x1B2154,	/* fw version minor */
14362306a36Sopenharmony_ci	0x1B2158,	/* fw version sub */
14462306a36Sopenharmony_ci	0x1B219C,	/* npar state */
14562306a36Sopenharmony_ci	0x1B21FC,	/* FW_IMG_VALID */
14662306a36Sopenharmony_ci	0x1B2250,	/* CMD_PEG_STATE */
14762306a36Sopenharmony_ci	0x1B233C,	/* RCV_PEG_STATE */
14862306a36Sopenharmony_ci	0x1B23B4,	/* ASIC TEMP */
14962306a36Sopenharmony_ci	0x1B216C,	/* FW api */
15062306a36Sopenharmony_ci	0x1B2170,	/* drv op mode */
15162306a36Sopenharmony_ci	0x13C010,	/* flash lock */
15262306a36Sopenharmony_ci	0x13C014,	/* flash unlock */
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic const struct qlcnic_board_info qlcnic_boards[] = {
15662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
15762306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE844X,
15862306a36Sopenharmony_ci	  0x0,
15962306a36Sopenharmony_ci	  0x0,
16062306a36Sopenharmony_ci	  "8400 series 10GbE Converged Network Adapter (TCP/IP Networking)" },
16162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
16262306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
16362306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
16462306a36Sopenharmony_ci	  0x24e,
16562306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
16662306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
16762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
16862306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
16962306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
17062306a36Sopenharmony_ci	  0x243,
17162306a36Sopenharmony_ci	  "8300 Series Single Port 10GbE Converged Network Adapter "
17262306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
17362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
17462306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
17562306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
17662306a36Sopenharmony_ci	  0x24a,
17762306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
17862306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
17962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
18062306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
18162306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
18262306a36Sopenharmony_ci	  0x246,
18362306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
18462306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
18562306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
18662306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
18762306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
18862306a36Sopenharmony_ci	  0x252,
18962306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
19062306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
19162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
19262306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
19362306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
19462306a36Sopenharmony_ci	  0x26e,
19562306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
19662306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
19762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
19862306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
19962306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
20062306a36Sopenharmony_ci	  0x260,
20162306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
20262306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
20362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
20462306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
20562306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
20662306a36Sopenharmony_ci	  0x266,
20762306a36Sopenharmony_ci	  "8300 Series Single Port 10GbE Converged Network Adapter "
20862306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
20962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
21062306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
21162306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
21262306a36Sopenharmony_ci	  0x269,
21362306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
21462306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
21562306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
21662306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
21762306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
21862306a36Sopenharmony_ci	  0x271,
21962306a36Sopenharmony_ci	  "8300 Series Dual Port 10GbE Converged Network Adapter "
22062306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
22162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
22262306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE834X,
22362306a36Sopenharmony_ci	  0x0, 0x0, "8300 Series 1/10GbE Controller" },
22462306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
22562306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE8830,
22662306a36Sopenharmony_ci	  0x0,
22762306a36Sopenharmony_ci	  0x0,
22862306a36Sopenharmony_ci	  "8830 Series 1/10GbE Controller" },
22962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
23062306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
23162306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
23262306a36Sopenharmony_ci	  0x203,
23362306a36Sopenharmony_ci	  "8200 Series Single Port 10GbE Converged Network Adapter"
23462306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
23562306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
23662306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
23762306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
23862306a36Sopenharmony_ci	  0x207,
23962306a36Sopenharmony_ci	  "8200 Series Dual Port 10GbE Converged Network Adapter"
24062306a36Sopenharmony_ci	  "(TCP/IP Networking)" },
24162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
24262306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
24362306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
24462306a36Sopenharmony_ci	  0x20b,
24562306a36Sopenharmony_ci	  "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter" },
24662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
24762306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
24862306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
24962306a36Sopenharmony_ci	  0x20c,
25062306a36Sopenharmony_ci	  "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter" },
25162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
25262306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
25362306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
25462306a36Sopenharmony_ci	  0x20f,
25562306a36Sopenharmony_ci	  "3200 Series Single Port 10Gb Intelligent Ethernet Adapter" },
25662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
25762306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
25862306a36Sopenharmony_ci	  0x103c, 0x3733,
25962306a36Sopenharmony_ci	  "NC523SFP 10Gb 2-port Server Adapter" },
26062306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
26162306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
26262306a36Sopenharmony_ci	  0x103c, 0x3346,
26362306a36Sopenharmony_ci	  "CN1000Q Dual Port Converged Network Adapter" },
26462306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
26562306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
26662306a36Sopenharmony_ci	  PCI_VENDOR_ID_QLOGIC,
26762306a36Sopenharmony_ci	  0x210,
26862306a36Sopenharmony_ci	  "QME8242-k 10GbE Dual Port Mezzanine Card" },
26962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_QLOGIC,
27062306a36Sopenharmony_ci	  PCI_DEVICE_ID_QLOGIC_QLE824X,
27162306a36Sopenharmony_ci	  0x0, 0x0, "cLOM8214 1/10GbE Controller" },
27262306a36Sopenharmony_ci};
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic const
27762306a36Sopenharmony_cistruct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ciint qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	int size = sizeof(struct qlcnic_host_sds_ring) * count;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return recv_ctx->sds_rings == NULL;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_civoid qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	kfree(recv_ctx->sds_rings);
29162306a36Sopenharmony_ci	recv_ctx->sds_rings = NULL;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ciint qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
29762306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
29862306a36Sopenharmony_ci	u8 mac_addr[ETH_ALEN];
29962306a36Sopenharmony_ci	int ret;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	ret = qlcnic_get_mac_address(adapter, mac_addr,
30262306a36Sopenharmony_ci				     adapter->ahw->pci_func);
30362306a36Sopenharmony_ci	if (ret)
30462306a36Sopenharmony_ci		return ret;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	eth_hw_addr_set(netdev, mac_addr);
30762306a36Sopenharmony_ci	memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* set station address */
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (!is_valid_ether_addr(netdev->dev_addr))
31262306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
31362306a36Sopenharmony_ci					netdev->dev_addr);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return 0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void qlcnic_delete_adapter_mac(struct qlcnic_adapter *adapter)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	list_for_each_entry(cur, &adapter->mac_list, list) {
32362306a36Sopenharmony_ci		if (ether_addr_equal_unaligned(adapter->mac_addr, cur->mac_addr)) {
32462306a36Sopenharmony_ci			qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
32562306a36Sopenharmony_ci						  0, QLCNIC_MAC_DEL);
32662306a36Sopenharmony_ci			list_del(&cur->list);
32762306a36Sopenharmony_ci			kfree(cur);
32862306a36Sopenharmony_ci			return;
32962306a36Sopenharmony_ci		}
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic int qlcnic_set_mac(struct net_device *netdev, void *p)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
33662306a36Sopenharmony_ci	struct sockaddr *addr = p;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter))
33962306a36Sopenharmony_ci		return -EINVAL;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if ((adapter->flags & QLCNIC_MAC_OVERRIDE_DISABLED))
34262306a36Sopenharmony_ci		return -EOPNOTSUPP;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
34562306a36Sopenharmony_ci		return -EINVAL;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data) &&
34862306a36Sopenharmony_ci	    ether_addr_equal_unaligned(netdev->dev_addr, addr->sa_data))
34962306a36Sopenharmony_ci		return 0;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
35262306a36Sopenharmony_ci		netif_device_detach(netdev);
35362306a36Sopenharmony_ci		qlcnic_napi_disable(adapter);
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	qlcnic_delete_adapter_mac(adapter);
35762306a36Sopenharmony_ci	memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len);
35862306a36Sopenharmony_ci	eth_hw_addr_set(netdev, addr->sa_data);
35962306a36Sopenharmony_ci	qlcnic_set_multi(adapter->netdev);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
36262306a36Sopenharmony_ci		netif_device_attach(netdev);
36362306a36Sopenharmony_ci		qlcnic_napi_enable(adapter);
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
36962306a36Sopenharmony_ci			struct net_device *netdev,
37062306a36Sopenharmony_ci			const unsigned char *addr, u16 vid,
37162306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
37462306a36Sopenharmony_ci	int err = -EOPNOTSUPP;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (!adapter->fdb_mac_learn)
37762306a36Sopenharmony_ci		return ndo_dflt_fdb_del(ndm, tb, netdev, addr, vid);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
38062306a36Sopenharmony_ci	    qlcnic_sriov_check(adapter)) {
38162306a36Sopenharmony_ci		if (is_unicast_ether_addr(addr)) {
38262306a36Sopenharmony_ci			err = dev_uc_del(netdev, addr);
38362306a36Sopenharmony_ci			if (!err)
38462306a36Sopenharmony_ci				err = qlcnic_nic_del_mac(adapter, addr);
38562306a36Sopenharmony_ci		} else if (is_multicast_ether_addr(addr)) {
38662306a36Sopenharmony_ci			err = dev_mc_del(netdev, addr);
38762306a36Sopenharmony_ci		} else {
38862306a36Sopenharmony_ci			err =  -EINVAL;
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	return err;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
39562306a36Sopenharmony_ci			struct net_device *netdev,
39662306a36Sopenharmony_ci			const unsigned char *addr, u16 vid, u16 flags,
39762306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
40062306a36Sopenharmony_ci	int err = 0;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (!adapter->fdb_mac_learn)
40362306a36Sopenharmony_ci		return ndo_dflt_fdb_add(ndm, tb, netdev, addr, vid, flags);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
40662306a36Sopenharmony_ci	    !qlcnic_sriov_check(adapter)) {
40762306a36Sopenharmony_ci		pr_info("%s: FDB e-switch is not enabled\n", __func__);
40862306a36Sopenharmony_ci		return -EOPNOTSUPP;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (ether_addr_equal(addr, adapter->mac_addr))
41262306a36Sopenharmony_ci		return err;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (is_unicast_ether_addr(addr)) {
41562306a36Sopenharmony_ci		if (netdev_uc_count(netdev) < adapter->ahw->max_uc_count)
41662306a36Sopenharmony_ci			err = dev_uc_add_excl(netdev, addr);
41762306a36Sopenharmony_ci		else
41862306a36Sopenharmony_ci			err = -ENOMEM;
41962306a36Sopenharmony_ci	} else if (is_multicast_ether_addr(addr)) {
42062306a36Sopenharmony_ci		err = dev_mc_add_excl(netdev, addr);
42162306a36Sopenharmony_ci	} else {
42262306a36Sopenharmony_ci		err = -EINVAL;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	return err;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,
42962306a36Sopenharmony_ci			struct net_device *netdev,
43062306a36Sopenharmony_ci			struct net_device *filter_dev, int *idx)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
43362306a36Sopenharmony_ci	int err = 0;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (!adapter->fdb_mac_learn)
43662306a36Sopenharmony_ci		return ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
43962306a36Sopenharmony_ci	    qlcnic_sriov_check(adapter))
44062306a36Sopenharmony_ci		err = ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return err;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
44862306a36Sopenharmony_ci		usleep_range(10000, 11000);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (!adapter->fw_work.work.func)
45162306a36Sopenharmony_ci		return;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	cancel_delayed_work_sync(&adapter->fw_work);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int qlcnic_get_phys_port_id(struct net_device *netdev,
45762306a36Sopenharmony_ci				   struct netdev_phys_item_id *ppid)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
46062306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (!(adapter->flags & QLCNIC_HAS_PHYS_PORT_ID))
46362306a36Sopenharmony_ci		return -EOPNOTSUPP;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	ppid->id_len = sizeof(ahw->phys_port_id);
46662306a36Sopenharmony_ci	memcpy(ppid->id, ahw->phys_port_id, ppid->id_len);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	return 0;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic int qlcnic_udp_tunnel_sync(struct net_device *dev, unsigned int table)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(dev);
47462306a36Sopenharmony_ci	struct udp_tunnel_info ti;
47562306a36Sopenharmony_ci	int err;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	udp_tunnel_nic_get_port(dev, table, 0, &ti);
47862306a36Sopenharmony_ci	if (ti.port) {
47962306a36Sopenharmony_ci		err = qlcnic_set_vxlan_port(adapter, ntohs(ti.port));
48062306a36Sopenharmony_ci		if (err)
48162306a36Sopenharmony_ci			return err;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	return qlcnic_set_vxlan_parsing(adapter, ntohs(ti.port));
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic const struct udp_tunnel_nic_info qlcnic_udp_tunnels = {
48862306a36Sopenharmony_ci	.sync_table	= qlcnic_udp_tunnel_sync,
48962306a36Sopenharmony_ci	.flags		= UDP_TUNNEL_NIC_INFO_MAY_SLEEP,
49062306a36Sopenharmony_ci	.tables		= {
49162306a36Sopenharmony_ci		{ .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, },
49262306a36Sopenharmony_ci	},
49362306a36Sopenharmony_ci};
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic netdev_features_t qlcnic_features_check(struct sk_buff *skb,
49662306a36Sopenharmony_ci					       struct net_device *dev,
49762306a36Sopenharmony_ci					       netdev_features_t features)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	features = vlan_features_check(skb, features);
50062306a36Sopenharmony_ci	return vxlan_features_check(skb, features);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic const struct net_device_ops qlcnic_netdev_ops = {
50462306a36Sopenharmony_ci	.ndo_open	   = qlcnic_open,
50562306a36Sopenharmony_ci	.ndo_stop	   = qlcnic_close,
50662306a36Sopenharmony_ci	.ndo_start_xmit    = qlcnic_xmit_frame,
50762306a36Sopenharmony_ci	.ndo_get_stats	   = qlcnic_get_stats,
50862306a36Sopenharmony_ci	.ndo_validate_addr = eth_validate_addr,
50962306a36Sopenharmony_ci	.ndo_set_rx_mode   = qlcnic_set_multi,
51062306a36Sopenharmony_ci	.ndo_set_mac_address    = qlcnic_set_mac,
51162306a36Sopenharmony_ci	.ndo_change_mtu	   = qlcnic_change_mtu,
51262306a36Sopenharmony_ci	.ndo_fix_features  = qlcnic_fix_features,
51362306a36Sopenharmony_ci	.ndo_set_features  = qlcnic_set_features,
51462306a36Sopenharmony_ci	.ndo_tx_timeout	   = qlcnic_tx_timeout,
51562306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid	= qlcnic_vlan_rx_add,
51662306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= qlcnic_vlan_rx_del,
51762306a36Sopenharmony_ci	.ndo_fdb_add		= qlcnic_fdb_add,
51862306a36Sopenharmony_ci	.ndo_fdb_del		= qlcnic_fdb_del,
51962306a36Sopenharmony_ci	.ndo_fdb_dump		= qlcnic_fdb_dump,
52062306a36Sopenharmony_ci	.ndo_get_phys_port_id	= qlcnic_get_phys_port_id,
52162306a36Sopenharmony_ci	.ndo_features_check	= qlcnic_features_check,
52262306a36Sopenharmony_ci#ifdef CONFIG_QLCNIC_SRIOV
52362306a36Sopenharmony_ci	.ndo_set_vf_mac		= qlcnic_sriov_set_vf_mac,
52462306a36Sopenharmony_ci	.ndo_set_vf_rate	= qlcnic_sriov_set_vf_tx_rate,
52562306a36Sopenharmony_ci	.ndo_get_vf_config	= qlcnic_sriov_get_vf_config,
52662306a36Sopenharmony_ci	.ndo_set_vf_vlan	= qlcnic_sriov_set_vf_vlan,
52762306a36Sopenharmony_ci	.ndo_set_vf_spoofchk	= qlcnic_sriov_set_vf_spoofchk,
52862306a36Sopenharmony_ci#endif
52962306a36Sopenharmony_ci};
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic const struct net_device_ops qlcnic_netdev_failed_ops = {
53262306a36Sopenharmony_ci	.ndo_open	   = qlcnic_open,
53362306a36Sopenharmony_ci};
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic struct qlcnic_nic_template qlcnic_ops = {
53662306a36Sopenharmony_ci	.config_bridged_mode	= qlcnic_config_bridged_mode,
53762306a36Sopenharmony_ci	.config_led		= qlcnic_82xx_config_led,
53862306a36Sopenharmony_ci	.start_firmware		= qlcnic_82xx_start_firmware,
53962306a36Sopenharmony_ci	.request_reset		= qlcnic_82xx_dev_request_reset,
54062306a36Sopenharmony_ci	.cancel_idc_work	= qlcnic_82xx_cancel_idc_work,
54162306a36Sopenharmony_ci	.napi_add		= qlcnic_82xx_napi_add,
54262306a36Sopenharmony_ci	.napi_del		= qlcnic_82xx_napi_del,
54362306a36Sopenharmony_ci	.config_ipaddr		= qlcnic_82xx_config_ipaddr,
54462306a36Sopenharmony_ci	.shutdown		= qlcnic_82xx_shutdown,
54562306a36Sopenharmony_ci	.resume			= qlcnic_82xx_resume,
54662306a36Sopenharmony_ci	.clear_legacy_intr	= qlcnic_82xx_clear_legacy_intr,
54762306a36Sopenharmony_ci};
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistruct qlcnic_nic_template qlcnic_vf_ops = {
55062306a36Sopenharmony_ci	.config_bridged_mode	= qlcnicvf_config_bridged_mode,
55162306a36Sopenharmony_ci	.config_led		= qlcnicvf_config_led,
55262306a36Sopenharmony_ci	.start_firmware		= qlcnicvf_start_firmware
55362306a36Sopenharmony_ci};
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic struct qlcnic_hardware_ops qlcnic_hw_ops = {
55662306a36Sopenharmony_ci	.read_crb			= qlcnic_82xx_read_crb,
55762306a36Sopenharmony_ci	.write_crb			= qlcnic_82xx_write_crb,
55862306a36Sopenharmony_ci	.read_reg			= qlcnic_82xx_hw_read_wx_2M,
55962306a36Sopenharmony_ci	.write_reg			= qlcnic_82xx_hw_write_wx_2M,
56062306a36Sopenharmony_ci	.get_mac_address		= qlcnic_82xx_get_mac_address,
56162306a36Sopenharmony_ci	.setup_intr			= qlcnic_82xx_setup_intr,
56262306a36Sopenharmony_ci	.alloc_mbx_args			= qlcnic_82xx_alloc_mbx_args,
56362306a36Sopenharmony_ci	.mbx_cmd			= qlcnic_82xx_issue_cmd,
56462306a36Sopenharmony_ci	.get_func_no			= qlcnic_82xx_get_func_no,
56562306a36Sopenharmony_ci	.api_lock			= qlcnic_82xx_api_lock,
56662306a36Sopenharmony_ci	.api_unlock			= qlcnic_82xx_api_unlock,
56762306a36Sopenharmony_ci	.add_sysfs			= qlcnic_82xx_add_sysfs,
56862306a36Sopenharmony_ci	.remove_sysfs			= qlcnic_82xx_remove_sysfs,
56962306a36Sopenharmony_ci	.process_lb_rcv_ring_diag	= qlcnic_82xx_process_rcv_ring_diag,
57062306a36Sopenharmony_ci	.create_rx_ctx			= qlcnic_82xx_fw_cmd_create_rx_ctx,
57162306a36Sopenharmony_ci	.create_tx_ctx			= qlcnic_82xx_fw_cmd_create_tx_ctx,
57262306a36Sopenharmony_ci	.del_rx_ctx			= qlcnic_82xx_fw_cmd_del_rx_ctx,
57362306a36Sopenharmony_ci	.del_tx_ctx			= qlcnic_82xx_fw_cmd_del_tx_ctx,
57462306a36Sopenharmony_ci	.setup_link_event		= qlcnic_82xx_linkevent_request,
57562306a36Sopenharmony_ci	.get_nic_info			= qlcnic_82xx_get_nic_info,
57662306a36Sopenharmony_ci	.get_pci_info			= qlcnic_82xx_get_pci_info,
57762306a36Sopenharmony_ci	.set_nic_info			= qlcnic_82xx_set_nic_info,
57862306a36Sopenharmony_ci	.change_macvlan			= qlcnic_82xx_sre_macaddr_change,
57962306a36Sopenharmony_ci	.napi_enable			= qlcnic_82xx_napi_enable,
58062306a36Sopenharmony_ci	.napi_disable			= qlcnic_82xx_napi_disable,
58162306a36Sopenharmony_ci	.config_intr_coal		= qlcnic_82xx_config_intr_coalesce,
58262306a36Sopenharmony_ci	.config_rss			= qlcnic_82xx_config_rss,
58362306a36Sopenharmony_ci	.config_hw_lro			= qlcnic_82xx_config_hw_lro,
58462306a36Sopenharmony_ci	.config_loopback		= qlcnic_82xx_set_lb_mode,
58562306a36Sopenharmony_ci	.clear_loopback			= qlcnic_82xx_clear_lb_mode,
58662306a36Sopenharmony_ci	.config_promisc_mode		= qlcnic_82xx_nic_set_promisc,
58762306a36Sopenharmony_ci	.change_l2_filter		= qlcnic_82xx_change_filter,
58862306a36Sopenharmony_ci	.get_board_info			= qlcnic_82xx_get_board_info,
58962306a36Sopenharmony_ci	.set_mac_filter_count		= qlcnic_82xx_set_mac_filter_count,
59062306a36Sopenharmony_ci	.free_mac_list			= qlcnic_82xx_free_mac_list,
59162306a36Sopenharmony_ci	.read_phys_port_id		= qlcnic_82xx_read_phys_port_id,
59262306a36Sopenharmony_ci	.io_error_detected		= qlcnic_82xx_io_error_detected,
59362306a36Sopenharmony_ci	.io_slot_reset			= qlcnic_82xx_io_slot_reset,
59462306a36Sopenharmony_ci	.io_resume			= qlcnic_82xx_io_resume,
59562306a36Sopenharmony_ci	.get_beacon_state		= qlcnic_82xx_get_beacon_state,
59662306a36Sopenharmony_ci	.enable_sds_intr		= qlcnic_82xx_enable_sds_intr,
59762306a36Sopenharmony_ci	.disable_sds_intr		= qlcnic_82xx_disable_sds_intr,
59862306a36Sopenharmony_ci	.enable_tx_intr			= qlcnic_82xx_enable_tx_intr,
59962306a36Sopenharmony_ci	.disable_tx_intr		= qlcnic_82xx_disable_tx_intr,
60062306a36Sopenharmony_ci	.get_saved_state		= qlcnic_82xx_get_saved_state,
60162306a36Sopenharmony_ci	.set_saved_state		= qlcnic_82xx_set_saved_state,
60262306a36Sopenharmony_ci	.cache_tmpl_hdr_values		= qlcnic_82xx_cache_tmpl_hdr_values,
60362306a36Sopenharmony_ci	.get_cap_size			= qlcnic_82xx_get_cap_size,
60462306a36Sopenharmony_ci	.set_sys_info			= qlcnic_82xx_set_sys_info,
60562306a36Sopenharmony_ci	.store_cap_mask			= qlcnic_82xx_store_cap_mask,
60662306a36Sopenharmony_ci	.encap_rx_offload               = qlcnic_82xx_encap_rx_offload,
60762306a36Sopenharmony_ci	.encap_tx_offload               = qlcnic_82xx_encap_tx_offload,
60862306a36Sopenharmony_ci};
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter) &&
61562306a36Sopenharmony_ci	    (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_MULTI_TX)) {
61662306a36Sopenharmony_ci		test_and_set_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state);
61762306a36Sopenharmony_ci		return 0;
61862306a36Sopenharmony_ci	} else {
61962306a36Sopenharmony_ci		return 1;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic int qlcnic_max_rings(struct qlcnic_adapter *adapter, u8 ring_cnt,
62462306a36Sopenharmony_ci			    int queue_type)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	int num_rings, max_rings = QLCNIC_MAX_SDS_RINGS;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (queue_type == QLCNIC_RX_QUEUE)
62962306a36Sopenharmony_ci		max_rings = adapter->max_sds_rings;
63062306a36Sopenharmony_ci	else if (queue_type == QLCNIC_TX_QUEUE)
63162306a36Sopenharmony_ci		max_rings = adapter->max_tx_rings;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	num_rings = rounddown_pow_of_two(min_t(int, num_online_cpus(),
63462306a36Sopenharmony_ci					      max_rings));
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (ring_cnt > num_rings)
63762306a36Sopenharmony_ci		return num_rings;
63862306a36Sopenharmony_ci	else
63962306a36Sopenharmony_ci		return ring_cnt;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_civoid qlcnic_set_tx_ring_count(struct qlcnic_adapter *adapter, u8 tx_cnt)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	/* 83xx adapter does not have max_tx_rings intialized in probe */
64562306a36Sopenharmony_ci	if (adapter->max_tx_rings)
64662306a36Sopenharmony_ci		adapter->drv_tx_rings = qlcnic_max_rings(adapter, tx_cnt,
64762306a36Sopenharmony_ci							 QLCNIC_TX_QUEUE);
64862306a36Sopenharmony_ci	else
64962306a36Sopenharmony_ci		adapter->drv_tx_rings = tx_cnt;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_civoid qlcnic_set_sds_ring_count(struct qlcnic_adapter *adapter, u8 rx_cnt)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	/* 83xx adapter does not have max_sds_rings intialized in probe */
65562306a36Sopenharmony_ci	if (adapter->max_sds_rings)
65662306a36Sopenharmony_ci		adapter->drv_sds_rings = qlcnic_max_rings(adapter, rx_cnt,
65762306a36Sopenharmony_ci							  QLCNIC_RX_QUEUE);
65862306a36Sopenharmony_ci	else
65962306a36Sopenharmony_ci		adapter->drv_sds_rings = rx_cnt;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ciint qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
66562306a36Sopenharmony_ci	int num_msix = 0, err = 0, vector;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	adapter->flags &= ~QLCNIC_TSS_RSS;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (adapter->drv_tss_rings > 0)
67062306a36Sopenharmony_ci		num_msix += adapter->drv_tss_rings;
67162306a36Sopenharmony_ci	else
67262306a36Sopenharmony_ci		num_msix += adapter->drv_tx_rings;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (adapter->drv_rss_rings > 0)
67562306a36Sopenharmony_ci		num_msix += adapter->drv_rss_rings;
67662306a36Sopenharmony_ci	else
67762306a36Sopenharmony_ci		num_msix += adapter->drv_sds_rings;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter))
68062306a36Sopenharmony_ci		num_msix += 1;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (!adapter->msix_entries) {
68362306a36Sopenharmony_ci		adapter->msix_entries = kcalloc(num_msix,
68462306a36Sopenharmony_ci						sizeof(struct msix_entry),
68562306a36Sopenharmony_ci						GFP_KERNEL);
68662306a36Sopenharmony_ci		if (!adapter->msix_entries)
68762306a36Sopenharmony_ci			return -ENOMEM;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	for (vector = 0; vector < num_msix; vector++)
69162306a36Sopenharmony_ci		adapter->msix_entries[vector].entry = vector;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cirestore:
69462306a36Sopenharmony_ci	err = pci_enable_msix_exact(pdev, adapter->msix_entries, num_msix);
69562306a36Sopenharmony_ci	if (err == -ENOSPC) {
69662306a36Sopenharmony_ci		if (!adapter->drv_tss_rings && !adapter->drv_rss_rings)
69762306a36Sopenharmony_ci			return err;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		netdev_info(adapter->netdev,
70062306a36Sopenharmony_ci			    "Unable to allocate %d MSI-X vectors, Available vectors %d\n",
70162306a36Sopenharmony_ci			    num_msix, err);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		num_msix = adapter->drv_tx_rings + adapter->drv_sds_rings;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		/* Set rings to 0 so we can restore original TSS/RSS count */
70662306a36Sopenharmony_ci		adapter->drv_tss_rings = 0;
70762306a36Sopenharmony_ci		adapter->drv_rss_rings = 0;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		if (qlcnic_83xx_check(adapter))
71062306a36Sopenharmony_ci			num_msix += 1;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci		netdev_info(adapter->netdev,
71362306a36Sopenharmony_ci			    "Restoring %d Tx, %d SDS rings for total %d vectors.\n",
71462306a36Sopenharmony_ci			    adapter->drv_tx_rings, adapter->drv_sds_rings,
71562306a36Sopenharmony_ci			    num_msix);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		goto restore;
71862306a36Sopenharmony_ci	} else if (err < 0) {
71962306a36Sopenharmony_ci		return err;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	adapter->ahw->num_msix = num_msix;
72362306a36Sopenharmony_ci	if (adapter->drv_tss_rings > 0)
72462306a36Sopenharmony_ci		adapter->drv_tx_rings = adapter->drv_tss_rings;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (adapter->drv_rss_rings > 0)
72762306a36Sopenharmony_ci		adapter->drv_sds_rings = adapter->drv_rss_rings;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	return 0;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ciint qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
73562306a36Sopenharmony_ci	int err, vector;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	if (!adapter->msix_entries) {
73862306a36Sopenharmony_ci		adapter->msix_entries = kcalloc(num_msix,
73962306a36Sopenharmony_ci						sizeof(struct msix_entry),
74062306a36Sopenharmony_ci						GFP_KERNEL);
74162306a36Sopenharmony_ci		if (!adapter->msix_entries)
74262306a36Sopenharmony_ci			return -ENOMEM;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (adapter->ahw->msix_supported) {
74862306a36Sopenharmony_cienable_msix:
74962306a36Sopenharmony_ci		for (vector = 0; vector < num_msix; vector++)
75062306a36Sopenharmony_ci			adapter->msix_entries[vector].entry = vector;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci		err = pci_enable_msix_range(pdev,
75362306a36Sopenharmony_ci					    adapter->msix_entries, 1, num_msix);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		if (err == num_msix) {
75662306a36Sopenharmony_ci			adapter->flags |= QLCNIC_MSIX_ENABLED;
75762306a36Sopenharmony_ci			adapter->ahw->num_msix = num_msix;
75862306a36Sopenharmony_ci			dev_info(&pdev->dev, "using msi-x interrupts\n");
75962306a36Sopenharmony_ci			return 0;
76062306a36Sopenharmony_ci		} else if (err > 0) {
76162306a36Sopenharmony_ci			pci_disable_msix(pdev);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci			dev_info(&pdev->dev,
76462306a36Sopenharmony_ci				 "Unable to allocate %d MSI-X vectors, Available vectors %d\n",
76562306a36Sopenharmony_ci				 num_msix, err);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci			if (qlcnic_82xx_check(adapter)) {
76862306a36Sopenharmony_ci				num_msix = rounddown_pow_of_two(err);
76962306a36Sopenharmony_ci				if (err < QLCNIC_82XX_MINIMUM_VECTOR)
77062306a36Sopenharmony_ci					return -ENOSPC;
77162306a36Sopenharmony_ci			} else {
77262306a36Sopenharmony_ci				num_msix = rounddown_pow_of_two(err - 1);
77362306a36Sopenharmony_ci				num_msix += 1;
77462306a36Sopenharmony_ci				if (err < QLCNIC_83XX_MINIMUM_VECTOR)
77562306a36Sopenharmony_ci					return -ENOSPC;
77662306a36Sopenharmony_ci			}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci			if (qlcnic_82xx_check(adapter) &&
77962306a36Sopenharmony_ci			    !qlcnic_check_multi_tx(adapter)) {
78062306a36Sopenharmony_ci				adapter->drv_sds_rings = num_msix;
78162306a36Sopenharmony_ci				adapter->drv_tx_rings = QLCNIC_SINGLE_RING;
78262306a36Sopenharmony_ci			} else {
78362306a36Sopenharmony_ci				/* Distribute vectors equally */
78462306a36Sopenharmony_ci				adapter->drv_tx_rings = num_msix / 2;
78562306a36Sopenharmony_ci				adapter->drv_sds_rings = adapter->drv_tx_rings;
78662306a36Sopenharmony_ci			}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci			if (num_msix) {
78962306a36Sopenharmony_ci				dev_info(&pdev->dev,
79062306a36Sopenharmony_ci					 "Trying to allocate %d MSI-X interrupt vectors\n",
79162306a36Sopenharmony_ci					 num_msix);
79262306a36Sopenharmony_ci				goto enable_msix;
79362306a36Sopenharmony_ci			}
79462306a36Sopenharmony_ci		} else {
79562306a36Sopenharmony_ci			dev_info(&pdev->dev,
79662306a36Sopenharmony_ci				 "Unable to allocate %d MSI-X vectors, err=%d\n",
79762306a36Sopenharmony_ci				 num_msix, err);
79862306a36Sopenharmony_ci			return err;
79962306a36Sopenharmony_ci		}
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return -EIO;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	int num_msix;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	num_msix = adapter->drv_sds_rings;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if (qlcnic_check_multi_tx(adapter))
81262306a36Sopenharmony_ci		num_msix += adapter->drv_tx_rings;
81362306a36Sopenharmony_ci	else
81462306a36Sopenharmony_ci		num_msix += QLCNIC_SINGLE_RING;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	return num_msix;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	int err = 0;
82262306a36Sopenharmony_ci	u32 offset, mask_reg;
82362306a36Sopenharmony_ci	const struct qlcnic_legacy_intr_set *legacy_intrp;
82462306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
82562306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	if (qlcnic_use_msi && !pci_enable_msi(pdev)) {
82862306a36Sopenharmony_ci		adapter->flags |= QLCNIC_MSI_ENABLED;
82962306a36Sopenharmony_ci		offset = msi_tgt_status[adapter->ahw->pci_func];
83062306a36Sopenharmony_ci		adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter->ahw,
83162306a36Sopenharmony_ci							    offset);
83262306a36Sopenharmony_ci		dev_info(&pdev->dev, "using msi interrupts\n");
83362306a36Sopenharmony_ci		adapter->msix_entries[0].vector = pdev->irq;
83462306a36Sopenharmony_ci		return err;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (qlcnic_use_msi || qlcnic_use_msi_x)
83862306a36Sopenharmony_ci		return -EOPNOTSUPP;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
84162306a36Sopenharmony_ci	adapter->ahw->int_vec_bit = legacy_intrp->int_vec_bit;
84262306a36Sopenharmony_ci	offset = legacy_intrp->tgt_status_reg;
84362306a36Sopenharmony_ci	adapter->tgt_status_reg = qlcnic_get_ioaddr(ahw, offset);
84462306a36Sopenharmony_ci	mask_reg = legacy_intrp->tgt_mask_reg;
84562306a36Sopenharmony_ci	adapter->tgt_mask_reg = qlcnic_get_ioaddr(ahw, mask_reg);
84662306a36Sopenharmony_ci	adapter->isr_int_vec = qlcnic_get_ioaddr(ahw, ISR_INT_VECTOR);
84762306a36Sopenharmony_ci	adapter->crb_int_state_reg = qlcnic_get_ioaddr(ahw, ISR_INT_STATE_REG);
84862306a36Sopenharmony_ci	dev_info(&pdev->dev, "using legacy interrupts\n");
84962306a36Sopenharmony_ci	adapter->msix_entries[0].vector = pdev->irq;
85062306a36Sopenharmony_ci	return err;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	int num_msix, err = 0;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (adapter->flags & QLCNIC_TSS_RSS) {
85862306a36Sopenharmony_ci		err = qlcnic_setup_tss_rss_intr(adapter);
85962306a36Sopenharmony_ci		if (err < 0)
86062306a36Sopenharmony_ci			return err;
86162306a36Sopenharmony_ci		num_msix = adapter->ahw->num_msix;
86262306a36Sopenharmony_ci	} else {
86362306a36Sopenharmony_ci		num_msix = qlcnic_82xx_calculate_msix_vector(adapter);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci		err = qlcnic_enable_msix(adapter, num_msix);
86662306a36Sopenharmony_ci		if (err == -ENOMEM)
86762306a36Sopenharmony_ci			return err;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
87062306a36Sopenharmony_ci			qlcnic_disable_multi_tx(adapter);
87162306a36Sopenharmony_ci			adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci			err = qlcnic_enable_msi_legacy(adapter);
87462306a36Sopenharmony_ci			if (err)
87562306a36Sopenharmony_ci				return err;
87662306a36Sopenharmony_ci		}
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	return 0;
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ciint qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *adapter, int op_type)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
88562306a36Sopenharmony_ci	int err, i;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	if (qlcnic_check_multi_tx(adapter) &&
88862306a36Sopenharmony_ci	    !ahw->diag_test &&
88962306a36Sopenharmony_ci	    (adapter->flags & QLCNIC_MSIX_ENABLED)) {
89062306a36Sopenharmony_ci		ahw->intr_tbl =
89162306a36Sopenharmony_ci			vzalloc(array_size(sizeof(struct qlcnic_intrpt_config),
89262306a36Sopenharmony_ci					   ahw->num_msix));
89362306a36Sopenharmony_ci		if (!ahw->intr_tbl)
89462306a36Sopenharmony_ci			return -ENOMEM;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		for (i = 0; i < ahw->num_msix; i++) {
89762306a36Sopenharmony_ci			ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX;
89862306a36Sopenharmony_ci			ahw->intr_tbl[i].id = i;
89962306a36Sopenharmony_ci			ahw->intr_tbl[i].src = 0;
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		err = qlcnic_82xx_config_intrpt(adapter, 1);
90362306a36Sopenharmony_ci		if (err)
90462306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
90562306a36Sopenharmony_ci				"Failed to configure Interrupt for %d vector\n",
90662306a36Sopenharmony_ci				ahw->num_msix);
90762306a36Sopenharmony_ci		return err;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	return 0;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_civoid qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	if (adapter->flags & QLCNIC_MSIX_ENABLED)
91662306a36Sopenharmony_ci		pci_disable_msix(adapter->pdev);
91762306a36Sopenharmony_ci	if (adapter->flags & QLCNIC_MSI_ENABLED)
91862306a36Sopenharmony_ci		pci_disable_msi(adapter->pdev);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	kfree(adapter->msix_entries);
92162306a36Sopenharmony_ci	adapter->msix_entries = NULL;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (adapter->ahw->intr_tbl) {
92462306a36Sopenharmony_ci		vfree(adapter->ahw->intr_tbl);
92562306a36Sopenharmony_ci		adapter->ahw->intr_tbl = NULL;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cistatic void qlcnic_cleanup_pci_map(struct qlcnic_hardware_context *ahw)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	if (ahw->pci_base0 != NULL)
93262306a36Sopenharmony_ci		iounmap(ahw->pci_base0);
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
93862306a36Sopenharmony_ci	struct qlcnic_pci_info *pci_info;
93962306a36Sopenharmony_ci	int ret;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
94262306a36Sopenharmony_ci		switch (ahw->port_type) {
94362306a36Sopenharmony_ci		case QLCNIC_GBE:
94462306a36Sopenharmony_ci			ahw->total_nic_func = QLCNIC_NIU_MAX_GBE_PORTS;
94562306a36Sopenharmony_ci			break;
94662306a36Sopenharmony_ci		case QLCNIC_XGBE:
94762306a36Sopenharmony_ci			ahw->total_nic_func = QLCNIC_NIU_MAX_XG_PORTS;
94862306a36Sopenharmony_ci			break;
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci		return 0;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (ahw->op_mode == QLCNIC_MGMT_FUNC)
95462306a36Sopenharmony_ci		return 0;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL);
95762306a36Sopenharmony_ci	if (!pci_info)
95862306a36Sopenharmony_ci		return -ENOMEM;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	ret = qlcnic_get_pci_info(adapter, pci_info);
96162306a36Sopenharmony_ci	kfree(pci_info);
96262306a36Sopenharmony_ci	return ret;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic bool qlcnic_port_eswitch_cfg_capability(struct qlcnic_adapter *adapter)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	bool ret = false;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (qlcnic_84xx_check(adapter)) {
97062306a36Sopenharmony_ci		ret = true;
97162306a36Sopenharmony_ci	} else if (qlcnic_83xx_check(adapter)) {
97262306a36Sopenharmony_ci		if (adapter->ahw->extra_capability[0] &
97362306a36Sopenharmony_ci		    QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG)
97462306a36Sopenharmony_ci			ret = true;
97562306a36Sopenharmony_ci		else
97662306a36Sopenharmony_ci			ret = false;
97762306a36Sopenharmony_ci	}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	return ret;
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ciint qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
98562306a36Sopenharmony_ci	struct qlcnic_pci_info *pci_info;
98662306a36Sopenharmony_ci	int i, id = 0, ret = 0, j = 0;
98762306a36Sopenharmony_ci	u16 act_pci_func;
98862306a36Sopenharmony_ci	u8 pfn;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL);
99162306a36Sopenharmony_ci	if (!pci_info)
99262306a36Sopenharmony_ci		return -ENOMEM;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	ret = qlcnic_get_pci_info(adapter, pci_info);
99562306a36Sopenharmony_ci	if (ret)
99662306a36Sopenharmony_ci		goto err_pci_info;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	act_pci_func = ahw->total_nic_func;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	adapter->npars = kcalloc(act_pci_func,
100162306a36Sopenharmony_ci				 sizeof(struct qlcnic_npar_info),
100262306a36Sopenharmony_ci				 GFP_KERNEL);
100362306a36Sopenharmony_ci	if (!adapter->npars) {
100462306a36Sopenharmony_ci		ret = -ENOMEM;
100562306a36Sopenharmony_ci		goto err_pci_info;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	adapter->eswitch = kcalloc(QLCNIC_NIU_MAX_XG_PORTS,
100962306a36Sopenharmony_ci				   sizeof(struct qlcnic_eswitch),
101062306a36Sopenharmony_ci				   GFP_KERNEL);
101162306a36Sopenharmony_ci	if (!adapter->eswitch) {
101262306a36Sopenharmony_ci		ret = -ENOMEM;
101362306a36Sopenharmony_ci		goto err_npars;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	for (i = 0; i < ahw->max_vnic_func; i++) {
101762306a36Sopenharmony_ci		pfn = pci_info[i].id;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci		if (pfn >= ahw->max_vnic_func) {
102062306a36Sopenharmony_ci			ret = -EINVAL;
102162306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev, "%s: Invalid function 0x%x, max 0x%x\n",
102262306a36Sopenharmony_ci				__func__, pfn, ahw->max_vnic_func);
102362306a36Sopenharmony_ci			goto err_eswitch;
102462306a36Sopenharmony_ci		}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		if (!pci_info[i].active ||
102762306a36Sopenharmony_ci		    (pci_info[i].type != QLCNIC_TYPE_NIC))
102862306a36Sopenharmony_ci			continue;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci		if (qlcnic_port_eswitch_cfg_capability(adapter)) {
103162306a36Sopenharmony_ci			if (!qlcnic_83xx_set_port_eswitch_status(adapter, pfn,
103262306a36Sopenharmony_ci								 &id))
103362306a36Sopenharmony_ci				adapter->npars[j].eswitch_status = true;
103462306a36Sopenharmony_ci			else
103562306a36Sopenharmony_ci				continue;
103662306a36Sopenharmony_ci		} else {
103762306a36Sopenharmony_ci			adapter->npars[j].eswitch_status = true;
103862306a36Sopenharmony_ci		}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci		adapter->npars[j].pci_func = pfn;
104162306a36Sopenharmony_ci		adapter->npars[j].active = (u8)pci_info[i].active;
104262306a36Sopenharmony_ci		adapter->npars[j].type = (u8)pci_info[i].type;
104362306a36Sopenharmony_ci		adapter->npars[j].phy_port = (u8)pci_info[i].default_port;
104462306a36Sopenharmony_ci		adapter->npars[j].min_bw = pci_info[i].tx_min_bw;
104562306a36Sopenharmony_ci		adapter->npars[j].max_bw = pci_info[i].tx_max_bw;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci		memcpy(&adapter->npars[j].mac, &pci_info[i].mac, ETH_ALEN);
104862306a36Sopenharmony_ci		j++;
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* Update eSwitch status for adapters without per port eSwitch
105262306a36Sopenharmony_ci	 * configuration capability
105362306a36Sopenharmony_ci	 */
105462306a36Sopenharmony_ci	if (!qlcnic_port_eswitch_cfg_capability(adapter)) {
105562306a36Sopenharmony_ci		for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
105662306a36Sopenharmony_ci			adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	kfree(pci_info);
106062306a36Sopenharmony_ci	return 0;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cierr_eswitch:
106362306a36Sopenharmony_ci	kfree(adapter->eswitch);
106462306a36Sopenharmony_ci	adapter->eswitch = NULL;
106562306a36Sopenharmony_cierr_npars:
106662306a36Sopenharmony_ci	kfree(adapter->npars);
106762306a36Sopenharmony_ci	adapter->npars = NULL;
106862306a36Sopenharmony_cierr_pci_info:
106962306a36Sopenharmony_ci	kfree(pci_info);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	return ret;
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_cistatic int
107562306a36Sopenharmony_ciqlcnic_set_function_modes(struct qlcnic_adapter *adapter)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	u8 id;
107862306a36Sopenharmony_ci	int ret;
107962306a36Sopenharmony_ci	u32 data = QLCNIC_MGMT_FUNC;
108062306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	ret = qlcnic_api_lock(adapter);
108362306a36Sopenharmony_ci	if (ret)
108462306a36Sopenharmony_ci		goto err_lock;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	id = ahw->pci_func;
108762306a36Sopenharmony_ci	data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
108862306a36Sopenharmony_ci	data = (data & ~QLC_DEV_SET_DRV(0xf, id)) |
108962306a36Sopenharmony_ci	       QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, id);
109062306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_DRV_OP_MODE, data);
109162306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
109262306a36Sopenharmony_cierr_lock:
109362306a36Sopenharmony_ci	return ret;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic void qlcnic_check_vf(struct qlcnic_adapter *adapter,
109762306a36Sopenharmony_ci			    const struct pci_device_id *ent)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	u32 op_mode, priv_level;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	/* Determine FW API version */
110262306a36Sopenharmony_ci	adapter->ahw->fw_hal_version = QLC_SHARED_REG_RD32(adapter,
110362306a36Sopenharmony_ci							   QLCNIC_FW_API);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* Find PCI function number */
110662306a36Sopenharmony_ci	qlcnic_get_func_no(adapter);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/* Determine function privilege level */
110962306a36Sopenharmony_ci	op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
111062306a36Sopenharmony_ci	if (op_mode == QLC_DEV_DRV_DEFAULT)
111162306a36Sopenharmony_ci		priv_level = QLCNIC_MGMT_FUNC;
111262306a36Sopenharmony_ci	else
111362306a36Sopenharmony_ci		priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	if (priv_level == QLCNIC_NON_PRIV_FUNC) {
111662306a36Sopenharmony_ci		adapter->ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
111762306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev,
111862306a36Sopenharmony_ci			"HAL Version: %d Non Privileged function\n",
111962306a36Sopenharmony_ci			 adapter->ahw->fw_hal_version);
112062306a36Sopenharmony_ci		adapter->nic_ops = &qlcnic_vf_ops;
112162306a36Sopenharmony_ci	} else
112262306a36Sopenharmony_ci		adapter->nic_ops = &qlcnic_ops;
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci#define QLCNIC_82XX_BAR0_LENGTH 0x00200000UL
112662306a36Sopenharmony_ci#define QLCNIC_83XX_BAR0_LENGTH 0x4000
112762306a36Sopenharmony_cistatic void qlcnic_get_bar_length(u32 dev_id, ulong *bar)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	switch (dev_id) {
113062306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE824X:
113162306a36Sopenharmony_ci		*bar = QLCNIC_82XX_BAR0_LENGTH;
113262306a36Sopenharmony_ci		break;
113362306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE834X:
113462306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE8830:
113562306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE844X:
113662306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_VF_QLE834X:
113762306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_VF_QLE844X:
113862306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_VF_QLE8C30:
113962306a36Sopenharmony_ci		*bar = QLCNIC_83XX_BAR0_LENGTH;
114062306a36Sopenharmony_ci		break;
114162306a36Sopenharmony_ci	default:
114262306a36Sopenharmony_ci		*bar = 0;
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic int qlcnic_setup_pci_map(struct pci_dev *pdev,
114762306a36Sopenharmony_ci				struct qlcnic_hardware_context *ahw)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	u32 offset;
115062306a36Sopenharmony_ci	void __iomem *mem_ptr0 = NULL;
115162306a36Sopenharmony_ci	unsigned long mem_len, pci_len0 = 0, bar0_len;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/* remap phys address */
115462306a36Sopenharmony_ci	mem_len = pci_resource_len(pdev, 0);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	qlcnic_get_bar_length(pdev->device, &bar0_len);
115762306a36Sopenharmony_ci	if (mem_len >= bar0_len) {
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci		mem_ptr0 = pci_ioremap_bar(pdev, 0);
116062306a36Sopenharmony_ci		if (mem_ptr0 == NULL) {
116162306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to map PCI bar 0\n");
116262306a36Sopenharmony_ci			return -EIO;
116362306a36Sopenharmony_ci		}
116462306a36Sopenharmony_ci		pci_len0 = mem_len;
116562306a36Sopenharmony_ci	} else {
116662306a36Sopenharmony_ci		return -EIO;
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	dev_info(&pdev->dev, "%dKB memory map\n", (int)(mem_len >> 10));
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	ahw->pci_base0 = mem_ptr0;
117262306a36Sopenharmony_ci	ahw->pci_len0 = pci_len0;
117362306a36Sopenharmony_ci	offset = QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(ahw->pci_func));
117462306a36Sopenharmony_ci	qlcnic_get_ioaddr(ahw, offset);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	return 0;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic bool qlcnic_validate_subsystem_id(struct qlcnic_adapter *adapter,
118062306a36Sopenharmony_ci					 int index)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
118362306a36Sopenharmony_ci	unsigned short subsystem_vendor;
118462306a36Sopenharmony_ci	bool ret = true;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	subsystem_vendor = pdev->subsystem_vendor;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	if (pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X ||
118962306a36Sopenharmony_ci	    pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
119062306a36Sopenharmony_ci		if (qlcnic_boards[index].sub_vendor == subsystem_vendor &&
119162306a36Sopenharmony_ci		    qlcnic_boards[index].sub_device == pdev->subsystem_device)
119262306a36Sopenharmony_ci			ret = true;
119362306a36Sopenharmony_ci		else
119462306a36Sopenharmony_ci			ret = false;
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	return ret;
119862306a36Sopenharmony_ci}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
120362306a36Sopenharmony_ci	int i, found = 0;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
120662306a36Sopenharmony_ci		if (qlcnic_boards[i].vendor == pdev->vendor &&
120762306a36Sopenharmony_ci		    qlcnic_boards[i].device == pdev->device &&
120862306a36Sopenharmony_ci		    qlcnic_validate_subsystem_id(adapter, i)) {
120962306a36Sopenharmony_ci			found = 1;
121062306a36Sopenharmony_ci			break;
121162306a36Sopenharmony_ci		}
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	if (!found)
121562306a36Sopenharmony_ci		sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
121662306a36Sopenharmony_ci	else
121762306a36Sopenharmony_ci		sprintf(name, "%pM: %s" , adapter->mac_addr,
121862306a36Sopenharmony_ci			qlcnic_boards[i].short_name);
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_cistatic void
122262306a36Sopenharmony_ciqlcnic_check_options(struct qlcnic_adapter *adapter)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	int err;
122562306a36Sopenharmony_ci	u32 fw_major, fw_minor, fw_build, prev_fw_version;
122662306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
122762306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
122862306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	prev_fw_version = adapter->fw_version;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
123362306a36Sopenharmony_ci	fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
123462306a36Sopenharmony_ci	fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	err = qlcnic_get_board_info(adapter);
123962306a36Sopenharmony_ci	if (err) {
124062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Error getting board config info.\n");
124162306a36Sopenharmony_ci		return;
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci	if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
124462306a36Sopenharmony_ci		if (fw_dump->tmpl_hdr == NULL ||
124562306a36Sopenharmony_ci				adapter->fw_version > prev_fw_version) {
124662306a36Sopenharmony_ci			vfree(fw_dump->tmpl_hdr);
124762306a36Sopenharmony_ci			if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
124862306a36Sopenharmony_ci				dev_info(&pdev->dev,
124962306a36Sopenharmony_ci					"Supports FW dump capability\n");
125062306a36Sopenharmony_ci		}
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	dev_info(&pdev->dev, "Driver v%s, firmware v%d.%d.%d\n",
125462306a36Sopenharmony_ci		 QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	if (adapter->ahw->port_type == QLCNIC_XGBE) {
125762306a36Sopenharmony_ci		if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
125862306a36Sopenharmony_ci			adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
125962306a36Sopenharmony_ci			adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
126062306a36Sopenharmony_ci		} else {
126162306a36Sopenharmony_ci			adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
126262306a36Sopenharmony_ci			adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
126362306a36Sopenharmony_ci		}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
126662306a36Sopenharmony_ci		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	} else if (adapter->ahw->port_type == QLCNIC_GBE) {
126962306a36Sopenharmony_ci		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
127062306a36Sopenharmony_ci		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
127162306a36Sopenharmony_ci		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
127262306a36Sopenharmony_ci		adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	adapter->num_txd = MAX_CMD_DESCRIPTORS;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	adapter->max_rds_rings = MAX_RDS_RINGS;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int
128362306a36Sopenharmony_ciqlcnic_initialize_nic(struct qlcnic_adapter *adapter)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct qlcnic_info nic_info;
128662306a36Sopenharmony_ci	int err = 0;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	memset(&nic_info, 0, sizeof(struct qlcnic_info));
128962306a36Sopenharmony_ci	err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func);
129062306a36Sopenharmony_ci	if (err)
129162306a36Sopenharmony_ci		return err;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	adapter->ahw->physical_port = (u8)nic_info.phys_port;
129462306a36Sopenharmony_ci	adapter->ahw->switch_mode = nic_info.switch_mode;
129562306a36Sopenharmony_ci	adapter->ahw->max_tx_ques = nic_info.max_tx_ques;
129662306a36Sopenharmony_ci	adapter->ahw->max_rx_ques = nic_info.max_rx_ques;
129762306a36Sopenharmony_ci	adapter->ahw->capabilities = nic_info.capabilities;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
130062306a36Sopenharmony_ci		u32 temp;
130162306a36Sopenharmony_ci		temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err);
130262306a36Sopenharmony_ci		if (err == -EIO)
130362306a36Sopenharmony_ci			return err;
130462306a36Sopenharmony_ci		adapter->ahw->extra_capability[0] = temp;
130562306a36Sopenharmony_ci	} else {
130662306a36Sopenharmony_ci		adapter->ahw->extra_capability[0] = 0;
130762306a36Sopenharmony_ci	}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
131062306a36Sopenharmony_ci	adapter->ahw->max_mtu = nic_info.max_mtu;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (adapter->ahw->capabilities & BIT_6) {
131362306a36Sopenharmony_ci		adapter->flags |= QLCNIC_ESWITCH_ENABLED;
131462306a36Sopenharmony_ci		adapter->ahw->nic_mode = QLCNIC_VNIC_MODE;
131562306a36Sopenharmony_ci		adapter->max_tx_rings = QLCNIC_MAX_HW_VNIC_TX_RINGS;
131662306a36Sopenharmony_ci		adapter->max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "vNIC mode enabled.\n");
131962306a36Sopenharmony_ci	} else {
132062306a36Sopenharmony_ci		adapter->ahw->nic_mode = QLCNIC_DEFAULT_MODE;
132162306a36Sopenharmony_ci		adapter->max_tx_rings = QLCNIC_MAX_HW_TX_RINGS;
132262306a36Sopenharmony_ci		adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS;
132362306a36Sopenharmony_ci		adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	return err;
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_civoid qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
133062306a36Sopenharmony_ci			    struct qlcnic_esw_func_cfg *esw_cfg)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	if (esw_cfg->discard_tagged)
133362306a36Sopenharmony_ci		adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
133462306a36Sopenharmony_ci	else
133562306a36Sopenharmony_ci		adapter->flags |= QLCNIC_TAGGING_ENABLED;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (esw_cfg->vlan_id) {
133862306a36Sopenharmony_ci		adapter->rx_pvid = esw_cfg->vlan_id;
133962306a36Sopenharmony_ci		adapter->tx_pvid = esw_cfg->vlan_id;
134062306a36Sopenharmony_ci	} else {
134162306a36Sopenharmony_ci		adapter->rx_pvid = 0;
134262306a36Sopenharmony_ci		adapter->tx_pvid = 0;
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cistatic int
134762306a36Sopenharmony_ciqlcnic_vlan_rx_add(struct net_device *netdev, __be16 proto, u16 vid)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
135062306a36Sopenharmony_ci	int err;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter)) {
135362306a36Sopenharmony_ci		err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 1);
135462306a36Sopenharmony_ci		if (err) {
135562306a36Sopenharmony_ci			netdev_err(netdev,
135662306a36Sopenharmony_ci				   "Cannot add VLAN filter for VLAN id %d, err=%d",
135762306a36Sopenharmony_ci				   vid, err);
135862306a36Sopenharmony_ci			return err;
135962306a36Sopenharmony_ci		}
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	set_bit(vid, adapter->vlans);
136362306a36Sopenharmony_ci	return 0;
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_cistatic int
136762306a36Sopenharmony_ciqlcnic_vlan_rx_del(struct net_device *netdev, __be16 proto, u16 vid)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
137062306a36Sopenharmony_ci	int err;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter)) {
137362306a36Sopenharmony_ci		err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 0);
137462306a36Sopenharmony_ci		if (err) {
137562306a36Sopenharmony_ci			netdev_err(netdev,
137662306a36Sopenharmony_ci				   "Cannot delete VLAN filter for VLAN id %d, err=%d",
137762306a36Sopenharmony_ci				   vid, err);
137862306a36Sopenharmony_ci			return err;
137962306a36Sopenharmony_ci		}
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	qlcnic_restore_indev_addr(netdev, NETDEV_DOWN);
138362306a36Sopenharmony_ci	clear_bit(vid, adapter->vlans);
138462306a36Sopenharmony_ci	return 0;
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_civoid qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
138862306a36Sopenharmony_ci				      struct qlcnic_esw_func_cfg *esw_cfg)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	adapter->flags &= ~(QLCNIC_MACSPOOF | QLCNIC_MAC_OVERRIDE_DISABLED |
139162306a36Sopenharmony_ci				QLCNIC_PROMISC_DISABLED);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	if (esw_cfg->mac_anti_spoof)
139462306a36Sopenharmony_ci		adapter->flags |= QLCNIC_MACSPOOF;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (!esw_cfg->mac_override)
139762306a36Sopenharmony_ci		adapter->flags |= QLCNIC_MAC_OVERRIDE_DISABLED;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	if (!esw_cfg->promisc_mode)
140062306a36Sopenharmony_ci		adapter->flags |= QLCNIC_PROMISC_DISABLED;
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ciint qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	struct qlcnic_esw_func_cfg esw_cfg;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
140862306a36Sopenharmony_ci		return 0;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	esw_cfg.pci_func = adapter->ahw->pci_func;
141162306a36Sopenharmony_ci	if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg))
141262306a36Sopenharmony_ci			return -EIO;
141362306a36Sopenharmony_ci	qlcnic_set_vlan_config(adapter, &esw_cfg);
141462306a36Sopenharmony_ci	qlcnic_set_eswitch_port_features(adapter, &esw_cfg);
141562306a36Sopenharmony_ci	qlcnic_set_netdev_features(adapter, &esw_cfg);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	return 0;
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_civoid qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
142162306a36Sopenharmony_ci				struct qlcnic_esw_func_cfg *esw_cfg)
142262306a36Sopenharmony_ci{
142362306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter))
142662306a36Sopenharmony_ci		return;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	adapter->offload_flags = esw_cfg->offload_flags;
142962306a36Sopenharmony_ci	adapter->flags |= QLCNIC_APP_CHANGED_FLAGS;
143062306a36Sopenharmony_ci	netdev_update_features(netdev);
143162306a36Sopenharmony_ci	adapter->flags &= ~QLCNIC_APP_CHANGED_FLAGS;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_cistatic int
143562306a36Sopenharmony_ciqlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	u32 op_mode, priv_level;
143862306a36Sopenharmony_ci	int err = 0;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	err = qlcnic_initialize_nic(adapter);
144162306a36Sopenharmony_ci	if (err)
144262306a36Sopenharmony_ci		return err;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
144562306a36Sopenharmony_ci		return 0;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
144862306a36Sopenharmony_ci	priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	if (op_mode == QLC_DEV_DRV_DEFAULT)
145162306a36Sopenharmony_ci		priv_level = QLCNIC_MGMT_FUNC;
145262306a36Sopenharmony_ci	else
145362306a36Sopenharmony_ci		priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
145662306a36Sopenharmony_ci		if (priv_level == QLCNIC_MGMT_FUNC) {
145762306a36Sopenharmony_ci			adapter->ahw->op_mode = QLCNIC_MGMT_FUNC;
145862306a36Sopenharmony_ci			err = qlcnic_init_pci_info(adapter);
145962306a36Sopenharmony_ci			if (err)
146062306a36Sopenharmony_ci				return err;
146162306a36Sopenharmony_ci			/* Set privilege level for other functions */
146262306a36Sopenharmony_ci			qlcnic_set_function_modes(adapter);
146362306a36Sopenharmony_ci			dev_info(&adapter->pdev->dev,
146462306a36Sopenharmony_ci				"HAL Version: %d, Management function\n",
146562306a36Sopenharmony_ci				 adapter->ahw->fw_hal_version);
146662306a36Sopenharmony_ci		} else if (priv_level == QLCNIC_PRIV_FUNC) {
146762306a36Sopenharmony_ci			adapter->ahw->op_mode = QLCNIC_PRIV_FUNC;
146862306a36Sopenharmony_ci			dev_info(&adapter->pdev->dev,
146962306a36Sopenharmony_ci				"HAL Version: %d, Privileged function\n",
147062306a36Sopenharmony_ci				 adapter->ahw->fw_hal_version);
147162306a36Sopenharmony_ci		}
147262306a36Sopenharmony_ci	} else {
147362306a36Sopenharmony_ci		adapter->ahw->nic_mode = QLCNIC_DEFAULT_MODE;
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	return err;
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ciint qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
148262306a36Sopenharmony_ci{
148362306a36Sopenharmony_ci	struct qlcnic_esw_func_cfg esw_cfg;
148462306a36Sopenharmony_ci	struct qlcnic_npar_info *npar;
148562306a36Sopenharmony_ci	u8 i;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (adapter->need_fw_reset)
148862306a36Sopenharmony_ci		return 0;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	for (i = 0; i < adapter->ahw->total_nic_func; i++) {
149162306a36Sopenharmony_ci		if (!adapter->npars[i].eswitch_status)
149262306a36Sopenharmony_ci			continue;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci		memset(&esw_cfg, 0, sizeof(struct qlcnic_esw_func_cfg));
149562306a36Sopenharmony_ci		esw_cfg.pci_func = adapter->npars[i].pci_func;
149662306a36Sopenharmony_ci		esw_cfg.mac_override = BIT_0;
149762306a36Sopenharmony_ci		esw_cfg.promisc_mode = BIT_0;
149862306a36Sopenharmony_ci		if (qlcnic_82xx_check(adapter)) {
149962306a36Sopenharmony_ci			esw_cfg.offload_flags = BIT_0;
150062306a36Sopenharmony_ci			if (QLCNIC_IS_TSO_CAPABLE(adapter))
150162306a36Sopenharmony_ci				esw_cfg.offload_flags |= (BIT_1 | BIT_2);
150262306a36Sopenharmony_ci		}
150362306a36Sopenharmony_ci		if (qlcnic_config_switch_port(adapter, &esw_cfg))
150462306a36Sopenharmony_ci			return -EIO;
150562306a36Sopenharmony_ci		npar = &adapter->npars[i];
150662306a36Sopenharmony_ci		npar->pvid = esw_cfg.vlan_id;
150762306a36Sopenharmony_ci		npar->mac_override = esw_cfg.mac_override;
150862306a36Sopenharmony_ci		npar->mac_anti_spoof = esw_cfg.mac_anti_spoof;
150962306a36Sopenharmony_ci		npar->discard_tagged = esw_cfg.discard_tagged;
151062306a36Sopenharmony_ci		npar->promisc_mode = esw_cfg.promisc_mode;
151162306a36Sopenharmony_ci		npar->offload_flags = esw_cfg.offload_flags;
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	return 0;
151562306a36Sopenharmony_ci}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_cistatic int
151962306a36Sopenharmony_ciqlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
152062306a36Sopenharmony_ci			struct qlcnic_npar_info *npar, int pci_func)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	struct qlcnic_esw_func_cfg esw_cfg;
152362306a36Sopenharmony_ci	esw_cfg.op_mode = QLCNIC_PORT_DEFAULTS;
152462306a36Sopenharmony_ci	esw_cfg.pci_func = pci_func;
152562306a36Sopenharmony_ci	esw_cfg.vlan_id = npar->pvid;
152662306a36Sopenharmony_ci	esw_cfg.mac_override = npar->mac_override;
152762306a36Sopenharmony_ci	esw_cfg.discard_tagged = npar->discard_tagged;
152862306a36Sopenharmony_ci	esw_cfg.mac_anti_spoof = npar->mac_anti_spoof;
152962306a36Sopenharmony_ci	esw_cfg.offload_flags = npar->offload_flags;
153062306a36Sopenharmony_ci	esw_cfg.promisc_mode = npar->promisc_mode;
153162306a36Sopenharmony_ci	if (qlcnic_config_switch_port(adapter, &esw_cfg))
153262306a36Sopenharmony_ci		return -EIO;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	esw_cfg.op_mode = QLCNIC_ADD_VLAN;
153562306a36Sopenharmony_ci	if (qlcnic_config_switch_port(adapter, &esw_cfg))
153662306a36Sopenharmony_ci		return -EIO;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	return 0;
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ciint qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
154262306a36Sopenharmony_ci{
154362306a36Sopenharmony_ci	int i, err;
154462306a36Sopenharmony_ci	struct qlcnic_npar_info *npar;
154562306a36Sopenharmony_ci	struct qlcnic_info nic_info;
154662306a36Sopenharmony_ci	u8 pci_func;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
154962306a36Sopenharmony_ci		if (!adapter->need_fw_reset)
155062306a36Sopenharmony_ci			return 0;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	/* Set the NPAR config data after FW reset */
155362306a36Sopenharmony_ci	for (i = 0; i < adapter->ahw->total_nic_func; i++) {
155462306a36Sopenharmony_ci		npar = &adapter->npars[i];
155562306a36Sopenharmony_ci		pci_func = npar->pci_func;
155662306a36Sopenharmony_ci		if (!adapter->npars[i].eswitch_status)
155762306a36Sopenharmony_ci			continue;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci		memset(&nic_info, 0, sizeof(struct qlcnic_info));
156062306a36Sopenharmony_ci		err = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
156162306a36Sopenharmony_ci		if (err)
156262306a36Sopenharmony_ci			return err;
156362306a36Sopenharmony_ci		nic_info.min_tx_bw = npar->min_bw;
156462306a36Sopenharmony_ci		nic_info.max_tx_bw = npar->max_bw;
156562306a36Sopenharmony_ci		err = qlcnic_set_nic_info(adapter, &nic_info);
156662306a36Sopenharmony_ci		if (err)
156762306a36Sopenharmony_ci			return err;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci		if (npar->enable_pm) {
157062306a36Sopenharmony_ci			err = qlcnic_config_port_mirroring(adapter,
157162306a36Sopenharmony_ci							   npar->dest_npar, 1,
157262306a36Sopenharmony_ci							   pci_func);
157362306a36Sopenharmony_ci			if (err)
157462306a36Sopenharmony_ci				return err;
157562306a36Sopenharmony_ci		}
157662306a36Sopenharmony_ci		err = qlcnic_reset_eswitch_config(adapter, npar, pci_func);
157762306a36Sopenharmony_ci		if (err)
157862306a36Sopenharmony_ci			return err;
157962306a36Sopenharmony_ci	}
158062306a36Sopenharmony_ci	return 0;
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_cistatic int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	u8 npar_opt_timeo = QLCNIC_DEV_NPAR_OPER_TIMEO;
158662306a36Sopenharmony_ci	u32 npar_state;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
158962306a36Sopenharmony_ci		return 0;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	npar_state = QLC_SHARED_REG_RD32(adapter,
159262306a36Sopenharmony_ci					 QLCNIC_CRB_DEV_NPAR_STATE);
159362306a36Sopenharmony_ci	while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
159462306a36Sopenharmony_ci		msleep(1000);
159562306a36Sopenharmony_ci		npar_state = QLC_SHARED_REG_RD32(adapter,
159662306a36Sopenharmony_ci						 QLCNIC_CRB_DEV_NPAR_STATE);
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci	if (!npar_opt_timeo) {
159962306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
160062306a36Sopenharmony_ci			"Waiting for NPAR state to operational timeout\n");
160162306a36Sopenharmony_ci		return -EIO;
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci	return 0;
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistatic int
160762306a36Sopenharmony_ciqlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	int err;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
161262306a36Sopenharmony_ci	    adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
161362306a36Sopenharmony_ci		return 0;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	err = qlcnic_set_default_offload_settings(adapter);
161662306a36Sopenharmony_ci	if (err)
161762306a36Sopenharmony_ci		return err;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	err = qlcnic_reset_npar_config(adapter);
162062306a36Sopenharmony_ci	if (err)
162162306a36Sopenharmony_ci		return err;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	qlcnic_dev_set_npar_ready(adapter);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	return err;
162662306a36Sopenharmony_ci}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_cistatic int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	int err;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	err = qlcnic_can_start_firmware(adapter);
163362306a36Sopenharmony_ci	if (err < 0)
163462306a36Sopenharmony_ci		return err;
163562306a36Sopenharmony_ci	else if (!err)
163662306a36Sopenharmony_ci		goto check_fw_status;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	if (qlcnic_load_fw_file)
163962306a36Sopenharmony_ci		qlcnic_request_firmware(adapter);
164062306a36Sopenharmony_ci	else {
164162306a36Sopenharmony_ci		err = qlcnic_check_flash_fw_ver(adapter);
164262306a36Sopenharmony_ci		if (err)
164362306a36Sopenharmony_ci			goto err_out;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		adapter->ahw->fw_type = QLCNIC_FLASH_ROMIMAGE;
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	err = qlcnic_need_fw_reset(adapter);
164962306a36Sopenharmony_ci	if (err == 0)
165062306a36Sopenharmony_ci		goto check_fw_status;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	err = qlcnic_pinit_from_rom(adapter);
165362306a36Sopenharmony_ci	if (err)
165462306a36Sopenharmony_ci		goto err_out;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	err = qlcnic_load_firmware(adapter);
165762306a36Sopenharmony_ci	if (err)
165862306a36Sopenharmony_ci		goto err_out;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	qlcnic_release_firmware(adapter);
166162306a36Sopenharmony_ci	QLCWR32(adapter, CRB_DRIVER_VERSION, QLCNIC_DRIVER_VERSION);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_cicheck_fw_status:
166462306a36Sopenharmony_ci	err = qlcnic_check_fw_status(adapter);
166562306a36Sopenharmony_ci	if (err)
166662306a36Sopenharmony_ci		goto err_out;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
166962306a36Sopenharmony_ci	qlcnic_idc_debug_info(adapter, 1);
167062306a36Sopenharmony_ci	err = qlcnic_check_eswitch_mode(adapter);
167162306a36Sopenharmony_ci	if (err) {
167262306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
167362306a36Sopenharmony_ci			"Memory allocation failed for eswitch\n");
167462306a36Sopenharmony_ci		goto err_out;
167562306a36Sopenharmony_ci	}
167662306a36Sopenharmony_ci	err = qlcnic_set_mgmt_operations(adapter);
167762306a36Sopenharmony_ci	if (err)
167862306a36Sopenharmony_ci		goto err_out;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	qlcnic_check_options(adapter);
168162306a36Sopenharmony_ci	adapter->need_fw_reset = 0;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	qlcnic_release_firmware(adapter);
168462306a36Sopenharmony_ci	return 0;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_cierr_out:
168762306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
168862306a36Sopenharmony_ci	dev_err(&adapter->pdev->dev, "Device state set to failed\n");
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	qlcnic_release_firmware(adapter);
169162306a36Sopenharmony_ci	return err;
169262306a36Sopenharmony_ci}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic int
169562306a36Sopenharmony_ciqlcnic_request_irq(struct qlcnic_adapter *adapter)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	irq_handler_t handler;
169862306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring;
169962306a36Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring;
170062306a36Sopenharmony_ci	int err, ring, num_sds_rings;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	unsigned long flags = 0;
170362306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
170462306a36Sopenharmony_ci	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
170762306a36Sopenharmony_ci		if (qlcnic_82xx_check(adapter))
170862306a36Sopenharmony_ci			handler = qlcnic_tmp_intr;
170962306a36Sopenharmony_ci		else
171062306a36Sopenharmony_ci			handler = qlcnic_83xx_tmp_intr;
171162306a36Sopenharmony_ci		if (!QLCNIC_IS_MSI_FAMILY(adapter))
171262306a36Sopenharmony_ci			flags |= IRQF_SHARED;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	} else {
171562306a36Sopenharmony_ci		if (adapter->flags & QLCNIC_MSIX_ENABLED)
171662306a36Sopenharmony_ci			handler = qlcnic_msix_intr;
171762306a36Sopenharmony_ci		else if (adapter->flags & QLCNIC_MSI_ENABLED)
171862306a36Sopenharmony_ci			handler = qlcnic_msi_intr;
171962306a36Sopenharmony_ci		else {
172062306a36Sopenharmony_ci			flags |= IRQF_SHARED;
172162306a36Sopenharmony_ci			if (qlcnic_82xx_check(adapter))
172262306a36Sopenharmony_ci				handler = qlcnic_intr;
172362306a36Sopenharmony_ci			else
172462306a36Sopenharmony_ci				handler = qlcnic_83xx_intr;
172562306a36Sopenharmony_ci		}
172662306a36Sopenharmony_ci	}
172762306a36Sopenharmony_ci	adapter->irq = netdev->irq;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
173062306a36Sopenharmony_ci		if (qlcnic_82xx_check(adapter) ||
173162306a36Sopenharmony_ci		    (qlcnic_83xx_check(adapter) &&
173262306a36Sopenharmony_ci		     (adapter->flags & QLCNIC_MSIX_ENABLED))) {
173362306a36Sopenharmony_ci			num_sds_rings = adapter->drv_sds_rings;
173462306a36Sopenharmony_ci			for (ring = 0; ring < num_sds_rings; ring++) {
173562306a36Sopenharmony_ci				sds_ring = &recv_ctx->sds_rings[ring];
173662306a36Sopenharmony_ci				if (qlcnic_82xx_check(adapter) &&
173762306a36Sopenharmony_ci				    !qlcnic_check_multi_tx(adapter) &&
173862306a36Sopenharmony_ci				    (ring == (num_sds_rings - 1))) {
173962306a36Sopenharmony_ci					if (!(adapter->flags &
174062306a36Sopenharmony_ci					      QLCNIC_MSIX_ENABLED))
174162306a36Sopenharmony_ci						snprintf(sds_ring->name,
174262306a36Sopenharmony_ci							 sizeof(sds_ring->name),
174362306a36Sopenharmony_ci							 "qlcnic");
174462306a36Sopenharmony_ci					else
174562306a36Sopenharmony_ci						snprintf(sds_ring->name,
174662306a36Sopenharmony_ci							 sizeof(sds_ring->name),
174762306a36Sopenharmony_ci							 "%s-tx-0-rx-%d",
174862306a36Sopenharmony_ci							 netdev->name, ring);
174962306a36Sopenharmony_ci				} else {
175062306a36Sopenharmony_ci					snprintf(sds_ring->name,
175162306a36Sopenharmony_ci						 sizeof(sds_ring->name),
175262306a36Sopenharmony_ci						 "%s-rx-%d",
175362306a36Sopenharmony_ci						 netdev->name, ring);
175462306a36Sopenharmony_ci				}
175562306a36Sopenharmony_ci				err = request_irq(sds_ring->irq, handler, flags,
175662306a36Sopenharmony_ci						  sds_ring->name, sds_ring);
175762306a36Sopenharmony_ci				if (err)
175862306a36Sopenharmony_ci					return err;
175962306a36Sopenharmony_ci			}
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci		if ((qlcnic_82xx_check(adapter) &&
176262306a36Sopenharmony_ci		     qlcnic_check_multi_tx(adapter)) ||
176362306a36Sopenharmony_ci		    (qlcnic_83xx_check(adapter) &&
176462306a36Sopenharmony_ci		     (adapter->flags & QLCNIC_MSIX_ENABLED) &&
176562306a36Sopenharmony_ci		     !(adapter->flags & QLCNIC_TX_INTR_SHARED))) {
176662306a36Sopenharmony_ci			handler = qlcnic_msix_tx_intr;
176762306a36Sopenharmony_ci			for (ring = 0; ring < adapter->drv_tx_rings;
176862306a36Sopenharmony_ci			     ring++) {
176962306a36Sopenharmony_ci				tx_ring = &adapter->tx_ring[ring];
177062306a36Sopenharmony_ci				snprintf(tx_ring->name, sizeof(tx_ring->name),
177162306a36Sopenharmony_ci					 "%s-tx-%d", netdev->name, ring);
177262306a36Sopenharmony_ci				err = request_irq(tx_ring->irq, handler, flags,
177362306a36Sopenharmony_ci						  tx_ring->name, tx_ring);
177462306a36Sopenharmony_ci				if (err)
177562306a36Sopenharmony_ci					return err;
177662306a36Sopenharmony_ci			}
177762306a36Sopenharmony_ci		}
177862306a36Sopenharmony_ci	}
177962306a36Sopenharmony_ci	return 0;
178062306a36Sopenharmony_ci}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_cistatic void
178362306a36Sopenharmony_ciqlcnic_free_irq(struct qlcnic_adapter *adapter)
178462306a36Sopenharmony_ci{
178562306a36Sopenharmony_ci	int ring;
178662306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring;
178762306a36Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
179262306a36Sopenharmony_ci		if (qlcnic_82xx_check(adapter) ||
179362306a36Sopenharmony_ci		    (qlcnic_83xx_check(adapter) &&
179462306a36Sopenharmony_ci		     (adapter->flags & QLCNIC_MSIX_ENABLED))) {
179562306a36Sopenharmony_ci			for (ring = 0; ring < adapter->drv_sds_rings; ring++) {
179662306a36Sopenharmony_ci				sds_ring = &recv_ctx->sds_rings[ring];
179762306a36Sopenharmony_ci				free_irq(sds_ring->irq, sds_ring);
179862306a36Sopenharmony_ci			}
179962306a36Sopenharmony_ci		}
180062306a36Sopenharmony_ci		if ((qlcnic_83xx_check(adapter) &&
180162306a36Sopenharmony_ci		     !(adapter->flags & QLCNIC_TX_INTR_SHARED)) ||
180262306a36Sopenharmony_ci		    (qlcnic_82xx_check(adapter) &&
180362306a36Sopenharmony_ci		     qlcnic_check_multi_tx(adapter))) {
180462306a36Sopenharmony_ci			for (ring = 0; ring < adapter->drv_tx_rings;
180562306a36Sopenharmony_ci			     ring++) {
180662306a36Sopenharmony_ci				tx_ring = &adapter->tx_ring[ring];
180762306a36Sopenharmony_ci				if (tx_ring->irq)
180862306a36Sopenharmony_ci					free_irq(tx_ring->irq, tx_ring);
180962306a36Sopenharmony_ci			}
181062306a36Sopenharmony_ci		}
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter)
181562306a36Sopenharmony_ci{
181662306a36Sopenharmony_ci	u32 capab = 0;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter)) {
181962306a36Sopenharmony_ci		if (adapter->ahw->extra_capability[0] &
182062306a36Sopenharmony_ci		    QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
182162306a36Sopenharmony_ci			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
182262306a36Sopenharmony_ci	} else {
182362306a36Sopenharmony_ci		capab = adapter->ahw->capabilities;
182462306a36Sopenharmony_ci		if (QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(capab))
182562306a36Sopenharmony_ci			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
182662306a36Sopenharmony_ci	}
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cistatic int qlcnic_config_def_intr_coalesce(struct qlcnic_adapter *adapter)
183062306a36Sopenharmony_ci{
183162306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
183262306a36Sopenharmony_ci	int err;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	/* Initialize interrupt coalesce parameters */
183562306a36Sopenharmony_ci	ahw->coal.flag = QLCNIC_INTR_DEFAULT;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter)) {
183862306a36Sopenharmony_ci		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX;
183962306a36Sopenharmony_ci		ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
184062306a36Sopenharmony_ci		ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
184162306a36Sopenharmony_ci		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
184262306a36Sopenharmony_ci		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci		err = qlcnic_83xx_set_rx_tx_intr_coal(adapter);
184562306a36Sopenharmony_ci	} else {
184662306a36Sopenharmony_ci		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX;
184762306a36Sopenharmony_ci		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
184862306a36Sopenharmony_ci		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci		err = qlcnic_82xx_set_rx_coalesce(adapter);
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return err;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ciint __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	int ring;
185962306a36Sopenharmony_ci	struct qlcnic_host_rds_ring *rds_ring;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
186262306a36Sopenharmony_ci		return -EIO;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
186562306a36Sopenharmony_ci		return 0;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (qlcnic_set_eswitch_port_config(adapter))
186862306a36Sopenharmony_ci		return -EIO;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	qlcnic_get_lro_mss_capability(adapter);
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	if (qlcnic_fw_create_ctx(adapter))
187362306a36Sopenharmony_ci		return -EIO;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
187662306a36Sopenharmony_ci		rds_ring = &adapter->recv_ctx->rds_rings[ring];
187762306a36Sopenharmony_ci		qlcnic_post_rx_buffers(adapter, rds_ring, ring);
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	qlcnic_set_multi(netdev);
188162306a36Sopenharmony_ci	qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	adapter->ahw->linkup = 0;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	if (adapter->drv_sds_rings > 1)
188662306a36Sopenharmony_ci		qlcnic_config_rss(adapter, 1);
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	qlcnic_config_def_intr_coalesce(adapter);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	if (netdev->features & NETIF_F_LRO)
189162306a36Sopenharmony_ci		qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	set_bit(__QLCNIC_DEV_UP, &adapter->state);
189462306a36Sopenharmony_ci	qlcnic_napi_enable(adapter);
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	qlcnic_linkevent_request(adapter, 1);
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	adapter->ahw->reset_context = 0;
189962306a36Sopenharmony_ci	netif_tx_start_all_queues(netdev);
190062306a36Sopenharmony_ci	return 0;
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ciint qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	int err = 0;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	rtnl_lock();
190862306a36Sopenharmony_ci	if (netif_running(netdev))
190962306a36Sopenharmony_ci		err = __qlcnic_up(adapter, netdev);
191062306a36Sopenharmony_ci	rtnl_unlock();
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	return err;
191362306a36Sopenharmony_ci}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_civoid __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
191662306a36Sopenharmony_ci{
191762306a36Sopenharmony_ci	int ring;
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
192062306a36Sopenharmony_ci		return;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))
192362306a36Sopenharmony_ci		return;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	smp_mb();
192662306a36Sopenharmony_ci	netif_carrier_off(netdev);
192762306a36Sopenharmony_ci	adapter->ahw->linkup = 0;
192862306a36Sopenharmony_ci	netif_tx_disable(netdev);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	qlcnic_free_mac_list(adapter);
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (adapter->fhash.fnum)
193362306a36Sopenharmony_ci		qlcnic_delete_lb_filters(adapter);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
193662306a36Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter))
193762306a36Sopenharmony_ci		qlcnic_sriov_cleanup_async_list(&adapter->ahw->sriov->bc);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	qlcnic_napi_disable(adapter);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	qlcnic_fw_destroy_ctx(adapter);
194262306a36Sopenharmony_ci	adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	qlcnic_reset_rx_buffers_list(adapter);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	for (ring = 0; ring < adapter->drv_tx_rings; ring++)
194762306a36Sopenharmony_ci		qlcnic_release_tx_buffers(adapter, &adapter->tx_ring[ring]);
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci/* Usage: During suspend and firmware recovery module */
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_civoid qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	rtnl_lock();
195562306a36Sopenharmony_ci	if (netif_running(netdev))
195662306a36Sopenharmony_ci		__qlcnic_down(adapter, netdev);
195762306a36Sopenharmony_ci	rtnl_unlock();
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ciint
196262306a36Sopenharmony_ciqlcnic_attach(struct qlcnic_adapter *adapter)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
196562306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
196662306a36Sopenharmony_ci	int err;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
196962306a36Sopenharmony_ci		return 0;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	err = qlcnic_napi_add(adapter, netdev);
197262306a36Sopenharmony_ci	if (err)
197362306a36Sopenharmony_ci		return err;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	err = qlcnic_alloc_sw_resources(adapter);
197662306a36Sopenharmony_ci	if (err) {
197762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Error in setting sw resources\n");
197862306a36Sopenharmony_ci		goto err_out_napi_del;
197962306a36Sopenharmony_ci	}
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	err = qlcnic_alloc_hw_resources(adapter);
198262306a36Sopenharmony_ci	if (err) {
198362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Error in setting hw resources\n");
198462306a36Sopenharmony_ci		goto err_out_free_sw;
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	err = qlcnic_request_irq(adapter);
198862306a36Sopenharmony_ci	if (err) {
198962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to setup interrupt\n");
199062306a36Sopenharmony_ci		goto err_out_free_hw;
199162306a36Sopenharmony_ci	}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	qlcnic_create_sysfs_entries(adapter);
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	if (qlcnic_encap_rx_offload(adapter))
199662306a36Sopenharmony_ci		udp_tunnel_nic_reset_ntf(netdev);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
199962306a36Sopenharmony_ci	return 0;
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_cierr_out_free_hw:
200262306a36Sopenharmony_ci	qlcnic_free_hw_resources(adapter);
200362306a36Sopenharmony_cierr_out_free_sw:
200462306a36Sopenharmony_ci	qlcnic_free_sw_resources(adapter);
200562306a36Sopenharmony_cierr_out_napi_del:
200662306a36Sopenharmony_ci	qlcnic_napi_del(adapter);
200762306a36Sopenharmony_ci	return err;
200862306a36Sopenharmony_ci}
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_civoid qlcnic_detach(struct qlcnic_adapter *adapter)
201162306a36Sopenharmony_ci{
201262306a36Sopenharmony_ci	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
201362306a36Sopenharmony_ci		return;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	qlcnic_remove_sysfs_entries(adapter);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	qlcnic_free_hw_resources(adapter);
201862306a36Sopenharmony_ci	qlcnic_release_rx_buffers(adapter);
201962306a36Sopenharmony_ci	qlcnic_free_irq(adapter);
202062306a36Sopenharmony_ci	qlcnic_napi_del(adapter);
202162306a36Sopenharmony_ci	qlcnic_free_sw_resources(adapter);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	adapter->is_up = 0;
202462306a36Sopenharmony_ci}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_civoid qlcnic_diag_free_res(struct net_device *netdev, int drv_sds_rings)
202762306a36Sopenharmony_ci{
202862306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
202962306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring;
203062306a36Sopenharmony_ci	int drv_tx_rings = adapter->drv_tx_rings;
203162306a36Sopenharmony_ci	int ring;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	clear_bit(__QLCNIC_DEV_UP, &adapter->state);
203462306a36Sopenharmony_ci	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
203562306a36Sopenharmony_ci		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {
203662306a36Sopenharmony_ci			sds_ring = &adapter->recv_ctx->sds_rings[ring];
203762306a36Sopenharmony_ci			qlcnic_disable_sds_intr(adapter, sds_ring);
203862306a36Sopenharmony_ci		}
203962306a36Sopenharmony_ci	}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	qlcnic_fw_destroy_ctx(adapter);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	qlcnic_detach(adapter);
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	adapter->ahw->diag_test = 0;
204662306a36Sopenharmony_ci	adapter->drv_sds_rings = drv_sds_rings;
204762306a36Sopenharmony_ci	adapter->drv_tx_rings = drv_tx_rings;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	if (qlcnic_attach(adapter))
205062306a36Sopenharmony_ci		goto out;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	if (netif_running(netdev))
205362306a36Sopenharmony_ci		__qlcnic_up(adapter, netdev);
205462306a36Sopenharmony_ciout:
205562306a36Sopenharmony_ci	netif_device_attach(netdev);
205662306a36Sopenharmony_ci}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_cistatic int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
205962306a36Sopenharmony_ci{
206062306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
206162306a36Sopenharmony_ci	int err = 0;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
206462306a36Sopenharmony_ci				GFP_KERNEL);
206562306a36Sopenharmony_ci	if (!adapter->recv_ctx) {
206662306a36Sopenharmony_ci		err = -ENOMEM;
206762306a36Sopenharmony_ci		goto err_out;
206862306a36Sopenharmony_ci	}
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter)) {
207162306a36Sopenharmony_ci		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX;
207262306a36Sopenharmony_ci		ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
207362306a36Sopenharmony_ci		ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
207462306a36Sopenharmony_ci		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
207562306a36Sopenharmony_ci		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
207662306a36Sopenharmony_ci	} else {
207762306a36Sopenharmony_ci		ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX;
207862306a36Sopenharmony_ci		ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
207962306a36Sopenharmony_ci		ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
208062306a36Sopenharmony_ci	}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	/* clear stats */
208362306a36Sopenharmony_ci	memset(&adapter->stats, 0, sizeof(adapter->stats));
208462306a36Sopenharmony_cierr_out:
208562306a36Sopenharmony_ci	return err;
208662306a36Sopenharmony_ci}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_cistatic void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter)
208962306a36Sopenharmony_ci{
209062306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	kfree(adapter->recv_ctx);
209362306a36Sopenharmony_ci	adapter->recv_ctx = NULL;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	if (fw_dump->tmpl_hdr) {
209662306a36Sopenharmony_ci		vfree(fw_dump->tmpl_hdr);
209762306a36Sopenharmony_ci		fw_dump->tmpl_hdr = NULL;
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	if (fw_dump->dma_buffer) {
210162306a36Sopenharmony_ci		dma_free_coherent(&adapter->pdev->dev, QLC_PEX_DMA_READ_SIZE,
210262306a36Sopenharmony_ci				  fw_dump->dma_buffer, fw_dump->phys_addr);
210362306a36Sopenharmony_ci		fw_dump->dma_buffer = NULL;
210462306a36Sopenharmony_ci	}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	kfree(adapter->ahw->reset.buff);
210762306a36Sopenharmony_ci	adapter->ahw->fw_dump.tmpl_hdr = NULL;
210862306a36Sopenharmony_ci}
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ciint qlcnic_diag_alloc_res(struct net_device *netdev, int test)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
211362306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring;
211462306a36Sopenharmony_ci	struct qlcnic_host_rds_ring *rds_ring;
211562306a36Sopenharmony_ci	int ring;
211662306a36Sopenharmony_ci	int ret;
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	netif_device_detach(netdev);
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	if (netif_running(netdev))
212162306a36Sopenharmony_ci		__qlcnic_down(adapter, netdev);
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	qlcnic_detach(adapter);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
212662306a36Sopenharmony_ci	adapter->ahw->diag_test = test;
212762306a36Sopenharmony_ci	adapter->ahw->linkup = 0;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	ret = qlcnic_attach(adapter);
213062306a36Sopenharmony_ci	if (ret) {
213162306a36Sopenharmony_ci		netif_device_attach(netdev);
213262306a36Sopenharmony_ci		return ret;
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	ret = qlcnic_fw_create_ctx(adapter);
213662306a36Sopenharmony_ci	if (ret) {
213762306a36Sopenharmony_ci		qlcnic_detach(adapter);
213862306a36Sopenharmony_ci		netif_device_attach(netdev);
213962306a36Sopenharmony_ci		return ret;
214062306a36Sopenharmony_ci	}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
214362306a36Sopenharmony_ci		rds_ring = &adapter->recv_ctx->rds_rings[ring];
214462306a36Sopenharmony_ci		qlcnic_post_rx_buffers(adapter, rds_ring, ring);
214562306a36Sopenharmony_ci	}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
214862306a36Sopenharmony_ci		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {
214962306a36Sopenharmony_ci			sds_ring = &adapter->recv_ctx->sds_rings[ring];
215062306a36Sopenharmony_ci			qlcnic_enable_sds_intr(adapter, sds_ring);
215162306a36Sopenharmony_ci		}
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
215562306a36Sopenharmony_ci		adapter->ahw->loopback_state = 0;
215662306a36Sopenharmony_ci		qlcnic_linkevent_request(adapter, 1);
215762306a36Sopenharmony_ci	}
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	set_bit(__QLCNIC_DEV_UP, &adapter->state);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	return 0;
216262306a36Sopenharmony_ci}
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci/* Reset context in hardware only */
216562306a36Sopenharmony_cistatic int
216662306a36Sopenharmony_ciqlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
216762306a36Sopenharmony_ci{
216862306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
217162306a36Sopenharmony_ci		return -EBUSY;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	netif_device_detach(netdev);
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	qlcnic_down(adapter, netdev);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	qlcnic_up(adapter, netdev);
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	netif_device_attach(netdev);
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
218262306a36Sopenharmony_ci	netdev_info(adapter->netdev, "%s: soft reset complete\n", __func__);
218362306a36Sopenharmony_ci	return 0;
218462306a36Sopenharmony_ci}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ciint
218762306a36Sopenharmony_ciqlcnic_reset_context(struct qlcnic_adapter *adapter)
218862306a36Sopenharmony_ci{
218962306a36Sopenharmony_ci	int err = 0;
219062306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
219362306a36Sopenharmony_ci		return -EBUSY;
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci	if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) {
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci		netif_device_detach(netdev);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci		if (netif_running(netdev))
220062306a36Sopenharmony_ci			__qlcnic_down(adapter, netdev);
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci		qlcnic_detach(adapter);
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci		if (netif_running(netdev)) {
220562306a36Sopenharmony_ci			err = qlcnic_attach(adapter);
220662306a36Sopenharmony_ci			if (!err) {
220762306a36Sopenharmony_ci				__qlcnic_up(adapter, netdev);
220862306a36Sopenharmony_ci				qlcnic_restore_indev_addr(netdev, NETDEV_UP);
220962306a36Sopenharmony_ci			}
221062306a36Sopenharmony_ci		}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci		netif_device_attach(netdev);
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
221662306a36Sopenharmony_ci	return err;
221762306a36Sopenharmony_ci}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_cistatic void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter)
222062306a36Sopenharmony_ci{
222162306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
222262306a36Sopenharmony_ci	u16 act_pci_fn = ahw->total_nic_func;
222362306a36Sopenharmony_ci	u16 count;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
222662306a36Sopenharmony_ci	if (act_pci_fn <= 2)
222762306a36Sopenharmony_ci		count = (QLCNIC_MAX_UC_COUNT - QLCNIC_MAX_MC_COUNT) /
222862306a36Sopenharmony_ci			 act_pci_fn;
222962306a36Sopenharmony_ci	else
223062306a36Sopenharmony_ci		count = (QLCNIC_LB_MAX_FILTERS - QLCNIC_MAX_MC_COUNT) /
223162306a36Sopenharmony_ci			 act_pci_fn;
223262306a36Sopenharmony_ci	ahw->max_uc_count = count;
223362306a36Sopenharmony_ci}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_cistatic int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter,
223662306a36Sopenharmony_ci				      u8 tx_queues, u8 rx_queues)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
223962306a36Sopenharmony_ci	int err = 0;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	if (tx_queues) {
224262306a36Sopenharmony_ci		err = netif_set_real_num_tx_queues(netdev, tx_queues);
224362306a36Sopenharmony_ci		if (err) {
224462306a36Sopenharmony_ci			netdev_err(netdev, "failed to set %d Tx queues\n",
224562306a36Sopenharmony_ci				   tx_queues);
224662306a36Sopenharmony_ci			return err;
224762306a36Sopenharmony_ci		}
224862306a36Sopenharmony_ci	}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	if (rx_queues) {
225162306a36Sopenharmony_ci		err = netif_set_real_num_rx_queues(netdev, rx_queues);
225262306a36Sopenharmony_ci		if (err)
225362306a36Sopenharmony_ci			netdev_err(netdev, "failed to set %d Rx queues\n",
225462306a36Sopenharmony_ci				   rx_queues);
225562306a36Sopenharmony_ci	}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	return err;
225862306a36Sopenharmony_ci}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ciint
226162306a36Sopenharmony_ciqlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev)
226262306a36Sopenharmony_ci{
226362306a36Sopenharmony_ci	int err;
226462306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	adapter->rx_csum = 1;
226762306a36Sopenharmony_ci	adapter->ahw->mc_enabled = 0;
226862306a36Sopenharmony_ci	qlcnic_set_mac_filter_count(adapter);
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	netdev->netdev_ops	   = &qlcnic_netdev_ops;
227162306a36Sopenharmony_ci	netdev->watchdog_timeo     = QLCNIC_WATCHDOG_TIMEOUTVALUE * HZ;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	qlcnic_change_mtu(netdev, netdev->mtu);
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	netdev->ethtool_ops = (qlcnic_sriov_vf_check(adapter)) ?
227662306a36Sopenharmony_ci		&qlcnic_sriov_vf_ethtool_ops : &qlcnic_ethtool_ops;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
227962306a36Sopenharmony_ci			     NETIF_F_IPV6_CSUM | NETIF_F_GRO |
228062306a36Sopenharmony_ci			     NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HIGHDMA);
228162306a36Sopenharmony_ci	netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
228262306a36Sopenharmony_ci				  NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA);
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
228562306a36Sopenharmony_ci		netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
228662306a36Sopenharmony_ci		netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
228762306a36Sopenharmony_ci	}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	if (qlcnic_vlan_tx_check(adapter))
229062306a36Sopenharmony_ci		netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter))
229362306a36Sopenharmony_ci		netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
229662306a36Sopenharmony_ci		netdev->features |= NETIF_F_LRO;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	if (qlcnic_encap_tx_offload(adapter)) {
229962306a36Sopenharmony_ci		netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci		/* encapsulation Tx offload supported by Adapter */
230262306a36Sopenharmony_ci		netdev->hw_enc_features = NETIF_F_IP_CSUM        |
230362306a36Sopenharmony_ci					  NETIF_F_GSO_UDP_TUNNEL |
230462306a36Sopenharmony_ci					  NETIF_F_TSO            |
230562306a36Sopenharmony_ci					  NETIF_F_TSO6;
230662306a36Sopenharmony_ci	}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	if (qlcnic_encap_rx_offload(adapter)) {
230962306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_RXCSUM;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci		netdev->udp_tunnel_nic_info = &qlcnic_udp_tunnels;
231262306a36Sopenharmony_ci	}
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	netdev->hw_features = netdev->features;
231562306a36Sopenharmony_ci	netdev->priv_flags |= IFF_UNICAST_FLT;
231662306a36Sopenharmony_ci	netdev->irq = adapter->msix_entries[0].vector;
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	/* MTU range: 68 - 9600 */
231962306a36Sopenharmony_ci	netdev->min_mtu = P3P_MIN_MTU;
232062306a36Sopenharmony_ci	netdev->max_mtu = P3P_MAX_MTU;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	err = qlcnic_set_real_num_queues(adapter, adapter->drv_tx_rings,
232362306a36Sopenharmony_ci					 adapter->drv_sds_rings);
232462306a36Sopenharmony_ci	if (err)
232562306a36Sopenharmony_ci		return err;
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	qlcnic_dcb_init_dcbnl_ops(adapter->dcb);
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	err = register_netdev(netdev);
233062306a36Sopenharmony_ci	if (err) {
233162306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to register net device\n");
233262306a36Sopenharmony_ci		return err;
233362306a36Sopenharmony_ci	}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	return 0;
233662306a36Sopenharmony_ci}
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_civoid qlcnic_free_tx_rings(struct qlcnic_adapter *adapter)
233962306a36Sopenharmony_ci{
234062306a36Sopenharmony_ci	int ring;
234162306a36Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	for (ring = 0; ring < adapter->drv_tx_rings; ring++) {
234462306a36Sopenharmony_ci		tx_ring = &adapter->tx_ring[ring];
234562306a36Sopenharmony_ci		if (tx_ring) {
234662306a36Sopenharmony_ci			vfree(tx_ring->cmd_buf_arr);
234762306a36Sopenharmony_ci			tx_ring->cmd_buf_arr = NULL;
234862306a36Sopenharmony_ci		}
234962306a36Sopenharmony_ci	}
235062306a36Sopenharmony_ci	kfree(adapter->tx_ring);
235162306a36Sopenharmony_ci}
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ciint qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
235462306a36Sopenharmony_ci			  struct net_device *netdev)
235562306a36Sopenharmony_ci{
235662306a36Sopenharmony_ci	int ring, vector, index;
235762306a36Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring;
235862306a36Sopenharmony_ci	struct qlcnic_cmd_buffer *cmd_buf_arr;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	tx_ring = kcalloc(adapter->drv_tx_rings,
236162306a36Sopenharmony_ci			  sizeof(struct qlcnic_host_tx_ring), GFP_KERNEL);
236262306a36Sopenharmony_ci	if (tx_ring == NULL)
236362306a36Sopenharmony_ci		return -ENOMEM;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	adapter->tx_ring = tx_ring;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	for (ring = 0; ring < adapter->drv_tx_rings; ring++) {
236862306a36Sopenharmony_ci		tx_ring = &adapter->tx_ring[ring];
236962306a36Sopenharmony_ci		tx_ring->num_desc = adapter->num_txd;
237062306a36Sopenharmony_ci		tx_ring->txq = netdev_get_tx_queue(netdev, ring);
237162306a36Sopenharmony_ci		cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
237262306a36Sopenharmony_ci		if (cmd_buf_arr == NULL) {
237362306a36Sopenharmony_ci			qlcnic_free_tx_rings(adapter);
237462306a36Sopenharmony_ci			return -ENOMEM;
237562306a36Sopenharmony_ci		}
237662306a36Sopenharmony_ci		tx_ring->cmd_buf_arr = cmd_buf_arr;
237762306a36Sopenharmony_ci		spin_lock_init(&tx_ring->tx_clean_lock);
237862306a36Sopenharmony_ci	}
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter) ||
238162306a36Sopenharmony_ci	    (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter))) {
238262306a36Sopenharmony_ci		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {
238362306a36Sopenharmony_ci			tx_ring = &adapter->tx_ring[ring];
238462306a36Sopenharmony_ci			tx_ring->adapter = adapter;
238562306a36Sopenharmony_ci			if (adapter->flags & QLCNIC_MSIX_ENABLED) {
238662306a36Sopenharmony_ci				index = adapter->drv_sds_rings + ring;
238762306a36Sopenharmony_ci				vector = adapter->msix_entries[index].vector;
238862306a36Sopenharmony_ci				tx_ring->irq = vector;
238962306a36Sopenharmony_ci			}
239062306a36Sopenharmony_ci		}
239162306a36Sopenharmony_ci	}
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	return 0;
239462306a36Sopenharmony_ci}
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_civoid qlcnic_set_drv_version(struct qlcnic_adapter *adapter)
239762306a36Sopenharmony_ci{
239862306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
239962306a36Sopenharmony_ci	u32 fw_cmd = 0;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
240262306a36Sopenharmony_ci		fw_cmd = QLCNIC_CMD_82XX_SET_DRV_VER;
240362306a36Sopenharmony_ci	else if (qlcnic_83xx_check(adapter))
240462306a36Sopenharmony_ci		fw_cmd = QLCNIC_CMD_83XX_SET_DRV_VER;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_SET_DRV_VER)
240762306a36Sopenharmony_ci		qlcnic_fw_cmd_set_drv_version(adapter, fw_cmd);
240862306a36Sopenharmony_ci}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci/* Reset firmware API lock */
241162306a36Sopenharmony_cistatic void qlcnic_reset_api_lock(struct qlcnic_adapter *adapter)
241262306a36Sopenharmony_ci{
241362306a36Sopenharmony_ci	qlcnic_api_lock(adapter);
241462306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
241562306a36Sopenharmony_ci}
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_cistatic int
241962306a36Sopenharmony_ciqlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
242062306a36Sopenharmony_ci{
242162306a36Sopenharmony_ci	struct net_device *netdev = NULL;
242262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = NULL;
242362306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw;
242462306a36Sopenharmony_ci	char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */
242562306a36Sopenharmony_ci	int err;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	err = pci_enable_device(pdev);
242862306a36Sopenharmony_ci	if (err)
242962306a36Sopenharmony_ci		return err;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
243262306a36Sopenharmony_ci		err = -ENODEV;
243362306a36Sopenharmony_ci		goto err_out_disable_pdev;
243462306a36Sopenharmony_ci	}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
243762306a36Sopenharmony_ci	if (err) {
243862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unable to set DMA mask, aborting\n");
243962306a36Sopenharmony_ci		goto err_out_disable_pdev;
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	err = pci_request_regions(pdev, qlcnic_driver_name);
244362306a36Sopenharmony_ci	if (err)
244462306a36Sopenharmony_ci		goto err_out_disable_pdev;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	pci_set_master(pdev);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL);
244962306a36Sopenharmony_ci	if (!ahw) {
245062306a36Sopenharmony_ci		err = -ENOMEM;
245162306a36Sopenharmony_ci		goto err_out_free_res;
245262306a36Sopenharmony_ci	}
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	switch (ent->device) {
245562306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE824X:
245662306a36Sopenharmony_ci		ahw->hw_ops = &qlcnic_hw_ops;
245762306a36Sopenharmony_ci		ahw->reg_tbl = (u32 *) qlcnic_reg_tbl;
245862306a36Sopenharmony_ci		break;
245962306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE834X:
246062306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE8830:
246162306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_QLE844X:
246262306a36Sopenharmony_ci		qlcnic_83xx_register_map(ahw);
246362306a36Sopenharmony_ci		break;
246462306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_VF_QLE834X:
246562306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_VF_QLE8C30:
246662306a36Sopenharmony_ci	case PCI_DEVICE_ID_QLOGIC_VF_QLE844X:
246762306a36Sopenharmony_ci		qlcnic_sriov_vf_register_map(ahw);
246862306a36Sopenharmony_ci		break;
246962306a36Sopenharmony_ci	default:
247062306a36Sopenharmony_ci		err = -EINVAL;
247162306a36Sopenharmony_ci		goto err_out_free_hw_res;
247262306a36Sopenharmony_ci	}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	err = qlcnic_setup_pci_map(pdev, ahw);
247562306a36Sopenharmony_ci	if (err)
247662306a36Sopenharmony_ci		goto err_out_free_hw_res;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	netdev = alloc_etherdev_mq(sizeof(struct qlcnic_adapter),
247962306a36Sopenharmony_ci				   QLCNIC_MAX_TX_RINGS);
248062306a36Sopenharmony_ci	if (!netdev) {
248162306a36Sopenharmony_ci		err = -ENOMEM;
248262306a36Sopenharmony_ci		goto err_out_iounmap;
248362306a36Sopenharmony_ci	}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	adapter = netdev_priv(netdev);
248862306a36Sopenharmony_ci	adapter->netdev  = netdev;
248962306a36Sopenharmony_ci	adapter->pdev    = pdev;
249062306a36Sopenharmony_ci	adapter->ahw = ahw;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic");
249362306a36Sopenharmony_ci	if (adapter->qlcnic_wq == NULL) {
249462306a36Sopenharmony_ci		err = -ENOMEM;
249562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to create workqueue\n");
249662306a36Sopenharmony_ci		goto err_out_free_netdev;
249762306a36Sopenharmony_ci	}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	err = qlcnic_alloc_adapter_resources(adapter);
250062306a36Sopenharmony_ci	if (err)
250162306a36Sopenharmony_ci		goto err_out_free_wq;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	adapter->dev_rst_time = jiffies;
250462306a36Sopenharmony_ci	ahw->revision_id = pdev->revision;
250562306a36Sopenharmony_ci	ahw->max_vnic_func = qlcnic_get_vnic_func_count(adapter);
250662306a36Sopenharmony_ci	if (qlcnic_mac_learn == FDB_MAC_LEARN)
250762306a36Sopenharmony_ci		adapter->fdb_mac_learn = true;
250862306a36Sopenharmony_ci	else if (qlcnic_mac_learn == DRV_MAC_LEARN)
250962306a36Sopenharmony_ci		adapter->drv_mac_learn = true;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	rwlock_init(&adapter->ahw->crb_lock);
251262306a36Sopenharmony_ci	mutex_init(&adapter->ahw->mem_lock);
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	INIT_LIST_HEAD(&adapter->mac_list);
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	qlcnic_register_dcb(adapter);
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter)) {
251962306a36Sopenharmony_ci		qlcnic_check_vf(adapter, ent);
252062306a36Sopenharmony_ci		adapter->portnum = adapter->ahw->pci_func;
252162306a36Sopenharmony_ci		qlcnic_reset_api_lock(adapter);
252262306a36Sopenharmony_ci		err = qlcnic_start_firmware(adapter);
252362306a36Sopenharmony_ci		if (err) {
252462306a36Sopenharmony_ci			dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"
252562306a36Sopenharmony_ci				"\t\tIf reboot doesn't help, try flashing the card\n");
252662306a36Sopenharmony_ci			goto err_out_maintenance_mode;
252762306a36Sopenharmony_ci		}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci		/* compute and set default and max tx/sds rings */
253062306a36Sopenharmony_ci		if (adapter->ahw->msix_supported) {
253162306a36Sopenharmony_ci			if (qlcnic_check_multi_tx_capability(adapter) == 1)
253262306a36Sopenharmony_ci				qlcnic_set_tx_ring_count(adapter,
253362306a36Sopenharmony_ci							 QLCNIC_SINGLE_RING);
253462306a36Sopenharmony_ci			else
253562306a36Sopenharmony_ci				qlcnic_set_tx_ring_count(adapter,
253662306a36Sopenharmony_ci							 QLCNIC_DEF_TX_RINGS);
253762306a36Sopenharmony_ci			qlcnic_set_sds_ring_count(adapter,
253862306a36Sopenharmony_ci						  QLCNIC_DEF_SDS_RINGS);
253962306a36Sopenharmony_ci		} else {
254062306a36Sopenharmony_ci			qlcnic_set_tx_ring_count(adapter, QLCNIC_SINGLE_RING);
254162306a36Sopenharmony_ci			qlcnic_set_sds_ring_count(adapter, QLCNIC_SINGLE_RING);
254262306a36Sopenharmony_ci		}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci		err = qlcnic_setup_idc_param(adapter);
254562306a36Sopenharmony_ci		if (err)
254662306a36Sopenharmony_ci			goto err_out_free_hw;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci		adapter->flags |= QLCNIC_NEED_FLR;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	} else if (qlcnic_83xx_check(adapter)) {
255162306a36Sopenharmony_ci		qlcnic_83xx_check_vf(adapter, ent);
255262306a36Sopenharmony_ci		adapter->portnum = adapter->ahw->pci_func;
255362306a36Sopenharmony_ci		err = qlcnic_83xx_init(adapter);
255462306a36Sopenharmony_ci		if (err) {
255562306a36Sopenharmony_ci			switch (err) {
255662306a36Sopenharmony_ci			case -ENOTRECOVERABLE:
255762306a36Sopenharmony_ci				dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n");
255862306a36Sopenharmony_ci				dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n");
255962306a36Sopenharmony_ci				goto err_out_free_hw;
256062306a36Sopenharmony_ci			case -ENOMEM:
256162306a36Sopenharmony_ci				dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n");
256262306a36Sopenharmony_ci				goto err_out_free_hw;
256362306a36Sopenharmony_ci			case -EOPNOTSUPP:
256462306a36Sopenharmony_ci				dev_err(&pdev->dev, "Adapter initialization failed\n");
256562306a36Sopenharmony_ci				goto err_out_free_hw;
256662306a36Sopenharmony_ci			default:
256762306a36Sopenharmony_ci				dev_err(&pdev->dev, "Adapter initialization failed. Driver will load in maintenance mode to recover the adapter using the application\n");
256862306a36Sopenharmony_ci				goto err_out_maintenance_mode;
256962306a36Sopenharmony_ci			}
257062306a36Sopenharmony_ci		}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci		if (qlcnic_sriov_vf_check(adapter))
257362306a36Sopenharmony_ci			return 0;
257462306a36Sopenharmony_ci	} else {
257562306a36Sopenharmony_ci		dev_err(&pdev->dev,
257662306a36Sopenharmony_ci			"%s: failed. Please Reboot\n", __func__);
257762306a36Sopenharmony_ci		err = -ENODEV;
257862306a36Sopenharmony_ci		goto err_out_free_hw;
257962306a36Sopenharmony_ci	}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	if (qlcnic_read_mac_addr(adapter))
258262306a36Sopenharmony_ci		dev_warn(&pdev->dev, "failed to read mac addr\n");
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	qlcnic_read_phys_port_id(adapter);
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	if (adapter->portnum == 0) {
258762306a36Sopenharmony_ci		qlcnic_get_board_name(adapter, board_name);
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci		pr_info("%s: %s Board Chip rev 0x%x\n",
259062306a36Sopenharmony_ci			module_name(THIS_MODULE),
259162306a36Sopenharmony_ci			board_name, adapter->ahw->revision_id);
259262306a36Sopenharmony_ci	}
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x &&
259562306a36Sopenharmony_ci	    !!qlcnic_use_msi)
259662306a36Sopenharmony_ci		dev_warn(&pdev->dev,
259762306a36Sopenharmony_ci			 "Device does not support MSI interrupts\n");
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter)) {
260062306a36Sopenharmony_ci		err = qlcnic_dcb_enable(adapter->dcb);
260162306a36Sopenharmony_ci		if (err) {
260262306a36Sopenharmony_ci			qlcnic_dcb_free(adapter->dcb);
260362306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to enable DCB\n");
260462306a36Sopenharmony_ci			goto err_out_free_hw;
260562306a36Sopenharmony_ci		}
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci		qlcnic_dcb_get_info(adapter->dcb);
260862306a36Sopenharmony_ci		err = qlcnic_setup_intr(adapter);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci		if (err) {
261162306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to setup interrupt\n");
261262306a36Sopenharmony_ci			goto err_out_disable_msi;
261362306a36Sopenharmony_ci		}
261462306a36Sopenharmony_ci	}
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	err = qlcnic_get_act_pci_func(adapter);
261762306a36Sopenharmony_ci	if (err)
261862306a36Sopenharmony_ci		goto err_out_disable_mbx_intr;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	if (adapter->portnum == 0)
262162306a36Sopenharmony_ci		qlcnic_set_drv_version(adapter);
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	err = qlcnic_setup_netdev(adapter, netdev);
262462306a36Sopenharmony_ci	if (err)
262562306a36Sopenharmony_ci		goto err_out_disable_mbx_intr;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	pci_set_drvdata(pdev, adapter);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
263062306a36Sopenharmony_ci		qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
263162306a36Sopenharmony_ci				     FW_POLL_DELAY);
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	switch (adapter->ahw->port_type) {
263462306a36Sopenharmony_ci	case QLCNIC_GBE:
263562306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
263662306a36Sopenharmony_ci				adapter->netdev->name);
263762306a36Sopenharmony_ci		break;
263862306a36Sopenharmony_ci	case QLCNIC_XGBE:
263962306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
264062306a36Sopenharmony_ci				adapter->netdev->name);
264162306a36Sopenharmony_ci		break;
264262306a36Sopenharmony_ci	}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	if (adapter->drv_mac_learn)
264562306a36Sopenharmony_ci		qlcnic_alloc_lb_filters_mem(adapter);
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	qlcnic_add_sysfs(adapter);
264862306a36Sopenharmony_ci	qlcnic_register_hwmon_dev(adapter);
264962306a36Sopenharmony_ci	return 0;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_cierr_out_disable_mbx_intr:
265262306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter))
265362306a36Sopenharmony_ci		qlcnic_83xx_free_mbx_intr(adapter);
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_cierr_out_disable_msi:
265662306a36Sopenharmony_ci	qlcnic_teardown_intr(adapter);
265762306a36Sopenharmony_ci	qlcnic_cancel_idc_work(adapter);
265862306a36Sopenharmony_ci	qlcnic_clr_all_drv_state(adapter, 0);
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_cierr_out_free_hw:
266162306a36Sopenharmony_ci	qlcnic_free_adapter_resources(adapter);
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_cierr_out_free_wq:
266462306a36Sopenharmony_ci	destroy_workqueue(adapter->qlcnic_wq);
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_cierr_out_free_netdev:
266762306a36Sopenharmony_ci	free_netdev(netdev);
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_cierr_out_iounmap:
267062306a36Sopenharmony_ci	qlcnic_cleanup_pci_map(ahw);
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_cierr_out_free_hw_res:
267362306a36Sopenharmony_ci	kfree(ahw);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_cierr_out_free_res:
267662306a36Sopenharmony_ci	pci_release_regions(pdev);
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_cierr_out_disable_pdev:
267962306a36Sopenharmony_ci	pci_disable_device(pdev);
268062306a36Sopenharmony_ci	return err;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_cierr_out_maintenance_mode:
268362306a36Sopenharmony_ci	set_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state);
268462306a36Sopenharmony_ci	netdev->netdev_ops = &qlcnic_netdev_failed_ops;
268562306a36Sopenharmony_ci	netdev->ethtool_ops = &qlcnic_ethtool_failed_ops;
268662306a36Sopenharmony_ci	ahw->port_type = QLCNIC_XGBE;
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter))
268962306a36Sopenharmony_ci		adapter->tgt_status_reg = NULL;
269062306a36Sopenharmony_ci	else
269162306a36Sopenharmony_ci		ahw->board_type = QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	err = register_netdev(netdev);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	if (err) {
269662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register net device\n");
269762306a36Sopenharmony_ci		qlcnic_clr_all_drv_state(adapter, 0);
269862306a36Sopenharmony_ci		goto err_out_free_hw;
269962306a36Sopenharmony_ci	}
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	pci_set_drvdata(pdev, adapter);
270262306a36Sopenharmony_ci	qlcnic_add_sysfs(adapter);
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	return 0;
270562306a36Sopenharmony_ci}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_cistatic void qlcnic_remove(struct pci_dev *pdev)
270862306a36Sopenharmony_ci{
270962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter;
271062306a36Sopenharmony_ci	struct net_device *netdev;
271162306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	adapter = pci_get_drvdata(pdev);
271462306a36Sopenharmony_ci	if (adapter == NULL)
271562306a36Sopenharmony_ci		return;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	netdev = adapter->netdev;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	qlcnic_cancel_idc_work(adapter);
272062306a36Sopenharmony_ci	qlcnic_sriov_pf_disable(adapter);
272162306a36Sopenharmony_ci	ahw = adapter->ahw;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	unregister_netdev(netdev);
272462306a36Sopenharmony_ci	qlcnic_sriov_cleanup(adapter);
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter)) {
272762306a36Sopenharmony_ci		qlcnic_83xx_initialize_nic(adapter, 0);
272862306a36Sopenharmony_ci		cancel_delayed_work_sync(&adapter->idc_aen_work);
272962306a36Sopenharmony_ci		qlcnic_83xx_free_mbx_intr(adapter);
273062306a36Sopenharmony_ci		qlcnic_83xx_detach_mailbox_work(adapter);
273162306a36Sopenharmony_ci		qlcnic_83xx_free_mailbox(ahw->mailbox);
273262306a36Sopenharmony_ci		kfree(ahw->fw_info);
273362306a36Sopenharmony_ci	}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	qlcnic_dcb_free(adapter->dcb);
273662306a36Sopenharmony_ci	qlcnic_detach(adapter);
273762306a36Sopenharmony_ci	kfree(adapter->npars);
273862306a36Sopenharmony_ci	kfree(adapter->eswitch);
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
274162306a36Sopenharmony_ci		qlcnic_clr_all_drv_state(adapter, 0);
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	qlcnic_free_lb_filters_mem(adapter);
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	qlcnic_teardown_intr(adapter);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	qlcnic_remove_sysfs(adapter);
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	qlcnic_unregister_hwmon_dev(adapter);
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	qlcnic_cleanup_pci_map(adapter->ahw);
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	qlcnic_release_firmware(adapter);
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	pci_release_regions(pdev);
275862306a36Sopenharmony_ci	pci_disable_device(pdev);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	if (adapter->qlcnic_wq) {
276162306a36Sopenharmony_ci		destroy_workqueue(adapter->qlcnic_wq);
276262306a36Sopenharmony_ci		adapter->qlcnic_wq = NULL;
276362306a36Sopenharmony_ci	}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	qlcnic_free_adapter_resources(adapter);
276662306a36Sopenharmony_ci	kfree(ahw);
276762306a36Sopenharmony_ci	free_netdev(netdev);
276862306a36Sopenharmony_ci}
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_cistatic void qlcnic_shutdown(struct pci_dev *pdev)
277162306a36Sopenharmony_ci{
277262306a36Sopenharmony_ci	if (__qlcnic_shutdown(pdev))
277362306a36Sopenharmony_ci		return;
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	pci_disable_device(pdev);
277662306a36Sopenharmony_ci}
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_cistatic int __maybe_unused qlcnic_suspend(struct device *dev_d)
277962306a36Sopenharmony_ci{
278062306a36Sopenharmony_ci	return __qlcnic_shutdown(to_pci_dev(dev_d));
278162306a36Sopenharmony_ci}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_cistatic int __maybe_unused qlcnic_resume(struct device *dev_d)
278462306a36Sopenharmony_ci{
278562306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = dev_get_drvdata(dev_d);
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	return  __qlcnic_resume(adapter);
278862306a36Sopenharmony_ci}
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_cistatic int qlcnic_open(struct net_device *netdev)
279162306a36Sopenharmony_ci{
279262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
279362306a36Sopenharmony_ci	int err;
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
279662306a36Sopenharmony_ci		netdev_err(netdev, "%s: Device is in non-operational state\n",
279762306a36Sopenharmony_ci			   __func__);
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci		return -EIO;
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	netif_carrier_off(netdev);
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci	err = qlcnic_attach(adapter);
280562306a36Sopenharmony_ci	if (err)
280662306a36Sopenharmony_ci		return err;
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	err = __qlcnic_up(adapter, netdev);
280962306a36Sopenharmony_ci	if (err)
281062306a36Sopenharmony_ci		qlcnic_detach(adapter);
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	return err;
281362306a36Sopenharmony_ci}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci/*
281662306a36Sopenharmony_ci * qlcnic_close - Disables a network interface entry point
281762306a36Sopenharmony_ci */
281862306a36Sopenharmony_cistatic int qlcnic_close(struct net_device *netdev)
281962306a36Sopenharmony_ci{
282062306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	__qlcnic_down(adapter, netdev);
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	return 0;
282562306a36Sopenharmony_ci}
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci#define QLCNIC_VF_LB_BUCKET_SIZE 1
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_civoid qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
283062306a36Sopenharmony_ci{
283162306a36Sopenharmony_ci	void *head;
283262306a36Sopenharmony_ci	int i;
283362306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
283462306a36Sopenharmony_ci	u32 filter_size = 0;
283562306a36Sopenharmony_ci	u16 act_pci_func = 0;
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci	if (adapter->fhash.fmax && adapter->fhash.fhead)
283862306a36Sopenharmony_ci		return;
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	act_pci_func = adapter->ahw->total_nic_func;
284162306a36Sopenharmony_ci	spin_lock_init(&adapter->mac_learn_lock);
284262306a36Sopenharmony_ci	spin_lock_init(&adapter->rx_mac_learn_lock);
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter)) {
284562306a36Sopenharmony_ci		filter_size = QLCNIC_83XX_SRIOV_VF_MAX_MAC - 1;
284662306a36Sopenharmony_ci		adapter->fhash.fbucket_size = QLCNIC_VF_LB_BUCKET_SIZE;
284762306a36Sopenharmony_ci	} else if (qlcnic_82xx_check(adapter)) {
284862306a36Sopenharmony_ci		filter_size = QLCNIC_LB_MAX_FILTERS;
284962306a36Sopenharmony_ci		adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE;
285062306a36Sopenharmony_ci	} else {
285162306a36Sopenharmony_ci		filter_size = QLC_83XX_LB_MAX_FILTERS;
285262306a36Sopenharmony_ci		adapter->fhash.fbucket_size = QLC_83XX_LB_BUCKET_SIZE;
285362306a36Sopenharmony_ci	}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	head = kcalloc(adapter->fhash.fbucket_size,
285662306a36Sopenharmony_ci		       sizeof(struct hlist_head), GFP_ATOMIC);
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	if (!head)
285962306a36Sopenharmony_ci		return;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	adapter->fhash.fmax = (filter_size / act_pci_func);
286262306a36Sopenharmony_ci	adapter->fhash.fhead = head;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	netdev_info(netdev, "active nic func = %d, mac filter size=%d\n",
286562306a36Sopenharmony_ci		    act_pci_func, adapter->fhash.fmax);
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	for (i = 0; i < adapter->fhash.fbucket_size; i++)
286862306a36Sopenharmony_ci		INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	adapter->rx_fhash.fbucket_size = adapter->fhash.fbucket_size;
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci	head = kcalloc(adapter->rx_fhash.fbucket_size,
287362306a36Sopenharmony_ci		       sizeof(struct hlist_head), GFP_ATOMIC);
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	if (!head)
287662306a36Sopenharmony_ci		return;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	adapter->rx_fhash.fmax = (filter_size / act_pci_func);
287962306a36Sopenharmony_ci	adapter->rx_fhash.fhead = head;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	for (i = 0; i < adapter->rx_fhash.fbucket_size; i++)
288262306a36Sopenharmony_ci		INIT_HLIST_HEAD(&adapter->rx_fhash.fhead[i]);
288362306a36Sopenharmony_ci}
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_cistatic void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
288662306a36Sopenharmony_ci{
288762306a36Sopenharmony_ci	if (adapter->fhash.fmax)
288862306a36Sopenharmony_ci		kfree(adapter->fhash.fhead);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	adapter->fhash.fhead = NULL;
289162306a36Sopenharmony_ci	adapter->fhash.fmax = 0;
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	if (adapter->rx_fhash.fmax)
289462306a36Sopenharmony_ci		kfree(adapter->rx_fhash.fhead);
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	adapter->rx_fhash.fmax = 0;
289762306a36Sopenharmony_ci	adapter->rx_fhash.fhead = NULL;
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ciint qlcnic_check_temp(struct qlcnic_adapter *adapter)
290162306a36Sopenharmony_ci{
290262306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
290362306a36Sopenharmony_ci	u32 temp_state, temp_val, temp = 0;
290462306a36Sopenharmony_ci	int rv = 0;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter))
290762306a36Sopenharmony_ci		temp = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP);
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
291062306a36Sopenharmony_ci		temp = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	temp_state = qlcnic_get_temp_state(temp);
291362306a36Sopenharmony_ci	temp_val = qlcnic_get_temp_val(temp);
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	if (temp_state == QLCNIC_TEMP_PANIC) {
291662306a36Sopenharmony_ci		dev_err(&netdev->dev,
291762306a36Sopenharmony_ci		       "Device temperature %d degrees C exceeds"
291862306a36Sopenharmony_ci		       " maximum allowed. Hardware has been shut down.\n",
291962306a36Sopenharmony_ci		       temp_val);
292062306a36Sopenharmony_ci		rv = 1;
292162306a36Sopenharmony_ci	} else if (temp_state == QLCNIC_TEMP_WARN) {
292262306a36Sopenharmony_ci		if (adapter->ahw->temp == QLCNIC_TEMP_NORMAL) {
292362306a36Sopenharmony_ci			dev_err(&netdev->dev,
292462306a36Sopenharmony_ci			       "Device temperature %d degrees C "
292562306a36Sopenharmony_ci			       "exceeds operating range."
292662306a36Sopenharmony_ci			       " Immediate action needed.\n",
292762306a36Sopenharmony_ci			       temp_val);
292862306a36Sopenharmony_ci		}
292962306a36Sopenharmony_ci	} else {
293062306a36Sopenharmony_ci		if (adapter->ahw->temp == QLCNIC_TEMP_WARN) {
293162306a36Sopenharmony_ci			dev_info(&netdev->dev,
293262306a36Sopenharmony_ci			       "Device temperature is now %d degrees C"
293362306a36Sopenharmony_ci			       " in normal range.\n", temp_val);
293462306a36Sopenharmony_ci		}
293562306a36Sopenharmony_ci	}
293662306a36Sopenharmony_ci	adapter->ahw->temp = temp_state;
293762306a36Sopenharmony_ci	return rv;
293862306a36Sopenharmony_ci}
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_cistatic inline void dump_tx_ring_desc(struct qlcnic_host_tx_ring *tx_ring)
294162306a36Sopenharmony_ci{
294262306a36Sopenharmony_ci	int i;
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	for (i = 0; i < tx_ring->num_desc; i++) {
294562306a36Sopenharmony_ci		pr_info("TX Desc: %d\n", i);
294662306a36Sopenharmony_ci		print_hex_dump(KERN_INFO, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
294762306a36Sopenharmony_ci			       &tx_ring->desc_head[i],
294862306a36Sopenharmony_ci			       sizeof(struct cmd_desc_type0), true);
294962306a36Sopenharmony_ci	}
295062306a36Sopenharmony_ci}
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_cistatic void qlcnic_dump_rings(struct qlcnic_adapter *adapter)
295362306a36Sopenharmony_ci{
295462306a36Sopenharmony_ci	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
295562306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
295662306a36Sopenharmony_ci	struct qlcnic_host_rds_ring *rds_ring;
295762306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring;
295862306a36Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring;
295962306a36Sopenharmony_ci	int ring;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	if (!netdev || !netif_running(netdev))
296262306a36Sopenharmony_ci		return;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
296562306a36Sopenharmony_ci		rds_ring = &recv_ctx->rds_rings[ring];
296662306a36Sopenharmony_ci		if (!rds_ring)
296762306a36Sopenharmony_ci			continue;
296862306a36Sopenharmony_ci		netdev_info(netdev,
296962306a36Sopenharmony_ci			    "rds_ring=%d crb_rcv_producer=%d producer=%u num_desc=%u\n",
297062306a36Sopenharmony_ci			     ring, readl(rds_ring->crb_rcv_producer),
297162306a36Sopenharmony_ci			     rds_ring->producer, rds_ring->num_desc);
297262306a36Sopenharmony_ci	}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {
297562306a36Sopenharmony_ci		sds_ring = &(recv_ctx->sds_rings[ring]);
297662306a36Sopenharmony_ci		if (!sds_ring)
297762306a36Sopenharmony_ci			continue;
297862306a36Sopenharmony_ci		netdev_info(netdev,
297962306a36Sopenharmony_ci			    "sds_ring=%d crb_sts_consumer=%d consumer=%u crb_intr_mask=%d num_desc=%u\n",
298062306a36Sopenharmony_ci			    ring, readl(sds_ring->crb_sts_consumer),
298162306a36Sopenharmony_ci			    sds_ring->consumer, readl(sds_ring->crb_intr_mask),
298262306a36Sopenharmony_ci			    sds_ring->num_desc);
298362306a36Sopenharmony_ci	}
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	for (ring = 0; ring < adapter->drv_tx_rings; ring++) {
298662306a36Sopenharmony_ci		tx_ring = &adapter->tx_ring[ring];
298762306a36Sopenharmony_ci		if (!tx_ring)
298862306a36Sopenharmony_ci			continue;
298962306a36Sopenharmony_ci		netdev_info(netdev, "Tx ring=%d Context Id=0x%x\n",
299062306a36Sopenharmony_ci			    ring, tx_ring->ctx_id);
299162306a36Sopenharmony_ci		netdev_info(netdev,
299262306a36Sopenharmony_ci			    "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n",
299362306a36Sopenharmony_ci			    tx_ring->tx_stats.xmit_finished,
299462306a36Sopenharmony_ci			    tx_ring->tx_stats.xmit_called,
299562306a36Sopenharmony_ci			    tx_ring->tx_stats.xmit_on,
299662306a36Sopenharmony_ci			    tx_ring->tx_stats.xmit_off);
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci		if (tx_ring->crb_intr_mask)
299962306a36Sopenharmony_ci			netdev_info(netdev, "crb_intr_mask=%d\n",
300062306a36Sopenharmony_ci				    readl(tx_ring->crb_intr_mask));
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci		netdev_info(netdev,
300362306a36Sopenharmony_ci			    "hw_producer=%d, sw_producer=%d sw_consumer=%d, hw_consumer=%d\n",
300462306a36Sopenharmony_ci			    readl(tx_ring->crb_cmd_producer),
300562306a36Sopenharmony_ci			    tx_ring->producer, tx_ring->sw_consumer,
300662306a36Sopenharmony_ci			    le32_to_cpu(*(tx_ring->hw_consumer)));
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci		netdev_info(netdev, "Total desc=%d, Available desc=%d\n",
300962306a36Sopenharmony_ci			    tx_ring->num_desc, qlcnic_tx_avail(tx_ring));
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci		if (netif_msg_tx_err(adapter->ahw))
301262306a36Sopenharmony_ci			dump_tx_ring_desc(tx_ring);
301362306a36Sopenharmony_ci	}
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci}
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_cistatic void qlcnic_tx_timeout(struct net_device *netdev, unsigned int txqueue)
301862306a36Sopenharmony_ci{
301962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci	if (test_bit(__QLCNIC_RESETTING, &adapter->state))
302262306a36Sopenharmony_ci		return;
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	qlcnic_dump_rings(adapter);
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS ||
302762306a36Sopenharmony_ci	    netif_msg_tx_err(adapter->ahw)) {
302862306a36Sopenharmony_ci		netdev_err(netdev, "Tx timeout, reset the adapter.\n");
302962306a36Sopenharmony_ci		if (qlcnic_82xx_check(adapter))
303062306a36Sopenharmony_ci			adapter->need_fw_reset = 1;
303162306a36Sopenharmony_ci		else if (qlcnic_83xx_check(adapter))
303262306a36Sopenharmony_ci			qlcnic_83xx_idc_request_reset(adapter,
303362306a36Sopenharmony_ci						      QLCNIC_FORCE_FW_DUMP_KEY);
303462306a36Sopenharmony_ci	} else {
303562306a36Sopenharmony_ci		netdev_err(netdev, "Tx timeout, reset adapter context.\n");
303662306a36Sopenharmony_ci		adapter->ahw->reset_context = 1;
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_cistatic struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
304162306a36Sopenharmony_ci{
304262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
304362306a36Sopenharmony_ci	struct net_device_stats *stats = &netdev->stats;
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci	if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
304662306a36Sopenharmony_ci		qlcnic_update_stats(adapter);
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
304962306a36Sopenharmony_ci	stats->tx_packets = adapter->stats.xmitfinished;
305062306a36Sopenharmony_ci	stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
305162306a36Sopenharmony_ci	stats->tx_bytes = adapter->stats.txbytes;
305262306a36Sopenharmony_ci	stats->rx_dropped = adapter->stats.rxdropped;
305362306a36Sopenharmony_ci	stats->tx_dropped = adapter->stats.txdropped;
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	return stats;
305662306a36Sopenharmony_ci}
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_cistatic irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
305962306a36Sopenharmony_ci{
306062306a36Sopenharmony_ci	u32 status;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	status = readl(adapter->isr_int_vec);
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	if (!(status & adapter->ahw->int_vec_bit))
306562306a36Sopenharmony_ci		return IRQ_NONE;
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ci	/* check interrupt state machine, to be sure */
306862306a36Sopenharmony_ci	status = readl(adapter->crb_int_state_reg);
306962306a36Sopenharmony_ci	if (!ISR_LEGACY_INT_TRIGGERED(status))
307062306a36Sopenharmony_ci		return IRQ_NONE;
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	writel(0xffffffff, adapter->tgt_status_reg);
307362306a36Sopenharmony_ci	/* read twice to ensure write is flushed */
307462306a36Sopenharmony_ci	readl(adapter->isr_int_vec);
307562306a36Sopenharmony_ci	readl(adapter->isr_int_vec);
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci	return IRQ_HANDLED;
307862306a36Sopenharmony_ci}
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_cistatic irqreturn_t qlcnic_tmp_intr(int irq, void *data)
308162306a36Sopenharmony_ci{
308262306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring = data;
308362306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = sds_ring->adapter;
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	if (adapter->flags & QLCNIC_MSIX_ENABLED)
308662306a36Sopenharmony_ci		goto done;
308762306a36Sopenharmony_ci	else if (adapter->flags & QLCNIC_MSI_ENABLED) {
308862306a36Sopenharmony_ci		writel(0xffffffff, adapter->tgt_status_reg);
308962306a36Sopenharmony_ci		goto done;
309062306a36Sopenharmony_ci	}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
309362306a36Sopenharmony_ci		return IRQ_NONE;
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_cidone:
309662306a36Sopenharmony_ci	adapter->ahw->diag_cnt++;
309762306a36Sopenharmony_ci	qlcnic_enable_sds_intr(adapter, sds_ring);
309862306a36Sopenharmony_ci	return IRQ_HANDLED;
309962306a36Sopenharmony_ci}
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_cistatic irqreturn_t qlcnic_intr(int irq, void *data)
310262306a36Sopenharmony_ci{
310362306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring = data;
310462306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = sds_ring->adapter;
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
310762306a36Sopenharmony_ci		return IRQ_NONE;
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	napi_schedule(&sds_ring->napi);
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	return IRQ_HANDLED;
311262306a36Sopenharmony_ci}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_cistatic irqreturn_t qlcnic_msi_intr(int irq, void *data)
311562306a36Sopenharmony_ci{
311662306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring = data;
311762306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = sds_ring->adapter;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	/* clear interrupt */
312062306a36Sopenharmony_ci	writel(0xffffffff, adapter->tgt_status_reg);
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	napi_schedule(&sds_ring->napi);
312362306a36Sopenharmony_ci	return IRQ_HANDLED;
312462306a36Sopenharmony_ci}
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_cistatic irqreturn_t qlcnic_msix_intr(int irq, void *data)
312762306a36Sopenharmony_ci{
312862306a36Sopenharmony_ci	struct qlcnic_host_sds_ring *sds_ring = data;
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_ci	napi_schedule(&sds_ring->napi);
313162306a36Sopenharmony_ci	return IRQ_HANDLED;
313262306a36Sopenharmony_ci}
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_cistatic irqreturn_t qlcnic_msix_tx_intr(int irq, void *data)
313562306a36Sopenharmony_ci{
313662306a36Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring = data;
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	napi_schedule(&tx_ring->napi);
313962306a36Sopenharmony_ci	return IRQ_HANDLED;
314062306a36Sopenharmony_ci}
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_cistatic void
314362306a36Sopenharmony_ciqlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
314462306a36Sopenharmony_ci{
314562306a36Sopenharmony_ci	u32 val;
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	val = adapter->portnum & 0xf;
314862306a36Sopenharmony_ci	val |= encoding << 7;
314962306a36Sopenharmony_ci	val |= (jiffies - adapter->dev_rst_time) << 8;
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
315262306a36Sopenharmony_ci	adapter->dev_rst_time = jiffies;
315362306a36Sopenharmony_ci}
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_cistatic int
315662306a36Sopenharmony_ciqlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
315762306a36Sopenharmony_ci{
315862306a36Sopenharmony_ci	u32  val;
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
316162306a36Sopenharmony_ci			state != QLCNIC_DEV_NEED_QUISCENT);
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
316462306a36Sopenharmony_ci		return -EIO;
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	if (state == QLCNIC_DEV_NEED_RESET)
316962306a36Sopenharmony_ci		QLC_DEV_SET_RST_RDY(val, adapter->portnum);
317062306a36Sopenharmony_ci	else if (state == QLCNIC_DEV_NEED_QUISCENT)
317162306a36Sopenharmony_ci		QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	return 0;
317862306a36Sopenharmony_ci}
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_cistatic int
318162306a36Sopenharmony_ciqlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
318262306a36Sopenharmony_ci{
318362306a36Sopenharmony_ci	u32  val;
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
318662306a36Sopenharmony_ci		return -EBUSY;
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
318962306a36Sopenharmony_ci	QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
319062306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	return 0;
319562306a36Sopenharmony_ci}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_civoid qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
319862306a36Sopenharmony_ci{
319962306a36Sopenharmony_ci	u32  val;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
320262306a36Sopenharmony_ci		goto err;
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
320562306a36Sopenharmony_ci	QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
320662306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci	if (failed) {
320962306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
321062306a36Sopenharmony_ci				    QLCNIC_DEV_FAILED);
321162306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev,
321262306a36Sopenharmony_ci				"Device state set to Failed. Please Reboot\n");
321362306a36Sopenharmony_ci	} else if (!(val & 0x11111111))
321462306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
321562306a36Sopenharmony_ci				    QLCNIC_DEV_COLD);
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
321862306a36Sopenharmony_ci	QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
321962306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
322262306a36Sopenharmony_cierr:
322362306a36Sopenharmony_ci	adapter->fw_fail_cnt = 0;
322462306a36Sopenharmony_ci	adapter->flags &= ~QLCNIC_FW_HANG;
322562306a36Sopenharmony_ci	clear_bit(__QLCNIC_START_FW, &adapter->state);
322662306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
322762306a36Sopenharmony_ci}
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci/* Grab api lock, before checking state */
323062306a36Sopenharmony_cistatic int
323162306a36Sopenharmony_ciqlcnic_check_drv_state(struct qlcnic_adapter *adapter)
323262306a36Sopenharmony_ci{
323362306a36Sopenharmony_ci	int act, state, active_mask;
323462306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
323762306a36Sopenharmony_ci	act = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
324062306a36Sopenharmony_ci		active_mask = (~(1 << (ahw->pci_func * 4)));
324162306a36Sopenharmony_ci		act = act & active_mask;
324262306a36Sopenharmony_ci	}
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	if (((state & 0x11111111) == (act & 0x11111111)) ||
324562306a36Sopenharmony_ci			((act & 0x11111111) == ((state >> 1) & 0x11111111)))
324662306a36Sopenharmony_ci		return 0;
324762306a36Sopenharmony_ci	else
324862306a36Sopenharmony_ci		return 1;
324962306a36Sopenharmony_ci}
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_cistatic int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
325262306a36Sopenharmony_ci{
325362306a36Sopenharmony_ci	u32 val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	if (val != QLCNIC_DRV_IDC_VER) {
325662306a36Sopenharmony_ci		dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
325762306a36Sopenharmony_ci			" idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
325862306a36Sopenharmony_ci	}
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci	return 0;
326162306a36Sopenharmony_ci}
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_cistatic int
326462306a36Sopenharmony_ciqlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
326562306a36Sopenharmony_ci{
326662306a36Sopenharmony_ci	u32 val, prev_state;
326762306a36Sopenharmony_ci	u8 dev_init_timeo = adapter->dev_init_timeo;
326862306a36Sopenharmony_ci	u8 portnum = adapter->portnum;
326962306a36Sopenharmony_ci	u8 ret;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
327262306a36Sopenharmony_ci		return 1;
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
327562306a36Sopenharmony_ci		return -1;
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
327862306a36Sopenharmony_ci	if (!(val & (1 << (portnum * 4)))) {
327962306a36Sopenharmony_ci		QLC_DEV_SET_REF_CNT(val, portnum);
328062306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
328162306a36Sopenharmony_ci	}
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
328462306a36Sopenharmony_ci	QLCDB(adapter, HW, "Device state = %u\n", prev_state);
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	switch (prev_state) {
328762306a36Sopenharmony_ci	case QLCNIC_DEV_COLD:
328862306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
328962306a36Sopenharmony_ci				    QLCNIC_DEV_INITIALIZING);
329062306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_IDC_VER,
329162306a36Sopenharmony_ci				    QLCNIC_DRV_IDC_VER);
329262306a36Sopenharmony_ci		qlcnic_idc_debug_info(adapter, 0);
329362306a36Sopenharmony_ci		qlcnic_api_unlock(adapter);
329462306a36Sopenharmony_ci		return 1;
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci	case QLCNIC_DEV_READY:
329762306a36Sopenharmony_ci		ret = qlcnic_check_idc_ver(adapter);
329862306a36Sopenharmony_ci		qlcnic_api_unlock(adapter);
329962306a36Sopenharmony_ci		return ret;
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	case QLCNIC_DEV_NEED_RESET:
330262306a36Sopenharmony_ci		val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
330362306a36Sopenharmony_ci		QLC_DEV_SET_RST_RDY(val, portnum);
330462306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
330562306a36Sopenharmony_ci		break;
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci	case QLCNIC_DEV_NEED_QUISCENT:
330862306a36Sopenharmony_ci		val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
330962306a36Sopenharmony_ci		QLC_DEV_SET_QSCNT_RDY(val, portnum);
331062306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
331162306a36Sopenharmony_ci		break;
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	case QLCNIC_DEV_FAILED:
331462306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Device in failed state.\n");
331562306a36Sopenharmony_ci		qlcnic_api_unlock(adapter);
331662306a36Sopenharmony_ci		return -1;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	case QLCNIC_DEV_INITIALIZING:
331962306a36Sopenharmony_ci	case QLCNIC_DEV_QUISCENT:
332062306a36Sopenharmony_ci		break;
332162306a36Sopenharmony_ci	}
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	do {
332662306a36Sopenharmony_ci		msleep(1000);
332762306a36Sopenharmony_ci		prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
332862306a36Sopenharmony_ci	} while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci	if (!dev_init_timeo) {
333162306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
333262306a36Sopenharmony_ci			"Waiting for device to initialize timeout\n");
333362306a36Sopenharmony_ci		return -1;
333462306a36Sopenharmony_ci	}
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
333762306a36Sopenharmony_ci		return -1;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
334062306a36Sopenharmony_ci	QLC_DEV_CLR_RST_QSCNT(val, portnum);
334162306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci	ret = qlcnic_check_idc_ver(adapter);
334462306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	return ret;
334762306a36Sopenharmony_ci}
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_cistatic void
335062306a36Sopenharmony_ciqlcnic_fwinit_work(struct work_struct *work)
335162306a36Sopenharmony_ci{
335262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = container_of(work,
335362306a36Sopenharmony_ci			struct qlcnic_adapter, fw_work.work);
335462306a36Sopenharmony_ci	u32 dev_state = 0xf;
335562306a36Sopenharmony_ci	u32 val;
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
335862306a36Sopenharmony_ci		goto err_ret;
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
336162306a36Sopenharmony_ci	if (dev_state == QLCNIC_DEV_QUISCENT ||
336262306a36Sopenharmony_ci	    dev_state == QLCNIC_DEV_NEED_QUISCENT) {
336362306a36Sopenharmony_ci		qlcnic_api_unlock(adapter);
336462306a36Sopenharmony_ci		qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
336562306a36Sopenharmony_ci						FW_POLL_DELAY * 2);
336662306a36Sopenharmony_ci		return;
336762306a36Sopenharmony_ci	}
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
337062306a36Sopenharmony_ci		qlcnic_api_unlock(adapter);
337162306a36Sopenharmony_ci		goto wait_npar;
337262306a36Sopenharmony_ci	}
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	if (dev_state == QLCNIC_DEV_INITIALIZING ||
337562306a36Sopenharmony_ci	    dev_state == QLCNIC_DEV_READY) {
337662306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Detected state change from "
337762306a36Sopenharmony_ci				"DEV_NEED_RESET, skipping ack check\n");
337862306a36Sopenharmony_ci		goto skip_ack_check;
337962306a36Sopenharmony_ci	}
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci	if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
338262306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
338362306a36Sopenharmony_ci					adapter->reset_ack_timeo);
338462306a36Sopenharmony_ci		goto skip_ack_check;
338562306a36Sopenharmony_ci	}
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci	if (!qlcnic_check_drv_state(adapter)) {
338862306a36Sopenharmony_ciskip_ack_check:
338962306a36Sopenharmony_ci		dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci		if (dev_state == QLCNIC_DEV_NEED_RESET) {
339262306a36Sopenharmony_ci			QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
339362306a36Sopenharmony_ci					    QLCNIC_DEV_INITIALIZING);
339462306a36Sopenharmony_ci			set_bit(__QLCNIC_START_FW, &adapter->state);
339562306a36Sopenharmony_ci			QLCDB(adapter, DRV, "Restarting fw\n");
339662306a36Sopenharmony_ci			qlcnic_idc_debug_info(adapter, 0);
339762306a36Sopenharmony_ci			val = QLC_SHARED_REG_RD32(adapter,
339862306a36Sopenharmony_ci						  QLCNIC_CRB_DRV_STATE);
339962306a36Sopenharmony_ci			QLC_DEV_SET_RST_RDY(val, adapter->portnum);
340062306a36Sopenharmony_ci			QLC_SHARED_REG_WR32(adapter,
340162306a36Sopenharmony_ci					    QLCNIC_CRB_DRV_STATE, val);
340262306a36Sopenharmony_ci		}
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci		qlcnic_api_unlock(adapter);
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci		rtnl_lock();
340762306a36Sopenharmony_ci		if (qlcnic_check_fw_dump_state(adapter) &&
340862306a36Sopenharmony_ci		    (adapter->flags & QLCNIC_FW_RESET_OWNER)) {
340962306a36Sopenharmony_ci			QLCDB(adapter, DRV, "Take FW dump\n");
341062306a36Sopenharmony_ci			qlcnic_dump_fw(adapter);
341162306a36Sopenharmony_ci			adapter->flags |= QLCNIC_FW_HANG;
341262306a36Sopenharmony_ci		}
341362306a36Sopenharmony_ci		rtnl_unlock();
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci		adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
341662306a36Sopenharmony_ci		if (!adapter->nic_ops->start_firmware(adapter)) {
341762306a36Sopenharmony_ci			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
341862306a36Sopenharmony_ci			adapter->fw_wait_cnt = 0;
341962306a36Sopenharmony_ci			return;
342062306a36Sopenharmony_ci		}
342162306a36Sopenharmony_ci		goto err_ret;
342262306a36Sopenharmony_ci	}
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ciwait_npar:
342762306a36Sopenharmony_ci	dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
342862306a36Sopenharmony_ci	QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci	switch (dev_state) {
343162306a36Sopenharmony_ci	case QLCNIC_DEV_READY:
343262306a36Sopenharmony_ci		if (!qlcnic_start_firmware(adapter)) {
343362306a36Sopenharmony_ci			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
343462306a36Sopenharmony_ci			adapter->fw_wait_cnt = 0;
343562306a36Sopenharmony_ci			return;
343662306a36Sopenharmony_ci		}
343762306a36Sopenharmony_ci		break;
343862306a36Sopenharmony_ci	case QLCNIC_DEV_FAILED:
343962306a36Sopenharmony_ci		break;
344062306a36Sopenharmony_ci	default:
344162306a36Sopenharmony_ci		qlcnic_schedule_work(adapter,
344262306a36Sopenharmony_ci			qlcnic_fwinit_work, FW_POLL_DELAY);
344362306a36Sopenharmony_ci		return;
344462306a36Sopenharmony_ci	}
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_cierr_ret:
344762306a36Sopenharmony_ci	dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
344862306a36Sopenharmony_ci		"fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
344962306a36Sopenharmony_ci	netif_device_attach(adapter->netdev);
345062306a36Sopenharmony_ci	qlcnic_clr_all_drv_state(adapter, 0);
345162306a36Sopenharmony_ci}
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_cistatic void
345462306a36Sopenharmony_ciqlcnic_detach_work(struct work_struct *work)
345562306a36Sopenharmony_ci{
345662306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = container_of(work,
345762306a36Sopenharmony_ci			struct qlcnic_adapter, fw_work.work);
345862306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
345962306a36Sopenharmony_ci	u32 status;
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	netif_device_detach(netdev);
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci	/* Dont grab rtnl lock during Quiscent mode */
346462306a36Sopenharmony_ci	if (adapter->dev_state == QLCNIC_DEV_NEED_QUISCENT) {
346562306a36Sopenharmony_ci		if (netif_running(netdev))
346662306a36Sopenharmony_ci			__qlcnic_down(adapter, netdev);
346762306a36Sopenharmony_ci	} else
346862306a36Sopenharmony_ci		qlcnic_down(adapter, netdev);
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci	status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci	if (status & QLCNIC_RCODE_FATAL_ERROR) {
347362306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
347462306a36Sopenharmony_ci			"Detaching the device: peg halt status1=0x%x\n",
347562306a36Sopenharmony_ci					status);
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci		if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) {
347862306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
347962306a36Sopenharmony_ci			"On board active cooling fan failed. "
348062306a36Sopenharmony_ci				"Device has been halted.\n");
348162306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
348262306a36Sopenharmony_ci				"Replace the adapter.\n");
348362306a36Sopenharmony_ci		}
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci		goto err_ret;
348662306a36Sopenharmony_ci	}
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	if (adapter->ahw->temp == QLCNIC_TEMP_PANIC) {
348962306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Detaching the device: temp=%d\n",
349062306a36Sopenharmony_ci			adapter->ahw->temp);
349162306a36Sopenharmony_ci		goto err_ret;
349262306a36Sopenharmony_ci	}
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	/* Dont ack if this instance is the reset owner */
349562306a36Sopenharmony_ci	if (!(adapter->flags & QLCNIC_FW_RESET_OWNER)) {
349662306a36Sopenharmony_ci		if (qlcnic_set_drv_state(adapter, adapter->dev_state)) {
349762306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
349862306a36Sopenharmony_ci				"Failed to set driver state,"
349962306a36Sopenharmony_ci					"detaching the device.\n");
350062306a36Sopenharmony_ci			goto err_ret;
350162306a36Sopenharmony_ci		}
350262306a36Sopenharmony_ci	}
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	adapter->fw_wait_cnt = 0;
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci	qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
350762306a36Sopenharmony_ci
350862306a36Sopenharmony_ci	return;
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_cierr_ret:
351162306a36Sopenharmony_ci	netif_device_attach(netdev);
351262306a36Sopenharmony_ci	qlcnic_clr_all_drv_state(adapter, 1);
351362306a36Sopenharmony_ci}
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci/*Transit NPAR state to NON Operational */
351662306a36Sopenharmony_cistatic void
351762306a36Sopenharmony_ciqlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
351862306a36Sopenharmony_ci{
351962306a36Sopenharmony_ci	u32 state;
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
352262306a36Sopenharmony_ci	if (state == QLCNIC_DEV_NPAR_NON_OPER)
352362306a36Sopenharmony_ci		return;
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
352662306a36Sopenharmony_ci		return;
352762306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
352862306a36Sopenharmony_ci			    QLCNIC_DEV_NPAR_NON_OPER);
352962306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
353062306a36Sopenharmony_ci}
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_cistatic void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter,
353362306a36Sopenharmony_ci					  u32 key)
353462306a36Sopenharmony_ci{
353562306a36Sopenharmony_ci	u32 state, xg_val = 0, gb_val = 0;
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	qlcnic_xg_set_xg0_mask(xg_val);
353862306a36Sopenharmony_ci	qlcnic_xg_set_xg1_mask(xg_val);
353962306a36Sopenharmony_ci	QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, xg_val);
354062306a36Sopenharmony_ci	qlcnic_gb_set_gb0_mask(gb_val);
354162306a36Sopenharmony_ci	qlcnic_gb_set_gb1_mask(gb_val);
354262306a36Sopenharmony_ci	qlcnic_gb_set_gb2_mask(gb_val);
354362306a36Sopenharmony_ci	qlcnic_gb_set_gb3_mask(gb_val);
354462306a36Sopenharmony_ci	QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, gb_val);
354562306a36Sopenharmony_ci	dev_info(&adapter->pdev->dev, "Pause control frames disabled"
354662306a36Sopenharmony_ci				" on all ports\n");
354762306a36Sopenharmony_ci	adapter->need_fw_reset = 1;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
355062306a36Sopenharmony_ci		return;
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
355562306a36Sopenharmony_ci		netdev_err(adapter->netdev, "%s: Device is in non-operational state\n",
355662306a36Sopenharmony_ci			   __func__);
355762306a36Sopenharmony_ci		qlcnic_api_unlock(adapter);
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci		return;
356062306a36Sopenharmony_ci	}
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci	if (state == QLCNIC_DEV_READY) {
356362306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
356462306a36Sopenharmony_ci				    QLCNIC_DEV_NEED_RESET);
356562306a36Sopenharmony_ci		adapter->flags |= QLCNIC_FW_RESET_OWNER;
356662306a36Sopenharmony_ci		QLCDB(adapter, DRV, "NEED_RESET state set\n");
356762306a36Sopenharmony_ci		qlcnic_idc_debug_info(adapter, 0);
356862306a36Sopenharmony_ci	}
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
357162306a36Sopenharmony_ci			    QLCNIC_DEV_NPAR_NON_OPER);
357262306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
357362306a36Sopenharmony_ci}
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci/* Transit to NPAR READY state from NPAR NOT READY state */
357662306a36Sopenharmony_cistatic void
357762306a36Sopenharmony_ciqlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
357862306a36Sopenharmony_ci{
357962306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
358062306a36Sopenharmony_ci		return;
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
358362306a36Sopenharmony_ci			    QLCNIC_DEV_NPAR_OPER);
358462306a36Sopenharmony_ci	QLCDB(adapter, DRV, "NPAR operational state set\n");
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
358762306a36Sopenharmony_ci}
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_civoid qlcnic_schedule_work(struct qlcnic_adapter *adapter,
359062306a36Sopenharmony_ci			  work_func_t func, int delay)
359162306a36Sopenharmony_ci{
359262306a36Sopenharmony_ci	if (test_bit(__QLCNIC_AER, &adapter->state))
359362306a36Sopenharmony_ci		return;
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci	INIT_DELAYED_WORK(&adapter->fw_work, func);
359662306a36Sopenharmony_ci	queue_delayed_work(adapter->qlcnic_wq, &adapter->fw_work,
359762306a36Sopenharmony_ci			   round_jiffies_relative(delay));
359862306a36Sopenharmony_ci}
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_cistatic void
360162306a36Sopenharmony_ciqlcnic_attach_work(struct work_struct *work)
360262306a36Sopenharmony_ci{
360362306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = container_of(work,
360462306a36Sopenharmony_ci				struct qlcnic_adapter, fw_work.work);
360562306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
360662306a36Sopenharmony_ci	u32 npar_state;
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
360962306a36Sopenharmony_ci		npar_state = QLC_SHARED_REG_RD32(adapter,
361062306a36Sopenharmony_ci						 QLCNIC_CRB_DEV_NPAR_STATE);
361162306a36Sopenharmony_ci		if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
361262306a36Sopenharmony_ci			qlcnic_clr_all_drv_state(adapter, 0);
361362306a36Sopenharmony_ci		else if (npar_state != QLCNIC_DEV_NPAR_OPER)
361462306a36Sopenharmony_ci			qlcnic_schedule_work(adapter, qlcnic_attach_work,
361562306a36Sopenharmony_ci							FW_POLL_DELAY);
361662306a36Sopenharmony_ci		else
361762306a36Sopenharmony_ci			goto attach;
361862306a36Sopenharmony_ci		QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n");
361962306a36Sopenharmony_ci		return;
362062306a36Sopenharmony_ci	}
362162306a36Sopenharmony_ciattach:
362262306a36Sopenharmony_ci	qlcnic_dcb_get_info(adapter->dcb);
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	if (netif_running(netdev)) {
362562306a36Sopenharmony_ci		if (qlcnic_up(adapter, netdev))
362662306a36Sopenharmony_ci			goto done;
362762306a36Sopenharmony_ci
362862306a36Sopenharmony_ci		qlcnic_restore_indev_addr(netdev, NETDEV_UP);
362962306a36Sopenharmony_ci	}
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_cidone:
363262306a36Sopenharmony_ci	netif_device_attach(netdev);
363362306a36Sopenharmony_ci	adapter->fw_fail_cnt = 0;
363462306a36Sopenharmony_ci	adapter->flags &= ~QLCNIC_FW_HANG;
363562306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
363662306a36Sopenharmony_ci	if (adapter->portnum == 0)
363762306a36Sopenharmony_ci		qlcnic_set_drv_version(adapter);
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	if (!qlcnic_clr_drv_state(adapter))
364062306a36Sopenharmony_ci		qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
364162306a36Sopenharmony_ci							FW_POLL_DELAY);
364262306a36Sopenharmony_ci}
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_cistatic int
364562306a36Sopenharmony_ciqlcnic_check_health(struct qlcnic_adapter *adapter)
364662306a36Sopenharmony_ci{
364762306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
364862306a36Sopenharmony_ci	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
364962306a36Sopenharmony_ci	u32 state = 0, heartbeat;
365062306a36Sopenharmony_ci	u32 peg_status;
365162306a36Sopenharmony_ci	int err = 0;
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	if (qlcnic_check_temp(adapter))
365462306a36Sopenharmony_ci		goto detach;
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	if (adapter->need_fw_reset)
365762306a36Sopenharmony_ci		qlcnic_dev_request_reset(adapter, 0);
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
366062306a36Sopenharmony_ci	if (state == QLCNIC_DEV_NEED_RESET) {
366162306a36Sopenharmony_ci		qlcnic_set_npar_non_operational(adapter);
366262306a36Sopenharmony_ci		adapter->need_fw_reset = 1;
366362306a36Sopenharmony_ci	} else if (state == QLCNIC_DEV_NEED_QUISCENT)
366462306a36Sopenharmony_ci		goto detach;
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci	heartbeat = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
366762306a36Sopenharmony_ci	if (heartbeat != adapter->heartbeat) {
366862306a36Sopenharmony_ci		adapter->heartbeat = heartbeat;
366962306a36Sopenharmony_ci		adapter->fw_fail_cnt = 0;
367062306a36Sopenharmony_ci		if (adapter->need_fw_reset)
367162306a36Sopenharmony_ci			goto detach;
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci		if (ahw->reset_context && qlcnic_auto_fw_reset)
367462306a36Sopenharmony_ci			qlcnic_reset_hw_context(adapter);
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci		return 0;
367762306a36Sopenharmony_ci	}
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_ci	if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
368062306a36Sopenharmony_ci		return 0;
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_ci	adapter->flags |= QLCNIC_FW_HANG;
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	qlcnic_dev_request_reset(adapter, 0);
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci	if (qlcnic_auto_fw_reset)
368762306a36Sopenharmony_ci		clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci	dev_err(&adapter->pdev->dev, "firmware hang detected\n");
369062306a36Sopenharmony_ci	peg_status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
369162306a36Sopenharmony_ci	dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
369262306a36Sopenharmony_ci			"PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
369362306a36Sopenharmony_ci			"PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
369462306a36Sopenharmony_ci			"PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
369562306a36Sopenharmony_ci			"PEG_NET_4_PC: 0x%x\n",
369662306a36Sopenharmony_ci			peg_status,
369762306a36Sopenharmony_ci			QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2),
369862306a36Sopenharmony_ci			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err),
369962306a36Sopenharmony_ci			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err),
370062306a36Sopenharmony_ci			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err),
370162306a36Sopenharmony_ci			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err),
370262306a36Sopenharmony_ci			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err));
370362306a36Sopenharmony_ci	if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
370462306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
370562306a36Sopenharmony_ci			"Firmware aborted with error code 0x00006700. "
370662306a36Sopenharmony_ci				"Device is being reset.\n");
370762306a36Sopenharmony_cidetach:
370862306a36Sopenharmony_ci	adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
370962306a36Sopenharmony_ci		QLCNIC_DEV_NEED_RESET;
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci	if (qlcnic_auto_fw_reset && !test_and_set_bit(__QLCNIC_RESETTING,
371262306a36Sopenharmony_ci						      &adapter->state)) {
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci		qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
371562306a36Sopenharmony_ci		QLCDB(adapter, DRV, "fw recovery scheduled.\n");
371662306a36Sopenharmony_ci	} else if (!qlcnic_auto_fw_reset && fw_dump->enable &&
371762306a36Sopenharmony_ci		   adapter->flags & QLCNIC_FW_RESET_OWNER) {
371862306a36Sopenharmony_ci		qlcnic_dump_fw(adapter);
371962306a36Sopenharmony_ci	}
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci	return 1;
372262306a36Sopenharmony_ci}
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_civoid qlcnic_fw_poll_work(struct work_struct *work)
372562306a36Sopenharmony_ci{
372662306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = container_of(work,
372762306a36Sopenharmony_ci				struct qlcnic_adapter, fw_work.work);
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	if (test_bit(__QLCNIC_RESETTING, &adapter->state))
373062306a36Sopenharmony_ci		goto reschedule;
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	if (qlcnic_check_health(adapter))
373462306a36Sopenharmony_ci		return;
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	if (adapter->fhash.fnum)
373762306a36Sopenharmony_ci		qlcnic_prune_lb_filters(adapter);
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_cireschedule:
374062306a36Sopenharmony_ci	qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
374162306a36Sopenharmony_ci}
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_cistatic int qlcnic_is_first_func(struct pci_dev *pdev)
374462306a36Sopenharmony_ci{
374562306a36Sopenharmony_ci	struct pci_dev *oth_pdev;
374662306a36Sopenharmony_ci	int val = pdev->devfn;
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci	while (val-- > 0) {
374962306a36Sopenharmony_ci		oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
375062306a36Sopenharmony_ci			(pdev->bus), pdev->bus->number,
375162306a36Sopenharmony_ci			PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
375262306a36Sopenharmony_ci		if (!oth_pdev)
375362306a36Sopenharmony_ci			continue;
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci		if (oth_pdev->current_state != PCI_D3cold) {
375662306a36Sopenharmony_ci			pci_dev_put(oth_pdev);
375762306a36Sopenharmony_ci			return 0;
375862306a36Sopenharmony_ci		}
375962306a36Sopenharmony_ci		pci_dev_put(oth_pdev);
376062306a36Sopenharmony_ci	}
376162306a36Sopenharmony_ci	return 1;
376262306a36Sopenharmony_ci}
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_cistatic int qlcnic_attach_func(struct pci_dev *pdev)
376562306a36Sopenharmony_ci{
376662306a36Sopenharmony_ci	int err, first_func;
376762306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
376862306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci	pdev->error_state = pci_channel_io_normal;
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci	err = pci_enable_device(pdev);
377362306a36Sopenharmony_ci	if (err)
377462306a36Sopenharmony_ci		return err;
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	pci_set_master(pdev);
377762306a36Sopenharmony_ci	pci_restore_state(pdev);
377862306a36Sopenharmony_ci
377962306a36Sopenharmony_ci	first_func = qlcnic_is_first_func(pdev);
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	if (qlcnic_api_lock(adapter))
378262306a36Sopenharmony_ci		return -EINVAL;
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
378562306a36Sopenharmony_ci		adapter->need_fw_reset = 1;
378662306a36Sopenharmony_ci		set_bit(__QLCNIC_START_FW, &adapter->state);
378762306a36Sopenharmony_ci		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
378862306a36Sopenharmony_ci				    QLCNIC_DEV_INITIALIZING);
378962306a36Sopenharmony_ci		QLCDB(adapter, DRV, "Restarting fw\n");
379062306a36Sopenharmony_ci	}
379162306a36Sopenharmony_ci	qlcnic_api_unlock(adapter);
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	err = qlcnic_start_firmware(adapter);
379462306a36Sopenharmony_ci	if (err)
379562306a36Sopenharmony_ci		return err;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	qlcnic_clr_drv_state(adapter);
379862306a36Sopenharmony_ci	kfree(adapter->msix_entries);
379962306a36Sopenharmony_ci	adapter->msix_entries = NULL;
380062306a36Sopenharmony_ci	err = qlcnic_setup_intr(adapter);
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci	if (err) {
380362306a36Sopenharmony_ci		kfree(adapter->msix_entries);
380462306a36Sopenharmony_ci		netdev_err(netdev, "failed to setup interrupt\n");
380562306a36Sopenharmony_ci		return err;
380662306a36Sopenharmony_ci	}
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci	if (netif_running(netdev)) {
380962306a36Sopenharmony_ci		err = qlcnic_attach(adapter);
381062306a36Sopenharmony_ci		if (err) {
381162306a36Sopenharmony_ci			qlcnic_clr_all_drv_state(adapter, 1);
381262306a36Sopenharmony_ci			clear_bit(__QLCNIC_AER, &adapter->state);
381362306a36Sopenharmony_ci			netif_device_attach(netdev);
381462306a36Sopenharmony_ci			return err;
381562306a36Sopenharmony_ci		}
381662306a36Sopenharmony_ci
381762306a36Sopenharmony_ci		err = qlcnic_up(adapter, netdev);
381862306a36Sopenharmony_ci		if (err)
381962306a36Sopenharmony_ci			goto done;
382062306a36Sopenharmony_ci
382162306a36Sopenharmony_ci		qlcnic_restore_indev_addr(netdev, NETDEV_UP);
382262306a36Sopenharmony_ci	}
382362306a36Sopenharmony_ci done:
382462306a36Sopenharmony_ci	netif_device_attach(netdev);
382562306a36Sopenharmony_ci	return err;
382662306a36Sopenharmony_ci}
382762306a36Sopenharmony_ci
382862306a36Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev,
382962306a36Sopenharmony_ci						      pci_channel_state_t state)
383062306a36Sopenharmony_ci{
383162306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
383262306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
383362306a36Sopenharmony_ci
383462306a36Sopenharmony_ci	if (state == pci_channel_io_perm_failure)
383562306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	if (state == pci_channel_io_normal)
383862306a36Sopenharmony_ci		return PCI_ERS_RESULT_RECOVERED;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	set_bit(__QLCNIC_AER, &adapter->state);
384162306a36Sopenharmony_ci	netif_device_detach(netdev);
384262306a36Sopenharmony_ci
384362306a36Sopenharmony_ci	cancel_delayed_work_sync(&adapter->fw_work);
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci	if (netif_running(netdev))
384662306a36Sopenharmony_ci		qlcnic_down(adapter, netdev);
384762306a36Sopenharmony_ci
384862306a36Sopenharmony_ci	qlcnic_detach(adapter);
384962306a36Sopenharmony_ci	qlcnic_teardown_intr(adapter);
385062306a36Sopenharmony_ci
385162306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_ci	pci_save_state(pdev);
385462306a36Sopenharmony_ci	pci_disable_device(pdev);
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
385762306a36Sopenharmony_ci}
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *pdev)
386062306a36Sopenharmony_ci{
386162306a36Sopenharmony_ci	pci_ers_result_t res;
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	rtnl_lock();
386462306a36Sopenharmony_ci	res = qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
386562306a36Sopenharmony_ci					 PCI_ERS_RESULT_RECOVERED;
386662306a36Sopenharmony_ci	rtnl_unlock();
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci	return res;
386962306a36Sopenharmony_ci}
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_cistatic void qlcnic_82xx_io_resume(struct pci_dev *pdev)
387262306a36Sopenharmony_ci{
387362306a36Sopenharmony_ci	u32 state;
387462306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
387762306a36Sopenharmony_ci	if (state == QLCNIC_DEV_READY && test_and_clear_bit(__QLCNIC_AER,
387862306a36Sopenharmony_ci							    &adapter->state))
387962306a36Sopenharmony_ci		qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
388062306a36Sopenharmony_ci				     FW_POLL_DELAY);
388162306a36Sopenharmony_ci}
388262306a36Sopenharmony_ci
388362306a36Sopenharmony_cistatic pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
388462306a36Sopenharmony_ci						 pci_channel_state_t state)
388562306a36Sopenharmony_ci{
388662306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
388762306a36Sopenharmony_ci	struct qlcnic_hardware_ops *hw_ops = adapter->ahw->hw_ops;
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	if (hw_ops->io_error_detected) {
389062306a36Sopenharmony_ci		return hw_ops->io_error_detected(pdev, state);
389162306a36Sopenharmony_ci	} else {
389262306a36Sopenharmony_ci		dev_err(&pdev->dev, "AER error_detected handler not registered.\n");
389362306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
389462306a36Sopenharmony_ci	}
389562306a36Sopenharmony_ci}
389662306a36Sopenharmony_ci
389762306a36Sopenharmony_cistatic pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
389862306a36Sopenharmony_ci{
389962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
390062306a36Sopenharmony_ci	struct qlcnic_hardware_ops *hw_ops = adapter->ahw->hw_ops;
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci	if (hw_ops->io_slot_reset) {
390362306a36Sopenharmony_ci		return hw_ops->io_slot_reset(pdev);
390462306a36Sopenharmony_ci	} else {
390562306a36Sopenharmony_ci		dev_err(&pdev->dev, "AER slot_reset handler not registered.\n");
390662306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
390762306a36Sopenharmony_ci	}
390862306a36Sopenharmony_ci}
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_cistatic void qlcnic_io_resume(struct pci_dev *pdev)
391162306a36Sopenharmony_ci{
391262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
391362306a36Sopenharmony_ci	struct qlcnic_hardware_ops *hw_ops = adapter->ahw->hw_ops;
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_ci	if (hw_ops->io_resume)
391662306a36Sopenharmony_ci		hw_ops->io_resume(pdev);
391762306a36Sopenharmony_ci	else
391862306a36Sopenharmony_ci		dev_err(&pdev->dev, "AER resume handler not registered.\n");
391962306a36Sopenharmony_ci}
392062306a36Sopenharmony_ci
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_cistatic int
392362306a36Sopenharmony_ciqlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
392462306a36Sopenharmony_ci{
392562306a36Sopenharmony_ci	int err;
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci	err = qlcnic_can_start_firmware(adapter);
392862306a36Sopenharmony_ci	if (err)
392962306a36Sopenharmony_ci		return err;
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci	err = qlcnic_check_npar_opertional(adapter);
393262306a36Sopenharmony_ci	if (err)
393362306a36Sopenharmony_ci		return err;
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_ci	err = qlcnic_initialize_nic(adapter);
393662306a36Sopenharmony_ci	if (err)
393762306a36Sopenharmony_ci		return err;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	qlcnic_check_options(adapter);
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_ci	err = qlcnic_set_eswitch_port_config(adapter);
394262306a36Sopenharmony_ci	if (err)
394362306a36Sopenharmony_ci		return err;
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci	adapter->need_fw_reset = 0;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	return err;
394862306a36Sopenharmony_ci}
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_ciint qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt,
395162306a36Sopenharmony_ci			  int queue_type)
395262306a36Sopenharmony_ci{
395362306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
395462306a36Sopenharmony_ci	char buf[8];
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	if (queue_type == QLCNIC_RX_QUEUE)
395762306a36Sopenharmony_ci		strcpy(buf, "SDS");
395862306a36Sopenharmony_ci	else
395962306a36Sopenharmony_ci		strcpy(buf, "Tx");
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	if (!is_power_of_2(ring_cnt)) {
396262306a36Sopenharmony_ci		netdev_err(netdev, "%s rings value should be a power of 2\n",
396362306a36Sopenharmony_ci			   buf);
396462306a36Sopenharmony_ci		return -EINVAL;
396562306a36Sopenharmony_ci	}
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter) && (queue_type == QLCNIC_TX_QUEUE) &&
396862306a36Sopenharmony_ci	    !qlcnic_check_multi_tx(adapter)) {
396962306a36Sopenharmony_ci			netdev_err(netdev, "No Multi Tx queue support\n");
397062306a36Sopenharmony_ci			return -EINVAL;
397162306a36Sopenharmony_ci	}
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci	if (ring_cnt > num_online_cpus()) {
397462306a36Sopenharmony_ci		netdev_err(netdev,
397562306a36Sopenharmony_ci			   "%s value[%u] should not be higher than, number of online CPUs\n",
397662306a36Sopenharmony_ci			   buf, num_online_cpus());
397762306a36Sopenharmony_ci		return -EINVAL;
397862306a36Sopenharmony_ci	}
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_ci	return 0;
398162306a36Sopenharmony_ci}
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ciint qlcnic_setup_rings(struct qlcnic_adapter *adapter)
398462306a36Sopenharmony_ci{
398562306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
398662306a36Sopenharmony_ci	u8 tx_rings, rx_rings;
398762306a36Sopenharmony_ci	int err;
398862306a36Sopenharmony_ci
398962306a36Sopenharmony_ci	if (test_bit(__QLCNIC_RESETTING, &adapter->state))
399062306a36Sopenharmony_ci		return -EBUSY;
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	tx_rings = adapter->drv_tss_rings;
399362306a36Sopenharmony_ci	rx_rings = adapter->drv_rss_rings;
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	netif_device_detach(netdev);
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci	err = qlcnic_set_real_num_queues(adapter, tx_rings, rx_rings);
399862306a36Sopenharmony_ci	if (err)
399962306a36Sopenharmony_ci		goto done;
400062306a36Sopenharmony_ci
400162306a36Sopenharmony_ci	if (netif_running(netdev))
400262306a36Sopenharmony_ci		__qlcnic_down(adapter, netdev);
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci	qlcnic_detach(adapter);
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter)) {
400762306a36Sopenharmony_ci		qlcnic_83xx_free_mbx_intr(adapter);
400862306a36Sopenharmony_ci		qlcnic_83xx_enable_mbx_poll(adapter);
400962306a36Sopenharmony_ci	}
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_ci	qlcnic_teardown_intr(adapter);
401262306a36Sopenharmony_ci
401362306a36Sopenharmony_ci	err = qlcnic_setup_intr(adapter);
401462306a36Sopenharmony_ci	if (err) {
401562306a36Sopenharmony_ci		kfree(adapter->msix_entries);
401662306a36Sopenharmony_ci		netdev_err(netdev, "failed to setup interrupt\n");
401762306a36Sopenharmony_ci		return err;
401862306a36Sopenharmony_ci	}
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_ci	/* Check if we need to update real_num_{tx|rx}_queues because
402162306a36Sopenharmony_ci	 * qlcnic_setup_intr() may change Tx/Rx rings size
402262306a36Sopenharmony_ci	 */
402362306a36Sopenharmony_ci	if ((tx_rings != adapter->drv_tx_rings) ||
402462306a36Sopenharmony_ci	    (rx_rings != adapter->drv_sds_rings)) {
402562306a36Sopenharmony_ci		err = qlcnic_set_real_num_queues(adapter,
402662306a36Sopenharmony_ci						 adapter->drv_tx_rings,
402762306a36Sopenharmony_ci						 adapter->drv_sds_rings);
402862306a36Sopenharmony_ci		if (err)
402962306a36Sopenharmony_ci			goto done;
403062306a36Sopenharmony_ci	}
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	if (qlcnic_83xx_check(adapter)) {
403362306a36Sopenharmony_ci		qlcnic_83xx_initialize_nic(adapter, 1);
403462306a36Sopenharmony_ci		err = qlcnic_83xx_setup_mbx_intr(adapter);
403562306a36Sopenharmony_ci		qlcnic_83xx_disable_mbx_poll(adapter);
403662306a36Sopenharmony_ci		if (err) {
403762306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
403862306a36Sopenharmony_ci				"failed to setup mbx interrupt\n");
403962306a36Sopenharmony_ci			goto done;
404062306a36Sopenharmony_ci		}
404162306a36Sopenharmony_ci	}
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	if (netif_running(netdev)) {
404462306a36Sopenharmony_ci		err = qlcnic_attach(adapter);
404562306a36Sopenharmony_ci		if (err)
404662306a36Sopenharmony_ci			goto done;
404762306a36Sopenharmony_ci		err = __qlcnic_up(adapter, netdev);
404862306a36Sopenharmony_ci		if (err)
404962306a36Sopenharmony_ci			goto done;
405062306a36Sopenharmony_ci		qlcnic_restore_indev_addr(netdev, NETDEV_UP);
405162306a36Sopenharmony_ci	}
405262306a36Sopenharmony_cidone:
405362306a36Sopenharmony_ci	netif_device_attach(netdev);
405462306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
405562306a36Sopenharmony_ci	return err;
405662306a36Sopenharmony_ci}
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ci#ifdef CONFIG_INET
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_cistatic void
406362306a36Sopenharmony_ciqlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
406462306a36Sopenharmony_ci			struct net_device *dev, unsigned long event)
406562306a36Sopenharmony_ci{
406662306a36Sopenharmony_ci	const struct in_ifaddr *ifa;
406762306a36Sopenharmony_ci	struct in_device *indev;
406862306a36Sopenharmony_ci
406962306a36Sopenharmony_ci	indev = in_dev_get(dev);
407062306a36Sopenharmony_ci	if (!indev)
407162306a36Sopenharmony_ci		return;
407262306a36Sopenharmony_ci
407362306a36Sopenharmony_ci	in_dev_for_each_ifa_rtnl(ifa, indev) {
407462306a36Sopenharmony_ci		switch (event) {
407562306a36Sopenharmony_ci		case NETDEV_UP:
407662306a36Sopenharmony_ci			qlcnic_config_ipaddr(adapter,
407762306a36Sopenharmony_ci					ifa->ifa_address, QLCNIC_IP_UP);
407862306a36Sopenharmony_ci			break;
407962306a36Sopenharmony_ci		case NETDEV_DOWN:
408062306a36Sopenharmony_ci			qlcnic_config_ipaddr(adapter,
408162306a36Sopenharmony_ci					ifa->ifa_address, QLCNIC_IP_DOWN);
408262306a36Sopenharmony_ci			break;
408362306a36Sopenharmony_ci		default:
408462306a36Sopenharmony_ci			break;
408562306a36Sopenharmony_ci		}
408662306a36Sopenharmony_ci	}
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci	in_dev_put(indev);
408962306a36Sopenharmony_ci}
409062306a36Sopenharmony_ci
409162306a36Sopenharmony_civoid qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
409262306a36Sopenharmony_ci{
409362306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
409462306a36Sopenharmony_ci	struct net_device *dev;
409562306a36Sopenharmony_ci	u16 vid;
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	qlcnic_config_indev_addr(adapter, netdev, event);
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	rcu_read_lock();
410062306a36Sopenharmony_ci	for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
410162306a36Sopenharmony_ci		dev = __vlan_find_dev_deep_rcu(netdev, htons(ETH_P_8021Q), vid);
410262306a36Sopenharmony_ci		if (!dev)
410362306a36Sopenharmony_ci			continue;
410462306a36Sopenharmony_ci		qlcnic_config_indev_addr(adapter, dev, event);
410562306a36Sopenharmony_ci	}
410662306a36Sopenharmony_ci	rcu_read_unlock();
410762306a36Sopenharmony_ci}
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_cistatic int qlcnic_netdev_event(struct notifier_block *this,
411062306a36Sopenharmony_ci				 unsigned long event, void *ptr)
411162306a36Sopenharmony_ci{
411262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter;
411362306a36Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_cirecheck:
411662306a36Sopenharmony_ci	if (dev == NULL)
411762306a36Sopenharmony_ci		goto done;
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci	if (is_vlan_dev(dev)) {
412062306a36Sopenharmony_ci		dev = vlan_dev_real_dev(dev);
412162306a36Sopenharmony_ci		goto recheck;
412262306a36Sopenharmony_ci	}
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	if (!is_qlcnic_netdev(dev))
412562306a36Sopenharmony_ci		goto done;
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	adapter = netdev_priv(dev);
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	if (!adapter)
413062306a36Sopenharmony_ci		goto done;
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_ci	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
413362306a36Sopenharmony_ci		goto done;
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	qlcnic_config_indev_addr(adapter, dev, event);
413662306a36Sopenharmony_cidone:
413762306a36Sopenharmony_ci	return NOTIFY_DONE;
413862306a36Sopenharmony_ci}
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_cistatic int
414162306a36Sopenharmony_ciqlcnic_inetaddr_event(struct notifier_block *this,
414262306a36Sopenharmony_ci		unsigned long event, void *ptr)
414362306a36Sopenharmony_ci{
414462306a36Sopenharmony_ci	struct qlcnic_adapter *adapter;
414562306a36Sopenharmony_ci	struct net_device *dev;
414662306a36Sopenharmony_ci
414762306a36Sopenharmony_ci	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
414862306a36Sopenharmony_ci
414962306a36Sopenharmony_ci	dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
415062306a36Sopenharmony_ci
415162306a36Sopenharmony_cirecheck:
415262306a36Sopenharmony_ci	if (dev == NULL)
415362306a36Sopenharmony_ci		goto done;
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	if (is_vlan_dev(dev)) {
415662306a36Sopenharmony_ci		dev = vlan_dev_real_dev(dev);
415762306a36Sopenharmony_ci		goto recheck;
415862306a36Sopenharmony_ci	}
415962306a36Sopenharmony_ci
416062306a36Sopenharmony_ci	if (!is_qlcnic_netdev(dev))
416162306a36Sopenharmony_ci		goto done;
416262306a36Sopenharmony_ci
416362306a36Sopenharmony_ci	adapter = netdev_priv(dev);
416462306a36Sopenharmony_ci
416562306a36Sopenharmony_ci	if (!adapter)
416662306a36Sopenharmony_ci		goto done;
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_ci	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
416962306a36Sopenharmony_ci		goto done;
417062306a36Sopenharmony_ci
417162306a36Sopenharmony_ci	switch (event) {
417262306a36Sopenharmony_ci	case NETDEV_UP:
417362306a36Sopenharmony_ci		qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_ci		break;
417662306a36Sopenharmony_ci	case NETDEV_DOWN:
417762306a36Sopenharmony_ci		qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci		break;
418062306a36Sopenharmony_ci	default:
418162306a36Sopenharmony_ci		break;
418262306a36Sopenharmony_ci	}
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_cidone:
418562306a36Sopenharmony_ci	return NOTIFY_DONE;
418662306a36Sopenharmony_ci}
418762306a36Sopenharmony_ci
418862306a36Sopenharmony_cistatic struct notifier_block	qlcnic_netdev_cb = {
418962306a36Sopenharmony_ci	.notifier_call = qlcnic_netdev_event,
419062306a36Sopenharmony_ci};
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_cistatic struct notifier_block qlcnic_inetaddr_cb = {
419362306a36Sopenharmony_ci	.notifier_call = qlcnic_inetaddr_event,
419462306a36Sopenharmony_ci};
419562306a36Sopenharmony_ci#else
419662306a36Sopenharmony_civoid qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
419762306a36Sopenharmony_ci{ }
419862306a36Sopenharmony_ci#endif
419962306a36Sopenharmony_cistatic const struct pci_error_handlers qlcnic_err_handler = {
420062306a36Sopenharmony_ci	.error_detected = qlcnic_io_error_detected,
420162306a36Sopenharmony_ci	.slot_reset = qlcnic_io_slot_reset,
420262306a36Sopenharmony_ci	.resume = qlcnic_io_resume,
420362306a36Sopenharmony_ci};
420462306a36Sopenharmony_ci
420562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(qlcnic_pm_ops, qlcnic_suspend, qlcnic_resume);
420662306a36Sopenharmony_ci
420762306a36Sopenharmony_cistatic struct pci_driver qlcnic_driver = {
420862306a36Sopenharmony_ci	.name = qlcnic_driver_name,
420962306a36Sopenharmony_ci	.id_table = qlcnic_pci_tbl,
421062306a36Sopenharmony_ci	.probe = qlcnic_probe,
421162306a36Sopenharmony_ci	.remove = qlcnic_remove,
421262306a36Sopenharmony_ci	.driver.pm = &qlcnic_pm_ops,
421362306a36Sopenharmony_ci	.shutdown = qlcnic_shutdown,
421462306a36Sopenharmony_ci	.err_handler = &qlcnic_err_handler,
421562306a36Sopenharmony_ci#ifdef CONFIG_QLCNIC_SRIOV
421662306a36Sopenharmony_ci	.sriov_configure = qlcnic_pci_sriov_configure,
421762306a36Sopenharmony_ci#endif
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_ci};
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_cistatic int __init qlcnic_init_module(void)
422262306a36Sopenharmony_ci{
422362306a36Sopenharmony_ci	int ret;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	printk(KERN_INFO "%s\n", qlcnic_driver_string);
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci#ifdef CONFIG_INET
422862306a36Sopenharmony_ci	register_netdevice_notifier(&qlcnic_netdev_cb);
422962306a36Sopenharmony_ci	register_inetaddr_notifier(&qlcnic_inetaddr_cb);
423062306a36Sopenharmony_ci#endif
423162306a36Sopenharmony_ci
423262306a36Sopenharmony_ci	ret = pci_register_driver(&qlcnic_driver);
423362306a36Sopenharmony_ci	if (ret) {
423462306a36Sopenharmony_ci#ifdef CONFIG_INET
423562306a36Sopenharmony_ci		unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
423662306a36Sopenharmony_ci		unregister_netdevice_notifier(&qlcnic_netdev_cb);
423762306a36Sopenharmony_ci#endif
423862306a36Sopenharmony_ci	}
423962306a36Sopenharmony_ci
424062306a36Sopenharmony_ci	return ret;
424162306a36Sopenharmony_ci}
424262306a36Sopenharmony_ci
424362306a36Sopenharmony_cimodule_init(qlcnic_init_module);
424462306a36Sopenharmony_ci
424562306a36Sopenharmony_cistatic void __exit qlcnic_exit_module(void)
424662306a36Sopenharmony_ci{
424762306a36Sopenharmony_ci	pci_unregister_driver(&qlcnic_driver);
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci#ifdef CONFIG_INET
425062306a36Sopenharmony_ci	unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
425162306a36Sopenharmony_ci	unregister_netdevice_notifier(&qlcnic_netdev_cb);
425262306a36Sopenharmony_ci#endif
425362306a36Sopenharmony_ci}
425462306a36Sopenharmony_ci
425562306a36Sopenharmony_cimodule_exit(qlcnic_exit_module);
4256