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