18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic qlcnic NIC Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/swab.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 118c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 128c2ecf20Sopenharmony_ci#include <net/ip.h> 138c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 148c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 158c2ecf20Sopenharmony_ci#include <linux/aer.h> 168c2ecf20Sopenharmony_ci#include <linux/log2.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <net/vxlan.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "qlcnic.h" 218c2ecf20Sopenharmony_ci#include "qlcnic_sriov.h" 228c2ecf20Sopenharmony_ci#include "qlcnic_hw.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); 258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 268c2ecf20Sopenharmony_ciMODULE_VERSION(QLCNIC_LINUX_VERSIONID); 278c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cichar qlcnic_driver_name[] = "qlcnic"; 308c2ecf20Sopenharmony_cistatic const char qlcnic_driver_string[] = "QLogic 1/10 GbE " 318c2ecf20Sopenharmony_ci "Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int qlcnic_mac_learn; 348c2ecf20Sopenharmony_cimodule_param(qlcnic_mac_learn, int, 0444); 358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qlcnic_mac_learn, 368c2ecf20Sopenharmony_ci "Mac Filter (0=learning is disabled, 1=Driver learning is enabled, 2=FDB learning is enabled)"); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint qlcnic_use_msi = 1; 398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled)"); 408c2ecf20Sopenharmony_cimodule_param_named(use_msi, qlcnic_use_msi, int, 0444); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciint qlcnic_use_msi_x = 1; 438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled)"); 448c2ecf20Sopenharmony_cimodule_param_named(use_msi_x, qlcnic_use_msi_x, int, 0444); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint qlcnic_auto_fw_reset = 1; 478c2ecf20Sopenharmony_ciMODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled)"); 488c2ecf20Sopenharmony_cimodule_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint qlcnic_load_fw_file; 518c2ecf20Sopenharmony_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)"); 528c2ecf20Sopenharmony_cimodule_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); 558c2ecf20Sopenharmony_cistatic void qlcnic_remove(struct pci_dev *pdev); 568c2ecf20Sopenharmony_cistatic int qlcnic_open(struct net_device *netdev); 578c2ecf20Sopenharmony_cistatic int qlcnic_close(struct net_device *netdev); 588c2ecf20Sopenharmony_cistatic void qlcnic_tx_timeout(struct net_device *netdev, unsigned int txqueue); 598c2ecf20Sopenharmony_cistatic void qlcnic_attach_work(struct work_struct *work); 608c2ecf20Sopenharmony_cistatic void qlcnic_fwinit_work(struct work_struct *work); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding); 638c2ecf20Sopenharmony_cistatic int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_tmp_intr(int irq, void *data); 668c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_intr(int irq, void *data); 678c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_msi_intr(int irq, void *data); 688c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_msix_intr(int irq, void *data); 698c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_msix_tx_intr(int irq, void *data); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic struct net_device_stats *qlcnic_get_stats(struct net_device *netdev); 728c2ecf20Sopenharmony_cistatic int qlcnic_start_firmware(struct qlcnic_adapter *); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter); 758c2ecf20Sopenharmony_cistatic void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *); 768c2ecf20Sopenharmony_cistatic int qlcnicvf_start_firmware(struct qlcnic_adapter *); 778c2ecf20Sopenharmony_cistatic int qlcnic_vlan_rx_add(struct net_device *, __be16, u16); 788c2ecf20Sopenharmony_cistatic int qlcnic_vlan_rx_del(struct net_device *, __be16, u16); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int qlcnic_82xx_setup_intr(struct qlcnic_adapter *); 818c2ecf20Sopenharmony_cistatic void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32); 828c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *); 838c2ecf20Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *); 848c2ecf20Sopenharmony_cistatic int qlcnic_82xx_start_firmware(struct qlcnic_adapter *); 858c2ecf20Sopenharmony_cistatic void qlcnic_82xx_io_resume(struct pci_dev *); 868c2ecf20Sopenharmony_cistatic void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *); 878c2ecf20Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *, 888c2ecf20Sopenharmony_ci pci_channel_state_t); 898c2ecf20Sopenharmony_cistatic u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X) 948c2ecf20Sopenharmony_ci return ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX; 958c2ecf20Sopenharmony_ci else 968c2ecf20Sopenharmony_ci return 1; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* PCI Device ID Table */ 1008c2ecf20Sopenharmony_ci#define ENTRY(device) \ 1018c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \ 1028c2ecf20Sopenharmony_ci .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const struct pci_device_id qlcnic_pci_tbl[] = { 1058c2ecf20Sopenharmony_ci ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X), 1068c2ecf20Sopenharmony_ci ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X), 1078c2ecf20Sopenharmony_ci ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE834X), 1088c2ecf20Sopenharmony_ci ENTRY(PCI_DEVICE_ID_QLOGIC_QLE8830), 1098c2ecf20Sopenharmony_ci ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE8C30), 1108c2ecf20Sopenharmony_ci ENTRY(PCI_DEVICE_ID_QLOGIC_QLE844X), 1118c2ecf20Sopenharmony_ci ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE844X), 1128c2ecf20Sopenharmony_ci {0,} 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ciinline void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *tx_ring) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci writel(tx_ring->producer, tx_ring->crb_cmd_producer); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const u32 msi_tgt_status[8] = { 1248c2ecf20Sopenharmony_ci ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1, 1258c2ecf20Sopenharmony_ci ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3, 1268c2ecf20Sopenharmony_ci ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5, 1278c2ecf20Sopenharmony_ci ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic const u32 qlcnic_reg_tbl[] = { 1318c2ecf20Sopenharmony_ci 0x1B20A8, /* PEG_HALT_STAT1 */ 1328c2ecf20Sopenharmony_ci 0x1B20AC, /* PEG_HALT_STAT2 */ 1338c2ecf20Sopenharmony_ci 0x1B20B0, /* FW_HEARTBEAT */ 1348c2ecf20Sopenharmony_ci 0x1B2100, /* LOCK ID */ 1358c2ecf20Sopenharmony_ci 0x1B2128, /* FW_CAPABILITIES */ 1368c2ecf20Sopenharmony_ci 0x1B2138, /* drv active */ 1378c2ecf20Sopenharmony_ci 0x1B2140, /* dev state */ 1388c2ecf20Sopenharmony_ci 0x1B2144, /* drv state */ 1398c2ecf20Sopenharmony_ci 0x1B2148, /* drv scratch */ 1408c2ecf20Sopenharmony_ci 0x1B214C, /* dev partition info */ 1418c2ecf20Sopenharmony_ci 0x1B2174, /* drv idc ver */ 1428c2ecf20Sopenharmony_ci 0x1B2150, /* fw version major */ 1438c2ecf20Sopenharmony_ci 0x1B2154, /* fw version minor */ 1448c2ecf20Sopenharmony_ci 0x1B2158, /* fw version sub */ 1458c2ecf20Sopenharmony_ci 0x1B219C, /* npar state */ 1468c2ecf20Sopenharmony_ci 0x1B21FC, /* FW_IMG_VALID */ 1478c2ecf20Sopenharmony_ci 0x1B2250, /* CMD_PEG_STATE */ 1488c2ecf20Sopenharmony_ci 0x1B233C, /* RCV_PEG_STATE */ 1498c2ecf20Sopenharmony_ci 0x1B23B4, /* ASIC TEMP */ 1508c2ecf20Sopenharmony_ci 0x1B216C, /* FW api */ 1518c2ecf20Sopenharmony_ci 0x1B2170, /* drv op mode */ 1528c2ecf20Sopenharmony_ci 0x13C010, /* flash lock */ 1538c2ecf20Sopenharmony_ci 0x13C014, /* flash unlock */ 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic const struct qlcnic_board_info qlcnic_boards[] = { 1578c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1588c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE844X, 1598c2ecf20Sopenharmony_ci 0x0, 1608c2ecf20Sopenharmony_ci 0x0, 1618c2ecf20Sopenharmony_ci "8400 series 10GbE Converged Network Adapter (TCP/IP Networking)" }, 1628c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1638c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 1648c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 1658c2ecf20Sopenharmony_ci 0x24e, 1668c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 1678c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 1688c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1698c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 1708c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 1718c2ecf20Sopenharmony_ci 0x243, 1728c2ecf20Sopenharmony_ci "8300 Series Single Port 10GbE Converged Network Adapter " 1738c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 1748c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1758c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 1768c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 1778c2ecf20Sopenharmony_ci 0x24a, 1788c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 1798c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 1808c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1818c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 1828c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 1838c2ecf20Sopenharmony_ci 0x246, 1848c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 1858c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 1868c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1878c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 1888c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 1898c2ecf20Sopenharmony_ci 0x252, 1908c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 1918c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 1928c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1938c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 1948c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 1958c2ecf20Sopenharmony_ci 0x26e, 1968c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 1978c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 1988c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 1998c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 2008c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2018c2ecf20Sopenharmony_ci 0x260, 2028c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 2038c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 2048c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2058c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 2068c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2078c2ecf20Sopenharmony_ci 0x266, 2088c2ecf20Sopenharmony_ci "8300 Series Single Port 10GbE Converged Network Adapter " 2098c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 2108c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2118c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 2128c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2138c2ecf20Sopenharmony_ci 0x269, 2148c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 2158c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 2168c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2178c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 2188c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2198c2ecf20Sopenharmony_ci 0x271, 2208c2ecf20Sopenharmony_ci "8300 Series Dual Port 10GbE Converged Network Adapter " 2218c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 2228c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2238c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE834X, 2248c2ecf20Sopenharmony_ci 0x0, 0x0, "8300 Series 1/10GbE Controller" }, 2258c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2268c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE8830, 2278c2ecf20Sopenharmony_ci 0x0, 2288c2ecf20Sopenharmony_ci 0x0, 2298c2ecf20Sopenharmony_ci "8830 Series 1/10GbE Controller" }, 2308c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2318c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2328c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2338c2ecf20Sopenharmony_ci 0x203, 2348c2ecf20Sopenharmony_ci "8200 Series Single Port 10GbE Converged Network Adapter" 2358c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 2368c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2378c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2388c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2398c2ecf20Sopenharmony_ci 0x207, 2408c2ecf20Sopenharmony_ci "8200 Series Dual Port 10GbE Converged Network Adapter" 2418c2ecf20Sopenharmony_ci "(TCP/IP Networking)" }, 2428c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2438c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2448c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2458c2ecf20Sopenharmony_ci 0x20b, 2468c2ecf20Sopenharmony_ci "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter" }, 2478c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2488c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2498c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2508c2ecf20Sopenharmony_ci 0x20c, 2518c2ecf20Sopenharmony_ci "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter" }, 2528c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2538c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2548c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2558c2ecf20Sopenharmony_ci 0x20f, 2568c2ecf20Sopenharmony_ci "3200 Series Single Port 10Gb Intelligent Ethernet Adapter" }, 2578c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2588c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2598c2ecf20Sopenharmony_ci 0x103c, 0x3733, 2608c2ecf20Sopenharmony_ci "NC523SFP 10Gb 2-port Server Adapter" }, 2618c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2628c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2638c2ecf20Sopenharmony_ci 0x103c, 0x3346, 2648c2ecf20Sopenharmony_ci "CN1000Q Dual Port Converged Network Adapter" }, 2658c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2668c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2678c2ecf20Sopenharmony_ci PCI_VENDOR_ID_QLOGIC, 2688c2ecf20Sopenharmony_ci 0x210, 2698c2ecf20Sopenharmony_ci "QME8242-k 10GbE Dual Port Mezzanine Card" }, 2708c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QLOGIC, 2718c2ecf20Sopenharmony_ci PCI_DEVICE_ID_QLOGIC_QLE824X, 2728c2ecf20Sopenharmony_ci 0x0, 0x0, "cLOM8214 1/10GbE Controller" }, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards) 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic const 2788c2ecf20Sopenharmony_cistruct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ciint qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci int size = sizeof(struct qlcnic_host_sds_ring) * count; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return recv_ctx->sds_rings == NULL; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_civoid qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci kfree(recv_ctx->sds_rings); 2928c2ecf20Sopenharmony_ci recv_ctx->sds_rings = NULL; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ciint qlcnic_read_mac_addr(struct qlcnic_adapter *adapter) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 2988c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 2998c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 3008c2ecf20Sopenharmony_ci int ret; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ret = qlcnic_get_mac_address(adapter, mac_addr, 3038c2ecf20Sopenharmony_ci adapter->ahw->pci_func); 3048c2ecf20Sopenharmony_ci if (ret) 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci memcpy(netdev->dev_addr, mac_addr, ETH_ALEN); 3088c2ecf20Sopenharmony_ci memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* set station address */ 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(netdev->dev_addr)) 3138c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Bad MAC address %pM.\n", 3148c2ecf20Sopenharmony_ci netdev->dev_addr); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void qlcnic_delete_adapter_mac(struct qlcnic_adapter *adapter) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct qlcnic_mac_vlan_list *cur; 3228c2ecf20Sopenharmony_ci struct list_head *head; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci list_for_each(head, &adapter->mac_list) { 3258c2ecf20Sopenharmony_ci cur = list_entry(head, struct qlcnic_mac_vlan_list, list); 3268c2ecf20Sopenharmony_ci if (ether_addr_equal_unaligned(adapter->mac_addr, cur->mac_addr)) { 3278c2ecf20Sopenharmony_ci qlcnic_sre_macaddr_change(adapter, cur->mac_addr, 3288c2ecf20Sopenharmony_ci 0, QLCNIC_MAC_DEL); 3298c2ecf20Sopenharmony_ci list_del(&cur->list); 3308c2ecf20Sopenharmony_ci kfree(cur); 3318c2ecf20Sopenharmony_ci return; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int qlcnic_set_mac(struct net_device *netdev, void *p) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 3398c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (qlcnic_sriov_vf_check(adapter)) 3428c2ecf20Sopenharmony_ci return -EINVAL; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if ((adapter->flags & QLCNIC_MAC_OVERRIDE_DISABLED)) 3458c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 3488c2ecf20Sopenharmony_ci return -EINVAL; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data) && 3518c2ecf20Sopenharmony_ci ether_addr_equal_unaligned(netdev->dev_addr, addr->sa_data)) 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { 3558c2ecf20Sopenharmony_ci netif_device_detach(netdev); 3568c2ecf20Sopenharmony_ci qlcnic_napi_disable(adapter); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci qlcnic_delete_adapter_mac(adapter); 3608c2ecf20Sopenharmony_ci memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len); 3618c2ecf20Sopenharmony_ci memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); 3628c2ecf20Sopenharmony_ci qlcnic_set_multi(adapter->netdev); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { 3658c2ecf20Sopenharmony_ci netif_device_attach(netdev); 3668c2ecf20Sopenharmony_ci qlcnic_napi_enable(adapter); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], 3728c2ecf20Sopenharmony_ci struct net_device *netdev, 3738c2ecf20Sopenharmony_ci const unsigned char *addr, u16 vid) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 3768c2ecf20Sopenharmony_ci int err = -EOPNOTSUPP; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (!adapter->fdb_mac_learn) 3798c2ecf20Sopenharmony_ci return ndo_dflt_fdb_del(ndm, tb, netdev, addr, vid); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || 3828c2ecf20Sopenharmony_ci qlcnic_sriov_check(adapter)) { 3838c2ecf20Sopenharmony_ci if (is_unicast_ether_addr(addr)) { 3848c2ecf20Sopenharmony_ci err = dev_uc_del(netdev, addr); 3858c2ecf20Sopenharmony_ci if (!err) 3868c2ecf20Sopenharmony_ci err = qlcnic_nic_del_mac(adapter, addr); 3878c2ecf20Sopenharmony_ci } else if (is_multicast_ether_addr(addr)) { 3888c2ecf20Sopenharmony_ci err = dev_mc_del(netdev, addr); 3898c2ecf20Sopenharmony_ci } else { 3908c2ecf20Sopenharmony_ci err = -EINVAL; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci return err; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], 3978c2ecf20Sopenharmony_ci struct net_device *netdev, 3988c2ecf20Sopenharmony_ci const unsigned char *addr, u16 vid, u16 flags, 3998c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 4028c2ecf20Sopenharmony_ci int err = 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (!adapter->fdb_mac_learn) 4058c2ecf20Sopenharmony_ci return ndo_dflt_fdb_add(ndm, tb, netdev, addr, vid, flags); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) && 4088c2ecf20Sopenharmony_ci !qlcnic_sriov_check(adapter)) { 4098c2ecf20Sopenharmony_ci pr_info("%s: FDB e-switch is not enabled\n", __func__); 4108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (ether_addr_equal(addr, adapter->mac_addr)) 4148c2ecf20Sopenharmony_ci return err; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (is_unicast_ether_addr(addr)) { 4178c2ecf20Sopenharmony_ci if (netdev_uc_count(netdev) < adapter->ahw->max_uc_count) 4188c2ecf20Sopenharmony_ci err = dev_uc_add_excl(netdev, addr); 4198c2ecf20Sopenharmony_ci else 4208c2ecf20Sopenharmony_ci err = -ENOMEM; 4218c2ecf20Sopenharmony_ci } else if (is_multicast_ether_addr(addr)) { 4228c2ecf20Sopenharmony_ci err = dev_mc_add_excl(netdev, addr); 4238c2ecf20Sopenharmony_ci } else { 4248c2ecf20Sopenharmony_ci err = -EINVAL; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return err; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb, 4318c2ecf20Sopenharmony_ci struct net_device *netdev, 4328c2ecf20Sopenharmony_ci struct net_device *filter_dev, int *idx) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 4358c2ecf20Sopenharmony_ci int err = 0; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (!adapter->fdb_mac_learn) 4388c2ecf20Sopenharmony_ci return ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || 4418c2ecf20Sopenharmony_ci qlcnic_sriov_check(adapter)) 4428c2ecf20Sopenharmony_ci err = ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return err; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 4508c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (!adapter->fw_work.work.func) 4538c2ecf20Sopenharmony_ci return; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->fw_work); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int qlcnic_get_phys_port_id(struct net_device *netdev, 4598c2ecf20Sopenharmony_ci struct netdev_phys_item_id *ppid) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 4628c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_HAS_PHYS_PORT_ID)) 4658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci ppid->id_len = sizeof(ahw->phys_port_id); 4688c2ecf20Sopenharmony_ci memcpy(ppid->id, ahw->phys_port_id, ppid->id_len); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci return 0; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic int qlcnic_udp_tunnel_sync(struct net_device *dev, unsigned int table) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 4768c2ecf20Sopenharmony_ci struct udp_tunnel_info ti; 4778c2ecf20Sopenharmony_ci int err; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci udp_tunnel_nic_get_port(dev, table, 0, &ti); 4808c2ecf20Sopenharmony_ci if (ti.port) { 4818c2ecf20Sopenharmony_ci err = qlcnic_set_vxlan_port(adapter, ntohs(ti.port)); 4828c2ecf20Sopenharmony_ci if (err) 4838c2ecf20Sopenharmony_ci return err; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return qlcnic_set_vxlan_parsing(adapter, ntohs(ti.port)); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic const struct udp_tunnel_nic_info qlcnic_udp_tunnels = { 4908c2ecf20Sopenharmony_ci .sync_table = qlcnic_udp_tunnel_sync, 4918c2ecf20Sopenharmony_ci .flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP, 4928c2ecf20Sopenharmony_ci .tables = { 4938c2ecf20Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, 4948c2ecf20Sopenharmony_ci }, 4958c2ecf20Sopenharmony_ci}; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic netdev_features_t qlcnic_features_check(struct sk_buff *skb, 4988c2ecf20Sopenharmony_ci struct net_device *dev, 4998c2ecf20Sopenharmony_ci netdev_features_t features) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci features = vlan_features_check(skb, features); 5028c2ecf20Sopenharmony_ci return vxlan_features_check(skb, features); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic const struct net_device_ops qlcnic_netdev_ops = { 5068c2ecf20Sopenharmony_ci .ndo_open = qlcnic_open, 5078c2ecf20Sopenharmony_ci .ndo_stop = qlcnic_close, 5088c2ecf20Sopenharmony_ci .ndo_start_xmit = qlcnic_xmit_frame, 5098c2ecf20Sopenharmony_ci .ndo_get_stats = qlcnic_get_stats, 5108c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 5118c2ecf20Sopenharmony_ci .ndo_set_rx_mode = qlcnic_set_multi, 5128c2ecf20Sopenharmony_ci .ndo_set_mac_address = qlcnic_set_mac, 5138c2ecf20Sopenharmony_ci .ndo_change_mtu = qlcnic_change_mtu, 5148c2ecf20Sopenharmony_ci .ndo_fix_features = qlcnic_fix_features, 5158c2ecf20Sopenharmony_ci .ndo_set_features = qlcnic_set_features, 5168c2ecf20Sopenharmony_ci .ndo_tx_timeout = qlcnic_tx_timeout, 5178c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = qlcnic_vlan_rx_add, 5188c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = qlcnic_vlan_rx_del, 5198c2ecf20Sopenharmony_ci .ndo_fdb_add = qlcnic_fdb_add, 5208c2ecf20Sopenharmony_ci .ndo_fdb_del = qlcnic_fdb_del, 5218c2ecf20Sopenharmony_ci .ndo_fdb_dump = qlcnic_fdb_dump, 5228c2ecf20Sopenharmony_ci .ndo_get_phys_port_id = qlcnic_get_phys_port_id, 5238c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 5248c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 5258c2ecf20Sopenharmony_ci .ndo_features_check = qlcnic_features_check, 5268c2ecf20Sopenharmony_ci#ifdef CONFIG_QLCNIC_SRIOV 5278c2ecf20Sopenharmony_ci .ndo_set_vf_mac = qlcnic_sriov_set_vf_mac, 5288c2ecf20Sopenharmony_ci .ndo_set_vf_rate = qlcnic_sriov_set_vf_tx_rate, 5298c2ecf20Sopenharmony_ci .ndo_get_vf_config = qlcnic_sriov_get_vf_config, 5308c2ecf20Sopenharmony_ci .ndo_set_vf_vlan = qlcnic_sriov_set_vf_vlan, 5318c2ecf20Sopenharmony_ci .ndo_set_vf_spoofchk = qlcnic_sriov_set_vf_spoofchk, 5328c2ecf20Sopenharmony_ci#endif 5338c2ecf20Sopenharmony_ci}; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic const struct net_device_ops qlcnic_netdev_failed_ops = { 5368c2ecf20Sopenharmony_ci .ndo_open = qlcnic_open, 5378c2ecf20Sopenharmony_ci}; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic struct qlcnic_nic_template qlcnic_ops = { 5408c2ecf20Sopenharmony_ci .config_bridged_mode = qlcnic_config_bridged_mode, 5418c2ecf20Sopenharmony_ci .config_led = qlcnic_82xx_config_led, 5428c2ecf20Sopenharmony_ci .start_firmware = qlcnic_82xx_start_firmware, 5438c2ecf20Sopenharmony_ci .request_reset = qlcnic_82xx_dev_request_reset, 5448c2ecf20Sopenharmony_ci .cancel_idc_work = qlcnic_82xx_cancel_idc_work, 5458c2ecf20Sopenharmony_ci .napi_add = qlcnic_82xx_napi_add, 5468c2ecf20Sopenharmony_ci .napi_del = qlcnic_82xx_napi_del, 5478c2ecf20Sopenharmony_ci .config_ipaddr = qlcnic_82xx_config_ipaddr, 5488c2ecf20Sopenharmony_ci .shutdown = qlcnic_82xx_shutdown, 5498c2ecf20Sopenharmony_ci .resume = qlcnic_82xx_resume, 5508c2ecf20Sopenharmony_ci .clear_legacy_intr = qlcnic_82xx_clear_legacy_intr, 5518c2ecf20Sopenharmony_ci}; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistruct qlcnic_nic_template qlcnic_vf_ops = { 5548c2ecf20Sopenharmony_ci .config_bridged_mode = qlcnicvf_config_bridged_mode, 5558c2ecf20Sopenharmony_ci .config_led = qlcnicvf_config_led, 5568c2ecf20Sopenharmony_ci .start_firmware = qlcnicvf_start_firmware 5578c2ecf20Sopenharmony_ci}; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic struct qlcnic_hardware_ops qlcnic_hw_ops = { 5608c2ecf20Sopenharmony_ci .read_crb = qlcnic_82xx_read_crb, 5618c2ecf20Sopenharmony_ci .write_crb = qlcnic_82xx_write_crb, 5628c2ecf20Sopenharmony_ci .read_reg = qlcnic_82xx_hw_read_wx_2M, 5638c2ecf20Sopenharmony_ci .write_reg = qlcnic_82xx_hw_write_wx_2M, 5648c2ecf20Sopenharmony_ci .get_mac_address = qlcnic_82xx_get_mac_address, 5658c2ecf20Sopenharmony_ci .setup_intr = qlcnic_82xx_setup_intr, 5668c2ecf20Sopenharmony_ci .alloc_mbx_args = qlcnic_82xx_alloc_mbx_args, 5678c2ecf20Sopenharmony_ci .mbx_cmd = qlcnic_82xx_issue_cmd, 5688c2ecf20Sopenharmony_ci .get_func_no = qlcnic_82xx_get_func_no, 5698c2ecf20Sopenharmony_ci .api_lock = qlcnic_82xx_api_lock, 5708c2ecf20Sopenharmony_ci .api_unlock = qlcnic_82xx_api_unlock, 5718c2ecf20Sopenharmony_ci .add_sysfs = qlcnic_82xx_add_sysfs, 5728c2ecf20Sopenharmony_ci .remove_sysfs = qlcnic_82xx_remove_sysfs, 5738c2ecf20Sopenharmony_ci .process_lb_rcv_ring_diag = qlcnic_82xx_process_rcv_ring_diag, 5748c2ecf20Sopenharmony_ci .create_rx_ctx = qlcnic_82xx_fw_cmd_create_rx_ctx, 5758c2ecf20Sopenharmony_ci .create_tx_ctx = qlcnic_82xx_fw_cmd_create_tx_ctx, 5768c2ecf20Sopenharmony_ci .del_rx_ctx = qlcnic_82xx_fw_cmd_del_rx_ctx, 5778c2ecf20Sopenharmony_ci .del_tx_ctx = qlcnic_82xx_fw_cmd_del_tx_ctx, 5788c2ecf20Sopenharmony_ci .setup_link_event = qlcnic_82xx_linkevent_request, 5798c2ecf20Sopenharmony_ci .get_nic_info = qlcnic_82xx_get_nic_info, 5808c2ecf20Sopenharmony_ci .get_pci_info = qlcnic_82xx_get_pci_info, 5818c2ecf20Sopenharmony_ci .set_nic_info = qlcnic_82xx_set_nic_info, 5828c2ecf20Sopenharmony_ci .change_macvlan = qlcnic_82xx_sre_macaddr_change, 5838c2ecf20Sopenharmony_ci .napi_enable = qlcnic_82xx_napi_enable, 5848c2ecf20Sopenharmony_ci .napi_disable = qlcnic_82xx_napi_disable, 5858c2ecf20Sopenharmony_ci .config_intr_coal = qlcnic_82xx_config_intr_coalesce, 5868c2ecf20Sopenharmony_ci .config_rss = qlcnic_82xx_config_rss, 5878c2ecf20Sopenharmony_ci .config_hw_lro = qlcnic_82xx_config_hw_lro, 5888c2ecf20Sopenharmony_ci .config_loopback = qlcnic_82xx_set_lb_mode, 5898c2ecf20Sopenharmony_ci .clear_loopback = qlcnic_82xx_clear_lb_mode, 5908c2ecf20Sopenharmony_ci .config_promisc_mode = qlcnic_82xx_nic_set_promisc, 5918c2ecf20Sopenharmony_ci .change_l2_filter = qlcnic_82xx_change_filter, 5928c2ecf20Sopenharmony_ci .get_board_info = qlcnic_82xx_get_board_info, 5938c2ecf20Sopenharmony_ci .set_mac_filter_count = qlcnic_82xx_set_mac_filter_count, 5948c2ecf20Sopenharmony_ci .free_mac_list = qlcnic_82xx_free_mac_list, 5958c2ecf20Sopenharmony_ci .read_phys_port_id = qlcnic_82xx_read_phys_port_id, 5968c2ecf20Sopenharmony_ci .io_error_detected = qlcnic_82xx_io_error_detected, 5978c2ecf20Sopenharmony_ci .io_slot_reset = qlcnic_82xx_io_slot_reset, 5988c2ecf20Sopenharmony_ci .io_resume = qlcnic_82xx_io_resume, 5998c2ecf20Sopenharmony_ci .get_beacon_state = qlcnic_82xx_get_beacon_state, 6008c2ecf20Sopenharmony_ci .enable_sds_intr = qlcnic_82xx_enable_sds_intr, 6018c2ecf20Sopenharmony_ci .disable_sds_intr = qlcnic_82xx_disable_sds_intr, 6028c2ecf20Sopenharmony_ci .enable_tx_intr = qlcnic_82xx_enable_tx_intr, 6038c2ecf20Sopenharmony_ci .disable_tx_intr = qlcnic_82xx_disable_tx_intr, 6048c2ecf20Sopenharmony_ci .get_saved_state = qlcnic_82xx_get_saved_state, 6058c2ecf20Sopenharmony_ci .set_saved_state = qlcnic_82xx_set_saved_state, 6068c2ecf20Sopenharmony_ci .cache_tmpl_hdr_values = qlcnic_82xx_cache_tmpl_hdr_values, 6078c2ecf20Sopenharmony_ci .get_cap_size = qlcnic_82xx_get_cap_size, 6088c2ecf20Sopenharmony_ci .set_sys_info = qlcnic_82xx_set_sys_info, 6098c2ecf20Sopenharmony_ci .store_cap_mask = qlcnic_82xx_store_cap_mask, 6108c2ecf20Sopenharmony_ci .encap_rx_offload = qlcnic_82xx_encap_rx_offload, 6118c2ecf20Sopenharmony_ci .encap_tx_offload = qlcnic_82xx_encap_tx_offload, 6128c2ecf20Sopenharmony_ci}; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter) && 6198c2ecf20Sopenharmony_ci (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_MULTI_TX)) { 6208c2ecf20Sopenharmony_ci test_and_set_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci } else { 6238c2ecf20Sopenharmony_ci return 1; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic int qlcnic_max_rings(struct qlcnic_adapter *adapter, u8 ring_cnt, 6288c2ecf20Sopenharmony_ci int queue_type) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci int num_rings, max_rings = QLCNIC_MAX_SDS_RINGS; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (queue_type == QLCNIC_RX_QUEUE) 6338c2ecf20Sopenharmony_ci max_rings = adapter->max_sds_rings; 6348c2ecf20Sopenharmony_ci else if (queue_type == QLCNIC_TX_QUEUE) 6358c2ecf20Sopenharmony_ci max_rings = adapter->max_tx_rings; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci num_rings = rounddown_pow_of_two(min_t(int, num_online_cpus(), 6388c2ecf20Sopenharmony_ci max_rings)); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (ring_cnt > num_rings) 6418c2ecf20Sopenharmony_ci return num_rings; 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci return ring_cnt; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_civoid qlcnic_set_tx_ring_count(struct qlcnic_adapter *adapter, u8 tx_cnt) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci /* 83xx adapter does not have max_tx_rings intialized in probe */ 6498c2ecf20Sopenharmony_ci if (adapter->max_tx_rings) 6508c2ecf20Sopenharmony_ci adapter->drv_tx_rings = qlcnic_max_rings(adapter, tx_cnt, 6518c2ecf20Sopenharmony_ci QLCNIC_TX_QUEUE); 6528c2ecf20Sopenharmony_ci else 6538c2ecf20Sopenharmony_ci adapter->drv_tx_rings = tx_cnt; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_civoid qlcnic_set_sds_ring_count(struct qlcnic_adapter *adapter, u8 rx_cnt) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci /* 83xx adapter does not have max_sds_rings intialized in probe */ 6598c2ecf20Sopenharmony_ci if (adapter->max_sds_rings) 6608c2ecf20Sopenharmony_ci adapter->drv_sds_rings = qlcnic_max_rings(adapter, rx_cnt, 6618c2ecf20Sopenharmony_ci QLCNIC_RX_QUEUE); 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci adapter->drv_sds_rings = rx_cnt; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ciint qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 6698c2ecf20Sopenharmony_ci int num_msix = 0, err = 0, vector; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_TSS_RSS; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (adapter->drv_tss_rings > 0) 6748c2ecf20Sopenharmony_ci num_msix += adapter->drv_tss_rings; 6758c2ecf20Sopenharmony_ci else 6768c2ecf20Sopenharmony_ci num_msix += adapter->drv_tx_rings; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (adapter->drv_rss_rings > 0) 6798c2ecf20Sopenharmony_ci num_msix += adapter->drv_rss_rings; 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci num_msix += adapter->drv_sds_rings; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 6848c2ecf20Sopenharmony_ci num_msix += 1; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (!adapter->msix_entries) { 6878c2ecf20Sopenharmony_ci adapter->msix_entries = kcalloc(num_msix, 6888c2ecf20Sopenharmony_ci sizeof(struct msix_entry), 6898c2ecf20Sopenharmony_ci GFP_KERNEL); 6908c2ecf20Sopenharmony_ci if (!adapter->msix_entries) 6918c2ecf20Sopenharmony_ci return -ENOMEM; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci for (vector = 0; vector < num_msix; vector++) 6958c2ecf20Sopenharmony_ci adapter->msix_entries[vector].entry = vector; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cirestore: 6988c2ecf20Sopenharmony_ci err = pci_enable_msix_exact(pdev, adapter->msix_entries, num_msix); 6998c2ecf20Sopenharmony_ci if (err == -ENOSPC) { 7008c2ecf20Sopenharmony_ci if (!adapter->drv_tss_rings && !adapter->drv_rss_rings) 7018c2ecf20Sopenharmony_ci return err; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci netdev_info(adapter->netdev, 7048c2ecf20Sopenharmony_ci "Unable to allocate %d MSI-X vectors, Available vectors %d\n", 7058c2ecf20Sopenharmony_ci num_msix, err); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci num_msix = adapter->drv_tx_rings + adapter->drv_sds_rings; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* Set rings to 0 so we can restore original TSS/RSS count */ 7108c2ecf20Sopenharmony_ci adapter->drv_tss_rings = 0; 7118c2ecf20Sopenharmony_ci adapter->drv_rss_rings = 0; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 7148c2ecf20Sopenharmony_ci num_msix += 1; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci netdev_info(adapter->netdev, 7178c2ecf20Sopenharmony_ci "Restoring %d Tx, %d SDS rings for total %d vectors.\n", 7188c2ecf20Sopenharmony_ci adapter->drv_tx_rings, adapter->drv_sds_rings, 7198c2ecf20Sopenharmony_ci num_msix); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci goto restore; 7228c2ecf20Sopenharmony_ci } else if (err < 0) { 7238c2ecf20Sopenharmony_ci return err; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci adapter->ahw->num_msix = num_msix; 7278c2ecf20Sopenharmony_ci if (adapter->drv_tss_rings > 0) 7288c2ecf20Sopenharmony_ci adapter->drv_tx_rings = adapter->drv_tss_rings; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (adapter->drv_rss_rings > 0) 7318c2ecf20Sopenharmony_ci adapter->drv_sds_rings = adapter->drv_rss_rings; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci return 0; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ciint qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 7398c2ecf20Sopenharmony_ci int err, vector; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!adapter->msix_entries) { 7428c2ecf20Sopenharmony_ci adapter->msix_entries = kcalloc(num_msix, 7438c2ecf20Sopenharmony_ci sizeof(struct msix_entry), 7448c2ecf20Sopenharmony_ci GFP_KERNEL); 7458c2ecf20Sopenharmony_ci if (!adapter->msix_entries) 7468c2ecf20Sopenharmony_ci return -ENOMEM; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (adapter->ahw->msix_supported) { 7528c2ecf20Sopenharmony_cienable_msix: 7538c2ecf20Sopenharmony_ci for (vector = 0; vector < num_msix; vector++) 7548c2ecf20Sopenharmony_ci adapter->msix_entries[vector].entry = vector; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci err = pci_enable_msix_range(pdev, 7578c2ecf20Sopenharmony_ci adapter->msix_entries, 1, num_msix); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (err == num_msix) { 7608c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_MSIX_ENABLED; 7618c2ecf20Sopenharmony_ci adapter->ahw->num_msix = num_msix; 7628c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "using msi-x interrupts\n"); 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci } else if (err > 0) { 7658c2ecf20Sopenharmony_ci pci_disable_msix(pdev); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 7688c2ecf20Sopenharmony_ci "Unable to allocate %d MSI-X vectors, Available vectors %d\n", 7698c2ecf20Sopenharmony_ci num_msix, err); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) { 7728c2ecf20Sopenharmony_ci num_msix = rounddown_pow_of_two(err); 7738c2ecf20Sopenharmony_ci if (err < QLCNIC_82XX_MINIMUM_VECTOR) 7748c2ecf20Sopenharmony_ci return -ENOSPC; 7758c2ecf20Sopenharmony_ci } else { 7768c2ecf20Sopenharmony_ci num_msix = rounddown_pow_of_two(err - 1); 7778c2ecf20Sopenharmony_ci num_msix += 1; 7788c2ecf20Sopenharmony_ci if (err < QLCNIC_83XX_MINIMUM_VECTOR) 7798c2ecf20Sopenharmony_ci return -ENOSPC; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter) && 7838c2ecf20Sopenharmony_ci !qlcnic_check_multi_tx(adapter)) { 7848c2ecf20Sopenharmony_ci adapter->drv_sds_rings = num_msix; 7858c2ecf20Sopenharmony_ci adapter->drv_tx_rings = QLCNIC_SINGLE_RING; 7868c2ecf20Sopenharmony_ci } else { 7878c2ecf20Sopenharmony_ci /* Distribute vectors equally */ 7888c2ecf20Sopenharmony_ci adapter->drv_tx_rings = num_msix / 2; 7898c2ecf20Sopenharmony_ci adapter->drv_sds_rings = adapter->drv_tx_rings; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (num_msix) { 7938c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 7948c2ecf20Sopenharmony_ci "Trying to allocate %d MSI-X interrupt vectors\n", 7958c2ecf20Sopenharmony_ci num_msix); 7968c2ecf20Sopenharmony_ci goto enable_msix; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci } else { 7998c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 8008c2ecf20Sopenharmony_ci "Unable to allocate %d MSI-X vectors, err=%d\n", 8018c2ecf20Sopenharmony_ci num_msix, err); 8028c2ecf20Sopenharmony_ci return err; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return -EIO; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci int num_msix; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci num_msix = adapter->drv_sds_rings; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (qlcnic_check_multi_tx(adapter)) 8168c2ecf20Sopenharmony_ci num_msix += adapter->drv_tx_rings; 8178c2ecf20Sopenharmony_ci else 8188c2ecf20Sopenharmony_ci num_msix += QLCNIC_SINGLE_RING; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return num_msix; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci int err = 0; 8268c2ecf20Sopenharmony_ci u32 offset, mask_reg; 8278c2ecf20Sopenharmony_ci const struct qlcnic_legacy_intr_set *legacy_intrp; 8288c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 8298c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (qlcnic_use_msi && !pci_enable_msi(pdev)) { 8328c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_MSI_ENABLED; 8338c2ecf20Sopenharmony_ci offset = msi_tgt_status[adapter->ahw->pci_func]; 8348c2ecf20Sopenharmony_ci adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter->ahw, 8358c2ecf20Sopenharmony_ci offset); 8368c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "using msi interrupts\n"); 8378c2ecf20Sopenharmony_ci adapter->msix_entries[0].vector = pdev->irq; 8388c2ecf20Sopenharmony_ci return err; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (qlcnic_use_msi || qlcnic_use_msi_x) 8428c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci legacy_intrp = &legacy_intr[adapter->ahw->pci_func]; 8458c2ecf20Sopenharmony_ci adapter->ahw->int_vec_bit = legacy_intrp->int_vec_bit; 8468c2ecf20Sopenharmony_ci offset = legacy_intrp->tgt_status_reg; 8478c2ecf20Sopenharmony_ci adapter->tgt_status_reg = qlcnic_get_ioaddr(ahw, offset); 8488c2ecf20Sopenharmony_ci mask_reg = legacy_intrp->tgt_mask_reg; 8498c2ecf20Sopenharmony_ci adapter->tgt_mask_reg = qlcnic_get_ioaddr(ahw, mask_reg); 8508c2ecf20Sopenharmony_ci adapter->isr_int_vec = qlcnic_get_ioaddr(ahw, ISR_INT_VECTOR); 8518c2ecf20Sopenharmony_ci adapter->crb_int_state_reg = qlcnic_get_ioaddr(ahw, ISR_INT_STATE_REG); 8528c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "using legacy interrupts\n"); 8538c2ecf20Sopenharmony_ci adapter->msix_entries[0].vector = pdev->irq; 8548c2ecf20Sopenharmony_ci return err; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci int num_msix, err = 0; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_TSS_RSS) { 8628c2ecf20Sopenharmony_ci err = qlcnic_setup_tss_rss_intr(adapter); 8638c2ecf20Sopenharmony_ci if (err < 0) 8648c2ecf20Sopenharmony_ci return err; 8658c2ecf20Sopenharmony_ci num_msix = adapter->ahw->num_msix; 8668c2ecf20Sopenharmony_ci } else { 8678c2ecf20Sopenharmony_ci num_msix = qlcnic_82xx_calculate_msix_vector(adapter); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci err = qlcnic_enable_msix(adapter, num_msix); 8708c2ecf20Sopenharmony_ci if (err == -ENOMEM) 8718c2ecf20Sopenharmony_ci return err; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { 8748c2ecf20Sopenharmony_ci qlcnic_disable_multi_tx(adapter); 8758c2ecf20Sopenharmony_ci adapter->drv_sds_rings = QLCNIC_SINGLE_RING; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci err = qlcnic_enable_msi_legacy(adapter); 8788c2ecf20Sopenharmony_ci if (err) 8798c2ecf20Sopenharmony_ci return err; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci return 0; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ciint qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *adapter, int op_type) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 8898c2ecf20Sopenharmony_ci int err, i; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (qlcnic_check_multi_tx(adapter) && 8928c2ecf20Sopenharmony_ci !ahw->diag_test && 8938c2ecf20Sopenharmony_ci (adapter->flags & QLCNIC_MSIX_ENABLED)) { 8948c2ecf20Sopenharmony_ci ahw->intr_tbl = 8958c2ecf20Sopenharmony_ci vzalloc(array_size(sizeof(struct qlcnic_intrpt_config), 8968c2ecf20Sopenharmony_ci ahw->num_msix)); 8978c2ecf20Sopenharmony_ci if (!ahw->intr_tbl) 8988c2ecf20Sopenharmony_ci return -ENOMEM; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci for (i = 0; i < ahw->num_msix; i++) { 9018c2ecf20Sopenharmony_ci ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX; 9028c2ecf20Sopenharmony_ci ahw->intr_tbl[i].id = i; 9038c2ecf20Sopenharmony_ci ahw->intr_tbl[i].src = 0; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci err = qlcnic_82xx_config_intrpt(adapter, 1); 9078c2ecf20Sopenharmony_ci if (err) 9088c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 9098c2ecf20Sopenharmony_ci "Failed to configure Interrupt for %d vector\n", 9108c2ecf20Sopenharmony_ci ahw->num_msix); 9118c2ecf20Sopenharmony_ci return err; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci return 0; 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_civoid qlcnic_teardown_intr(struct qlcnic_adapter *adapter) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_MSIX_ENABLED) 9208c2ecf20Sopenharmony_ci pci_disable_msix(adapter->pdev); 9218c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_MSI_ENABLED) 9228c2ecf20Sopenharmony_ci pci_disable_msi(adapter->pdev); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci kfree(adapter->msix_entries); 9258c2ecf20Sopenharmony_ci adapter->msix_entries = NULL; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (adapter->ahw->intr_tbl) { 9288c2ecf20Sopenharmony_ci vfree(adapter->ahw->intr_tbl); 9298c2ecf20Sopenharmony_ci adapter->ahw->intr_tbl = NULL; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic void qlcnic_cleanup_pci_map(struct qlcnic_hardware_context *ahw) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci if (ahw->pci_base0 != NULL) 9368c2ecf20Sopenharmony_ci iounmap(ahw->pci_base0); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 9428c2ecf20Sopenharmony_ci struct qlcnic_pci_info *pci_info; 9438c2ecf20Sopenharmony_ci int ret; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) { 9468c2ecf20Sopenharmony_ci switch (ahw->port_type) { 9478c2ecf20Sopenharmony_ci case QLCNIC_GBE: 9488c2ecf20Sopenharmony_ci ahw->total_nic_func = QLCNIC_NIU_MAX_GBE_PORTS; 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci case QLCNIC_XGBE: 9518c2ecf20Sopenharmony_ci ahw->total_nic_func = QLCNIC_NIU_MAX_XG_PORTS; 9528c2ecf20Sopenharmony_ci break; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci return 0; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (ahw->op_mode == QLCNIC_MGMT_FUNC) 9588c2ecf20Sopenharmony_ci return 0; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL); 9618c2ecf20Sopenharmony_ci if (!pci_info) 9628c2ecf20Sopenharmony_ci return -ENOMEM; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci ret = qlcnic_get_pci_info(adapter, pci_info); 9658c2ecf20Sopenharmony_ci kfree(pci_info); 9668c2ecf20Sopenharmony_ci return ret; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic bool qlcnic_port_eswitch_cfg_capability(struct qlcnic_adapter *adapter) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci bool ret = false; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (qlcnic_84xx_check(adapter)) { 9748c2ecf20Sopenharmony_ci ret = true; 9758c2ecf20Sopenharmony_ci } else if (qlcnic_83xx_check(adapter)) { 9768c2ecf20Sopenharmony_ci if (adapter->ahw->extra_capability[0] & 9778c2ecf20Sopenharmony_ci QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG) 9788c2ecf20Sopenharmony_ci ret = true; 9798c2ecf20Sopenharmony_ci else 9808c2ecf20Sopenharmony_ci ret = false; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci return ret; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ciint qlcnic_init_pci_info(struct qlcnic_adapter *adapter) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 9898c2ecf20Sopenharmony_ci struct qlcnic_pci_info *pci_info; 9908c2ecf20Sopenharmony_ci int i, id = 0, ret = 0, j = 0; 9918c2ecf20Sopenharmony_ci u16 act_pci_func; 9928c2ecf20Sopenharmony_ci u8 pfn; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL); 9958c2ecf20Sopenharmony_ci if (!pci_info) 9968c2ecf20Sopenharmony_ci return -ENOMEM; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci ret = qlcnic_get_pci_info(adapter, pci_info); 9998c2ecf20Sopenharmony_ci if (ret) 10008c2ecf20Sopenharmony_ci goto err_pci_info; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci act_pci_func = ahw->total_nic_func; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci adapter->npars = kcalloc(act_pci_func, 10058c2ecf20Sopenharmony_ci sizeof(struct qlcnic_npar_info), 10068c2ecf20Sopenharmony_ci GFP_KERNEL); 10078c2ecf20Sopenharmony_ci if (!adapter->npars) { 10088c2ecf20Sopenharmony_ci ret = -ENOMEM; 10098c2ecf20Sopenharmony_ci goto err_pci_info; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci adapter->eswitch = kcalloc(QLCNIC_NIU_MAX_XG_PORTS, 10138c2ecf20Sopenharmony_ci sizeof(struct qlcnic_eswitch), 10148c2ecf20Sopenharmony_ci GFP_KERNEL); 10158c2ecf20Sopenharmony_ci if (!adapter->eswitch) { 10168c2ecf20Sopenharmony_ci ret = -ENOMEM; 10178c2ecf20Sopenharmony_ci goto err_npars; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci for (i = 0; i < ahw->max_vnic_func; i++) { 10218c2ecf20Sopenharmony_ci pfn = pci_info[i].id; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (pfn >= ahw->max_vnic_func) { 10248c2ecf20Sopenharmony_ci ret = -EINVAL; 10258c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "%s: Invalid function 0x%x, max 0x%x\n", 10268c2ecf20Sopenharmony_ci __func__, pfn, ahw->max_vnic_func); 10278c2ecf20Sopenharmony_ci goto err_eswitch; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (!pci_info[i].active || 10318c2ecf20Sopenharmony_ci (pci_info[i].type != QLCNIC_TYPE_NIC)) 10328c2ecf20Sopenharmony_ci continue; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (qlcnic_port_eswitch_cfg_capability(adapter)) { 10358c2ecf20Sopenharmony_ci if (!qlcnic_83xx_set_port_eswitch_status(adapter, pfn, 10368c2ecf20Sopenharmony_ci &id)) 10378c2ecf20Sopenharmony_ci adapter->npars[j].eswitch_status = true; 10388c2ecf20Sopenharmony_ci else 10398c2ecf20Sopenharmony_ci continue; 10408c2ecf20Sopenharmony_ci } else { 10418c2ecf20Sopenharmony_ci adapter->npars[j].eswitch_status = true; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci adapter->npars[j].pci_func = pfn; 10458c2ecf20Sopenharmony_ci adapter->npars[j].active = (u8)pci_info[i].active; 10468c2ecf20Sopenharmony_ci adapter->npars[j].type = (u8)pci_info[i].type; 10478c2ecf20Sopenharmony_ci adapter->npars[j].phy_port = (u8)pci_info[i].default_port; 10488c2ecf20Sopenharmony_ci adapter->npars[j].min_bw = pci_info[i].tx_min_bw; 10498c2ecf20Sopenharmony_ci adapter->npars[j].max_bw = pci_info[i].tx_max_bw; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci memcpy(&adapter->npars[j].mac, &pci_info[i].mac, ETH_ALEN); 10528c2ecf20Sopenharmony_ci j++; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci /* Update eSwitch status for adapters without per port eSwitch 10568c2ecf20Sopenharmony_ci * configuration capability 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci if (!qlcnic_port_eswitch_cfg_capability(adapter)) { 10598c2ecf20Sopenharmony_ci for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) 10608c2ecf20Sopenharmony_ci adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci kfree(pci_info); 10648c2ecf20Sopenharmony_ci return 0; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cierr_eswitch: 10678c2ecf20Sopenharmony_ci kfree(adapter->eswitch); 10688c2ecf20Sopenharmony_ci adapter->eswitch = NULL; 10698c2ecf20Sopenharmony_cierr_npars: 10708c2ecf20Sopenharmony_ci kfree(adapter->npars); 10718c2ecf20Sopenharmony_ci adapter->npars = NULL; 10728c2ecf20Sopenharmony_cierr_pci_info: 10738c2ecf20Sopenharmony_ci kfree(pci_info); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci return ret; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic int 10798c2ecf20Sopenharmony_ciqlcnic_set_function_modes(struct qlcnic_adapter *adapter) 10808c2ecf20Sopenharmony_ci{ 10818c2ecf20Sopenharmony_ci u8 id; 10828c2ecf20Sopenharmony_ci int ret; 10838c2ecf20Sopenharmony_ci u32 data = QLCNIC_MGMT_FUNC; 10848c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci ret = qlcnic_api_lock(adapter); 10878c2ecf20Sopenharmony_ci if (ret) 10888c2ecf20Sopenharmony_ci goto err_lock; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci id = ahw->pci_func; 10918c2ecf20Sopenharmony_ci data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE); 10928c2ecf20Sopenharmony_ci data = (data & ~QLC_DEV_SET_DRV(0xf, id)) | 10938c2ecf20Sopenharmony_ci QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, id); 10948c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_DRV_OP_MODE, data); 10958c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 10968c2ecf20Sopenharmony_cierr_lock: 10978c2ecf20Sopenharmony_ci return ret; 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic void qlcnic_check_vf(struct qlcnic_adapter *adapter, 11018c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci u32 op_mode, priv_level; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* Determine FW API version */ 11068c2ecf20Sopenharmony_ci adapter->ahw->fw_hal_version = QLC_SHARED_REG_RD32(adapter, 11078c2ecf20Sopenharmony_ci QLCNIC_FW_API); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* Find PCI function number */ 11108c2ecf20Sopenharmony_ci qlcnic_get_func_no(adapter); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci /* Determine function privilege level */ 11138c2ecf20Sopenharmony_ci op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE); 11148c2ecf20Sopenharmony_ci if (op_mode == QLC_DEV_DRV_DEFAULT) 11158c2ecf20Sopenharmony_ci priv_level = QLCNIC_MGMT_FUNC; 11168c2ecf20Sopenharmony_ci else 11178c2ecf20Sopenharmony_ci priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (priv_level == QLCNIC_NON_PRIV_FUNC) { 11208c2ecf20Sopenharmony_ci adapter->ahw->op_mode = QLCNIC_NON_PRIV_FUNC; 11218c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, 11228c2ecf20Sopenharmony_ci "HAL Version: %d Non Privileged function\n", 11238c2ecf20Sopenharmony_ci adapter->ahw->fw_hal_version); 11248c2ecf20Sopenharmony_ci adapter->nic_ops = &qlcnic_vf_ops; 11258c2ecf20Sopenharmony_ci } else 11268c2ecf20Sopenharmony_ci adapter->nic_ops = &qlcnic_ops; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci#define QLCNIC_82XX_BAR0_LENGTH 0x00200000UL 11308c2ecf20Sopenharmony_ci#define QLCNIC_83XX_BAR0_LENGTH 0x4000 11318c2ecf20Sopenharmony_cistatic void qlcnic_get_bar_length(u32 dev_id, ulong *bar) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci switch (dev_id) { 11348c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE824X: 11358c2ecf20Sopenharmony_ci *bar = QLCNIC_82XX_BAR0_LENGTH; 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE834X: 11388c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE8830: 11398c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE844X: 11408c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_VF_QLE834X: 11418c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_VF_QLE844X: 11428c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_VF_QLE8C30: 11438c2ecf20Sopenharmony_ci *bar = QLCNIC_83XX_BAR0_LENGTH; 11448c2ecf20Sopenharmony_ci break; 11458c2ecf20Sopenharmony_ci default: 11468c2ecf20Sopenharmony_ci *bar = 0; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic int qlcnic_setup_pci_map(struct pci_dev *pdev, 11518c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci u32 offset; 11548c2ecf20Sopenharmony_ci void __iomem *mem_ptr0 = NULL; 11558c2ecf20Sopenharmony_ci unsigned long mem_len, pci_len0 = 0, bar0_len; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* remap phys address */ 11588c2ecf20Sopenharmony_ci mem_len = pci_resource_len(pdev, 0); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci qlcnic_get_bar_length(pdev->device, &bar0_len); 11618c2ecf20Sopenharmony_ci if (mem_len >= bar0_len) { 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci mem_ptr0 = pci_ioremap_bar(pdev, 0); 11648c2ecf20Sopenharmony_ci if (mem_ptr0 == NULL) { 11658c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to map PCI bar 0\n"); 11668c2ecf20Sopenharmony_ci return -EIO; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci pci_len0 = mem_len; 11698c2ecf20Sopenharmony_ci } else { 11708c2ecf20Sopenharmony_ci return -EIO; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%dKB memory map\n", (int)(mem_len >> 10)); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci ahw->pci_base0 = mem_ptr0; 11768c2ecf20Sopenharmony_ci ahw->pci_len0 = pci_len0; 11778c2ecf20Sopenharmony_ci offset = QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(ahw->pci_func)); 11788c2ecf20Sopenharmony_ci qlcnic_get_ioaddr(ahw, offset); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return 0; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic bool qlcnic_validate_subsystem_id(struct qlcnic_adapter *adapter, 11848c2ecf20Sopenharmony_ci int index) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 11878c2ecf20Sopenharmony_ci unsigned short subsystem_vendor; 11888c2ecf20Sopenharmony_ci bool ret = true; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci subsystem_vendor = pdev->subsystem_vendor; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X || 11938c2ecf20Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X) { 11948c2ecf20Sopenharmony_ci if (qlcnic_boards[index].sub_vendor == subsystem_vendor && 11958c2ecf20Sopenharmony_ci qlcnic_boards[index].sub_device == pdev->subsystem_device) 11968c2ecf20Sopenharmony_ci ret = true; 11978c2ecf20Sopenharmony_ci else 11988c2ecf20Sopenharmony_ci ret = false; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci return ret; 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 12078c2ecf20Sopenharmony_ci int i, found = 0; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) { 12108c2ecf20Sopenharmony_ci if (qlcnic_boards[i].vendor == pdev->vendor && 12118c2ecf20Sopenharmony_ci qlcnic_boards[i].device == pdev->device && 12128c2ecf20Sopenharmony_ci qlcnic_validate_subsystem_id(adapter, i)) { 12138c2ecf20Sopenharmony_ci found = 1; 12148c2ecf20Sopenharmony_ci break; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (!found) 12198c2ecf20Sopenharmony_ci sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr); 12208c2ecf20Sopenharmony_ci else 12218c2ecf20Sopenharmony_ci sprintf(name, "%pM: %s" , adapter->mac_addr, 12228c2ecf20Sopenharmony_ci qlcnic_boards[i].short_name); 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic void 12268c2ecf20Sopenharmony_ciqlcnic_check_options(struct qlcnic_adapter *adapter) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci int err; 12298c2ecf20Sopenharmony_ci u32 fw_major, fw_minor, fw_build, prev_fw_version; 12308c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 12318c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 12328c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci prev_fw_version = adapter->fw_version; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR); 12378c2ecf20Sopenharmony_ci fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR); 12388c2ecf20Sopenharmony_ci fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci err = qlcnic_get_board_info(adapter); 12438c2ecf20Sopenharmony_ci if (err) { 12448c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error getting board config info.\n"); 12458c2ecf20Sopenharmony_ci return; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) { 12488c2ecf20Sopenharmony_ci if (fw_dump->tmpl_hdr == NULL || 12498c2ecf20Sopenharmony_ci adapter->fw_version > prev_fw_version) { 12508c2ecf20Sopenharmony_ci vfree(fw_dump->tmpl_hdr); 12518c2ecf20Sopenharmony_ci if (!qlcnic_fw_cmd_get_minidump_temp(adapter)) 12528c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 12538c2ecf20Sopenharmony_ci "Supports FW dump capability\n"); 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Driver v%s, firmware v%d.%d.%d\n", 12588c2ecf20Sopenharmony_ci QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (adapter->ahw->port_type == QLCNIC_XGBE) { 12618c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { 12628c2ecf20Sopenharmony_ci adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF; 12638c2ecf20Sopenharmony_ci adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF; 12648c2ecf20Sopenharmony_ci } else { 12658c2ecf20Sopenharmony_ci adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; 12668c2ecf20Sopenharmony_ci adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; 12708c2ecf20Sopenharmony_ci adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci } else if (adapter->ahw->port_type == QLCNIC_GBE) { 12738c2ecf20Sopenharmony_ci adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; 12748c2ecf20Sopenharmony_ci adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; 12758c2ecf20Sopenharmony_ci adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; 12768c2ecf20Sopenharmony_ci adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci adapter->ahw->msix_supported = !!qlcnic_use_msi_x; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci adapter->num_txd = MAX_CMD_DESCRIPTORS; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci adapter->max_rds_rings = MAX_RDS_RINGS; 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic int 12878c2ecf20Sopenharmony_ciqlcnic_initialize_nic(struct qlcnic_adapter *adapter) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct qlcnic_info nic_info; 12908c2ecf20Sopenharmony_ci int err = 0; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci memset(&nic_info, 0, sizeof(struct qlcnic_info)); 12938c2ecf20Sopenharmony_ci err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func); 12948c2ecf20Sopenharmony_ci if (err) 12958c2ecf20Sopenharmony_ci return err; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci adapter->ahw->physical_port = (u8)nic_info.phys_port; 12988c2ecf20Sopenharmony_ci adapter->ahw->switch_mode = nic_info.switch_mode; 12998c2ecf20Sopenharmony_ci adapter->ahw->max_tx_ques = nic_info.max_tx_ques; 13008c2ecf20Sopenharmony_ci adapter->ahw->max_rx_ques = nic_info.max_rx_ques; 13018c2ecf20Sopenharmony_ci adapter->ahw->capabilities = nic_info.capabilities; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) { 13048c2ecf20Sopenharmony_ci u32 temp; 13058c2ecf20Sopenharmony_ci temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err); 13068c2ecf20Sopenharmony_ci if (err == -EIO) 13078c2ecf20Sopenharmony_ci return err; 13088c2ecf20Sopenharmony_ci adapter->ahw->extra_capability[0] = temp; 13098c2ecf20Sopenharmony_ci } else { 13108c2ecf20Sopenharmony_ci adapter->ahw->extra_capability[0] = 0; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci adapter->ahw->max_mac_filters = nic_info.max_mac_filters; 13148c2ecf20Sopenharmony_ci adapter->ahw->max_mtu = nic_info.max_mtu; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (adapter->ahw->capabilities & BIT_6) { 13178c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_ESWITCH_ENABLED; 13188c2ecf20Sopenharmony_ci adapter->ahw->nic_mode = QLCNIC_VNIC_MODE; 13198c2ecf20Sopenharmony_ci adapter->max_tx_rings = QLCNIC_MAX_HW_VNIC_TX_RINGS; 13208c2ecf20Sopenharmony_ci adapter->max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "vNIC mode enabled.\n"); 13238c2ecf20Sopenharmony_ci } else { 13248c2ecf20Sopenharmony_ci adapter->ahw->nic_mode = QLCNIC_DEFAULT_MODE; 13258c2ecf20Sopenharmony_ci adapter->max_tx_rings = QLCNIC_MAX_HW_TX_RINGS; 13268c2ecf20Sopenharmony_ci adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS; 13278c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci return err; 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_civoid qlcnic_set_vlan_config(struct qlcnic_adapter *adapter, 13348c2ecf20Sopenharmony_ci struct qlcnic_esw_func_cfg *esw_cfg) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci if (esw_cfg->discard_tagged) 13378c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_TAGGING_ENABLED; 13388c2ecf20Sopenharmony_ci else 13398c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_TAGGING_ENABLED; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci if (esw_cfg->vlan_id) { 13428c2ecf20Sopenharmony_ci adapter->rx_pvid = esw_cfg->vlan_id; 13438c2ecf20Sopenharmony_ci adapter->tx_pvid = esw_cfg->vlan_id; 13448c2ecf20Sopenharmony_ci } else { 13458c2ecf20Sopenharmony_ci adapter->rx_pvid = 0; 13468c2ecf20Sopenharmony_ci adapter->tx_pvid = 0; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic int 13518c2ecf20Sopenharmony_ciqlcnic_vlan_rx_add(struct net_device *netdev, __be16 proto, u16 vid) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 13548c2ecf20Sopenharmony_ci int err; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (qlcnic_sriov_vf_check(adapter)) { 13578c2ecf20Sopenharmony_ci err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 1); 13588c2ecf20Sopenharmony_ci if (err) { 13598c2ecf20Sopenharmony_ci netdev_err(netdev, 13608c2ecf20Sopenharmony_ci "Cannot add VLAN filter for VLAN id %d, err=%d", 13618c2ecf20Sopenharmony_ci vid, err); 13628c2ecf20Sopenharmony_ci return err; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci set_bit(vid, adapter->vlans); 13678c2ecf20Sopenharmony_ci return 0; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic int 13718c2ecf20Sopenharmony_ciqlcnic_vlan_rx_del(struct net_device *netdev, __be16 proto, u16 vid) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 13748c2ecf20Sopenharmony_ci int err; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (qlcnic_sriov_vf_check(adapter)) { 13778c2ecf20Sopenharmony_ci err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 0); 13788c2ecf20Sopenharmony_ci if (err) { 13798c2ecf20Sopenharmony_ci netdev_err(netdev, 13808c2ecf20Sopenharmony_ci "Cannot delete VLAN filter for VLAN id %d, err=%d", 13818c2ecf20Sopenharmony_ci vid, err); 13828c2ecf20Sopenharmony_ci return err; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci qlcnic_restore_indev_addr(netdev, NETDEV_DOWN); 13878c2ecf20Sopenharmony_ci clear_bit(vid, adapter->vlans); 13888c2ecf20Sopenharmony_ci return 0; 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_civoid qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter, 13928c2ecf20Sopenharmony_ci struct qlcnic_esw_func_cfg *esw_cfg) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci adapter->flags &= ~(QLCNIC_MACSPOOF | QLCNIC_MAC_OVERRIDE_DISABLED | 13958c2ecf20Sopenharmony_ci QLCNIC_PROMISC_DISABLED); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (esw_cfg->mac_anti_spoof) 13988c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_MACSPOOF; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!esw_cfg->mac_override) 14018c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_MAC_OVERRIDE_DISABLED; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci if (!esw_cfg->promisc_mode) 14048c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_PROMISC_DISABLED; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ciint qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci struct qlcnic_esw_func_cfg esw_cfg; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) 14128c2ecf20Sopenharmony_ci return 0; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci esw_cfg.pci_func = adapter->ahw->pci_func; 14158c2ecf20Sopenharmony_ci if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg)) 14168c2ecf20Sopenharmony_ci return -EIO; 14178c2ecf20Sopenharmony_ci qlcnic_set_vlan_config(adapter, &esw_cfg); 14188c2ecf20Sopenharmony_ci qlcnic_set_eswitch_port_features(adapter, &esw_cfg); 14198c2ecf20Sopenharmony_ci qlcnic_set_netdev_features(adapter, &esw_cfg); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci return 0; 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_civoid qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, 14258c2ecf20Sopenharmony_ci struct qlcnic_esw_func_cfg *esw_cfg) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 14308c2ecf20Sopenharmony_ci return; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci adapter->offload_flags = esw_cfg->offload_flags; 14338c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_APP_CHANGED_FLAGS; 14348c2ecf20Sopenharmony_ci netdev_update_features(netdev); 14358c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_APP_CHANGED_FLAGS; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic int 14398c2ecf20Sopenharmony_ciqlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci u32 op_mode, priv_level; 14428c2ecf20Sopenharmony_ci int err = 0; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci err = qlcnic_initialize_nic(adapter); 14458c2ecf20Sopenharmony_ci if (err) 14468c2ecf20Sopenharmony_ci return err; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED) 14498c2ecf20Sopenharmony_ci return 0; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE); 14528c2ecf20Sopenharmony_ci priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (op_mode == QLC_DEV_DRV_DEFAULT) 14558c2ecf20Sopenharmony_ci priv_level = QLCNIC_MGMT_FUNC; 14568c2ecf20Sopenharmony_ci else 14578c2ecf20Sopenharmony_ci priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { 14608c2ecf20Sopenharmony_ci if (priv_level == QLCNIC_MGMT_FUNC) { 14618c2ecf20Sopenharmony_ci adapter->ahw->op_mode = QLCNIC_MGMT_FUNC; 14628c2ecf20Sopenharmony_ci err = qlcnic_init_pci_info(adapter); 14638c2ecf20Sopenharmony_ci if (err) 14648c2ecf20Sopenharmony_ci return err; 14658c2ecf20Sopenharmony_ci /* Set privilege level for other functions */ 14668c2ecf20Sopenharmony_ci qlcnic_set_function_modes(adapter); 14678c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, 14688c2ecf20Sopenharmony_ci "HAL Version: %d, Management function\n", 14698c2ecf20Sopenharmony_ci adapter->ahw->fw_hal_version); 14708c2ecf20Sopenharmony_ci } else if (priv_level == QLCNIC_PRIV_FUNC) { 14718c2ecf20Sopenharmony_ci adapter->ahw->op_mode = QLCNIC_PRIV_FUNC; 14728c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, 14738c2ecf20Sopenharmony_ci "HAL Version: %d, Privileged function\n", 14748c2ecf20Sopenharmony_ci adapter->ahw->fw_hal_version); 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci } else { 14778c2ecf20Sopenharmony_ci adapter->ahw->nic_mode = QLCNIC_DEFAULT_MODE; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_ADAPTER_INITIALIZED; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci return err; 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ciint qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci struct qlcnic_esw_func_cfg esw_cfg; 14888c2ecf20Sopenharmony_ci struct qlcnic_npar_info *npar; 14898c2ecf20Sopenharmony_ci u8 i; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (adapter->need_fw_reset) 14928c2ecf20Sopenharmony_ci return 0; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci for (i = 0; i < adapter->ahw->total_nic_func; i++) { 14958c2ecf20Sopenharmony_ci if (!adapter->npars[i].eswitch_status) 14968c2ecf20Sopenharmony_ci continue; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci memset(&esw_cfg, 0, sizeof(struct qlcnic_esw_func_cfg)); 14998c2ecf20Sopenharmony_ci esw_cfg.pci_func = adapter->npars[i].pci_func; 15008c2ecf20Sopenharmony_ci esw_cfg.mac_override = BIT_0; 15018c2ecf20Sopenharmony_ci esw_cfg.promisc_mode = BIT_0; 15028c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) { 15038c2ecf20Sopenharmony_ci esw_cfg.offload_flags = BIT_0; 15048c2ecf20Sopenharmony_ci if (QLCNIC_IS_TSO_CAPABLE(adapter)) 15058c2ecf20Sopenharmony_ci esw_cfg.offload_flags |= (BIT_1 | BIT_2); 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci if (qlcnic_config_switch_port(adapter, &esw_cfg)) 15088c2ecf20Sopenharmony_ci return -EIO; 15098c2ecf20Sopenharmony_ci npar = &adapter->npars[i]; 15108c2ecf20Sopenharmony_ci npar->pvid = esw_cfg.vlan_id; 15118c2ecf20Sopenharmony_ci npar->mac_override = esw_cfg.mac_override; 15128c2ecf20Sopenharmony_ci npar->mac_anti_spoof = esw_cfg.mac_anti_spoof; 15138c2ecf20Sopenharmony_ci npar->discard_tagged = esw_cfg.discard_tagged; 15148c2ecf20Sopenharmony_ci npar->promisc_mode = esw_cfg.promisc_mode; 15158c2ecf20Sopenharmony_ci npar->offload_flags = esw_cfg.offload_flags; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci return 0; 15198c2ecf20Sopenharmony_ci} 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_cistatic int 15238c2ecf20Sopenharmony_ciqlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter, 15248c2ecf20Sopenharmony_ci struct qlcnic_npar_info *npar, int pci_func) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct qlcnic_esw_func_cfg esw_cfg; 15278c2ecf20Sopenharmony_ci esw_cfg.op_mode = QLCNIC_PORT_DEFAULTS; 15288c2ecf20Sopenharmony_ci esw_cfg.pci_func = pci_func; 15298c2ecf20Sopenharmony_ci esw_cfg.vlan_id = npar->pvid; 15308c2ecf20Sopenharmony_ci esw_cfg.mac_override = npar->mac_override; 15318c2ecf20Sopenharmony_ci esw_cfg.discard_tagged = npar->discard_tagged; 15328c2ecf20Sopenharmony_ci esw_cfg.mac_anti_spoof = npar->mac_anti_spoof; 15338c2ecf20Sopenharmony_ci esw_cfg.offload_flags = npar->offload_flags; 15348c2ecf20Sopenharmony_ci esw_cfg.promisc_mode = npar->promisc_mode; 15358c2ecf20Sopenharmony_ci if (qlcnic_config_switch_port(adapter, &esw_cfg)) 15368c2ecf20Sopenharmony_ci return -EIO; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci esw_cfg.op_mode = QLCNIC_ADD_VLAN; 15398c2ecf20Sopenharmony_ci if (qlcnic_config_switch_port(adapter, &esw_cfg)) 15408c2ecf20Sopenharmony_ci return -EIO; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci return 0; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ciint qlcnic_reset_npar_config(struct qlcnic_adapter *adapter) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci int i, err; 15488c2ecf20Sopenharmony_ci struct qlcnic_npar_info *npar; 15498c2ecf20Sopenharmony_ci struct qlcnic_info nic_info; 15508c2ecf20Sopenharmony_ci u8 pci_func; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 15538c2ecf20Sopenharmony_ci if (!adapter->need_fw_reset) 15548c2ecf20Sopenharmony_ci return 0; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci /* Set the NPAR config data after FW reset */ 15578c2ecf20Sopenharmony_ci for (i = 0; i < adapter->ahw->total_nic_func; i++) { 15588c2ecf20Sopenharmony_ci npar = &adapter->npars[i]; 15598c2ecf20Sopenharmony_ci pci_func = npar->pci_func; 15608c2ecf20Sopenharmony_ci if (!adapter->npars[i].eswitch_status) 15618c2ecf20Sopenharmony_ci continue; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci memset(&nic_info, 0, sizeof(struct qlcnic_info)); 15648c2ecf20Sopenharmony_ci err = qlcnic_get_nic_info(adapter, &nic_info, pci_func); 15658c2ecf20Sopenharmony_ci if (err) 15668c2ecf20Sopenharmony_ci return err; 15678c2ecf20Sopenharmony_ci nic_info.min_tx_bw = npar->min_bw; 15688c2ecf20Sopenharmony_ci nic_info.max_tx_bw = npar->max_bw; 15698c2ecf20Sopenharmony_ci err = qlcnic_set_nic_info(adapter, &nic_info); 15708c2ecf20Sopenharmony_ci if (err) 15718c2ecf20Sopenharmony_ci return err; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (npar->enable_pm) { 15748c2ecf20Sopenharmony_ci err = qlcnic_config_port_mirroring(adapter, 15758c2ecf20Sopenharmony_ci npar->dest_npar, 1, 15768c2ecf20Sopenharmony_ci pci_func); 15778c2ecf20Sopenharmony_ci if (err) 15788c2ecf20Sopenharmony_ci return err; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci err = qlcnic_reset_eswitch_config(adapter, npar, pci_func); 15818c2ecf20Sopenharmony_ci if (err) 15828c2ecf20Sopenharmony_ci return err; 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci return 0; 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci u8 npar_opt_timeo = QLCNIC_DEV_NPAR_OPER_TIMEO; 15908c2ecf20Sopenharmony_ci u32 npar_state; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) 15938c2ecf20Sopenharmony_ci return 0; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci npar_state = QLC_SHARED_REG_RD32(adapter, 15968c2ecf20Sopenharmony_ci QLCNIC_CRB_DEV_NPAR_STATE); 15978c2ecf20Sopenharmony_ci while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) { 15988c2ecf20Sopenharmony_ci msleep(1000); 15998c2ecf20Sopenharmony_ci npar_state = QLC_SHARED_REG_RD32(adapter, 16008c2ecf20Sopenharmony_ci QLCNIC_CRB_DEV_NPAR_STATE); 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci if (!npar_opt_timeo) { 16038c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 16048c2ecf20Sopenharmony_ci "Waiting for NPAR state to operational timeout\n"); 16058c2ecf20Sopenharmony_ci return -EIO; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci return 0; 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic int 16118c2ecf20Sopenharmony_ciqlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter) 16128c2ecf20Sopenharmony_ci{ 16138c2ecf20Sopenharmony_ci int err; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) || 16168c2ecf20Sopenharmony_ci adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) 16178c2ecf20Sopenharmony_ci return 0; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci err = qlcnic_set_default_offload_settings(adapter); 16208c2ecf20Sopenharmony_ci if (err) 16218c2ecf20Sopenharmony_ci return err; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci err = qlcnic_reset_npar_config(adapter); 16248c2ecf20Sopenharmony_ci if (err) 16258c2ecf20Sopenharmony_ci return err; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci qlcnic_dev_set_npar_ready(adapter); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci return err; 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci int err; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci err = qlcnic_can_start_firmware(adapter); 16378c2ecf20Sopenharmony_ci if (err < 0) 16388c2ecf20Sopenharmony_ci return err; 16398c2ecf20Sopenharmony_ci else if (!err) 16408c2ecf20Sopenharmony_ci goto check_fw_status; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (qlcnic_load_fw_file) 16438c2ecf20Sopenharmony_ci qlcnic_request_firmware(adapter); 16448c2ecf20Sopenharmony_ci else { 16458c2ecf20Sopenharmony_ci err = qlcnic_check_flash_fw_ver(adapter); 16468c2ecf20Sopenharmony_ci if (err) 16478c2ecf20Sopenharmony_ci goto err_out; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci adapter->ahw->fw_type = QLCNIC_FLASH_ROMIMAGE; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci err = qlcnic_need_fw_reset(adapter); 16538c2ecf20Sopenharmony_ci if (err == 0) 16548c2ecf20Sopenharmony_ci goto check_fw_status; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci err = qlcnic_pinit_from_rom(adapter); 16578c2ecf20Sopenharmony_ci if (err) 16588c2ecf20Sopenharmony_ci goto err_out; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci err = qlcnic_load_firmware(adapter); 16618c2ecf20Sopenharmony_ci if (err) 16628c2ecf20Sopenharmony_ci goto err_out; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci qlcnic_release_firmware(adapter); 16658c2ecf20Sopenharmony_ci QLCWR32(adapter, CRB_DRIVER_VERSION, QLCNIC_DRIVER_VERSION); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_cicheck_fw_status: 16688c2ecf20Sopenharmony_ci err = qlcnic_check_fw_status(adapter); 16698c2ecf20Sopenharmony_ci if (err) 16708c2ecf20Sopenharmony_ci goto err_out; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY); 16738c2ecf20Sopenharmony_ci qlcnic_idc_debug_info(adapter, 1); 16748c2ecf20Sopenharmony_ci err = qlcnic_check_eswitch_mode(adapter); 16758c2ecf20Sopenharmony_ci if (err) { 16768c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 16778c2ecf20Sopenharmony_ci "Memory allocation failed for eswitch\n"); 16788c2ecf20Sopenharmony_ci goto err_out; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci err = qlcnic_set_mgmt_operations(adapter); 16818c2ecf20Sopenharmony_ci if (err) 16828c2ecf20Sopenharmony_ci goto err_out; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci qlcnic_check_options(adapter); 16858c2ecf20Sopenharmony_ci adapter->need_fw_reset = 0; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci qlcnic_release_firmware(adapter); 16888c2ecf20Sopenharmony_ci return 0; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_cierr_out: 16918c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED); 16928c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "Device state set to failed\n"); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci qlcnic_release_firmware(adapter); 16958c2ecf20Sopenharmony_ci return err; 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic int 16998c2ecf20Sopenharmony_ciqlcnic_request_irq(struct qlcnic_adapter *adapter) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci irq_handler_t handler; 17028c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 17038c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 17048c2ecf20Sopenharmony_ci int err, ring, num_sds_rings; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci unsigned long flags = 0; 17078c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 17088c2ecf20Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { 17118c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 17128c2ecf20Sopenharmony_ci handler = qlcnic_tmp_intr; 17138c2ecf20Sopenharmony_ci else 17148c2ecf20Sopenharmony_ci handler = qlcnic_83xx_tmp_intr; 17158c2ecf20Sopenharmony_ci if (!QLCNIC_IS_MSI_FAMILY(adapter)) 17168c2ecf20Sopenharmony_ci flags |= IRQF_SHARED; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci } else { 17198c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_MSIX_ENABLED) 17208c2ecf20Sopenharmony_ci handler = qlcnic_msix_intr; 17218c2ecf20Sopenharmony_ci else if (adapter->flags & QLCNIC_MSI_ENABLED) 17228c2ecf20Sopenharmony_ci handler = qlcnic_msi_intr; 17238c2ecf20Sopenharmony_ci else { 17248c2ecf20Sopenharmony_ci flags |= IRQF_SHARED; 17258c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 17268c2ecf20Sopenharmony_ci handler = qlcnic_intr; 17278c2ecf20Sopenharmony_ci else 17288c2ecf20Sopenharmony_ci handler = qlcnic_83xx_intr; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci adapter->irq = netdev->irq; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) { 17348c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter) || 17358c2ecf20Sopenharmony_ci (qlcnic_83xx_check(adapter) && 17368c2ecf20Sopenharmony_ci (adapter->flags & QLCNIC_MSIX_ENABLED))) { 17378c2ecf20Sopenharmony_ci num_sds_rings = adapter->drv_sds_rings; 17388c2ecf20Sopenharmony_ci for (ring = 0; ring < num_sds_rings; ring++) { 17398c2ecf20Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 17408c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter) && 17418c2ecf20Sopenharmony_ci !qlcnic_check_multi_tx(adapter) && 17428c2ecf20Sopenharmony_ci (ring == (num_sds_rings - 1))) { 17438c2ecf20Sopenharmony_ci if (!(adapter->flags & 17448c2ecf20Sopenharmony_ci QLCNIC_MSIX_ENABLED)) 17458c2ecf20Sopenharmony_ci snprintf(sds_ring->name, 17468c2ecf20Sopenharmony_ci sizeof(sds_ring->name), 17478c2ecf20Sopenharmony_ci "qlcnic"); 17488c2ecf20Sopenharmony_ci else 17498c2ecf20Sopenharmony_ci snprintf(sds_ring->name, 17508c2ecf20Sopenharmony_ci sizeof(sds_ring->name), 17518c2ecf20Sopenharmony_ci "%s-tx-0-rx-%d", 17528c2ecf20Sopenharmony_ci netdev->name, ring); 17538c2ecf20Sopenharmony_ci } else { 17548c2ecf20Sopenharmony_ci snprintf(sds_ring->name, 17558c2ecf20Sopenharmony_ci sizeof(sds_ring->name), 17568c2ecf20Sopenharmony_ci "%s-rx-%d", 17578c2ecf20Sopenharmony_ci netdev->name, ring); 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci err = request_irq(sds_ring->irq, handler, flags, 17608c2ecf20Sopenharmony_ci sds_ring->name, sds_ring); 17618c2ecf20Sopenharmony_ci if (err) 17628c2ecf20Sopenharmony_ci return err; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci if ((qlcnic_82xx_check(adapter) && 17668c2ecf20Sopenharmony_ci qlcnic_check_multi_tx(adapter)) || 17678c2ecf20Sopenharmony_ci (qlcnic_83xx_check(adapter) && 17688c2ecf20Sopenharmony_ci (adapter->flags & QLCNIC_MSIX_ENABLED) && 17698c2ecf20Sopenharmony_ci !(adapter->flags & QLCNIC_TX_INTR_SHARED))) { 17708c2ecf20Sopenharmony_ci handler = qlcnic_msix_tx_intr; 17718c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; 17728c2ecf20Sopenharmony_ci ring++) { 17738c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 17748c2ecf20Sopenharmony_ci snprintf(tx_ring->name, sizeof(tx_ring->name), 17758c2ecf20Sopenharmony_ci "%s-tx-%d", netdev->name, ring); 17768c2ecf20Sopenharmony_ci err = request_irq(tx_ring->irq, handler, flags, 17778c2ecf20Sopenharmony_ci tx_ring->name, tx_ring); 17788c2ecf20Sopenharmony_ci if (err) 17798c2ecf20Sopenharmony_ci return err; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci return 0; 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_cistatic void 17878c2ecf20Sopenharmony_ciqlcnic_free_irq(struct qlcnic_adapter *adapter) 17888c2ecf20Sopenharmony_ci{ 17898c2ecf20Sopenharmony_ci int ring; 17908c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 17918c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) { 17968c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter) || 17978c2ecf20Sopenharmony_ci (qlcnic_83xx_check(adapter) && 17988c2ecf20Sopenharmony_ci (adapter->flags & QLCNIC_MSIX_ENABLED))) { 17998c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 18008c2ecf20Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 18018c2ecf20Sopenharmony_ci free_irq(sds_ring->irq, sds_ring); 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci if ((qlcnic_83xx_check(adapter) && 18058c2ecf20Sopenharmony_ci !(adapter->flags & QLCNIC_TX_INTR_SHARED)) || 18068c2ecf20Sopenharmony_ci (qlcnic_82xx_check(adapter) && 18078c2ecf20Sopenharmony_ci qlcnic_check_multi_tx(adapter))) { 18088c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; 18098c2ecf20Sopenharmony_ci ring++) { 18108c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 18118c2ecf20Sopenharmony_ci if (tx_ring->irq) 18128c2ecf20Sopenharmony_ci free_irq(tx_ring->irq, tx_ring); 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci} 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_cistatic void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci u32 capab = 0; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) { 18238c2ecf20Sopenharmony_ci if (adapter->ahw->extra_capability[0] & 18248c2ecf20Sopenharmony_ci QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG) 18258c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_FW_LRO_MSS_CAP; 18268c2ecf20Sopenharmony_ci } else { 18278c2ecf20Sopenharmony_ci capab = adapter->ahw->capabilities; 18288c2ecf20Sopenharmony_ci if (QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(capab)) 18298c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_FW_LRO_MSS_CAP; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci} 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic int qlcnic_config_def_intr_coalesce(struct qlcnic_adapter *adapter) 18348c2ecf20Sopenharmony_ci{ 18358c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 18368c2ecf20Sopenharmony_ci int err; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci /* Initialize interrupt coalesce parameters */ 18398c2ecf20Sopenharmony_ci ahw->coal.flag = QLCNIC_INTR_DEFAULT; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 18428c2ecf20Sopenharmony_ci ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX; 18438c2ecf20Sopenharmony_ci ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; 18448c2ecf20Sopenharmony_ci ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; 18458c2ecf20Sopenharmony_ci ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; 18468c2ecf20Sopenharmony_ci ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci err = qlcnic_83xx_set_rx_tx_intr_coal(adapter); 18498c2ecf20Sopenharmony_ci } else { 18508c2ecf20Sopenharmony_ci ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; 18518c2ecf20Sopenharmony_ci ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; 18528c2ecf20Sopenharmony_ci ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci err = qlcnic_82xx_set_rx_coalesce(adapter); 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci return err; 18588c2ecf20Sopenharmony_ci} 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ciint __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci int ring; 18638c2ecf20Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 18668c2ecf20Sopenharmony_ci return -EIO; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) 18698c2ecf20Sopenharmony_ci return 0; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (qlcnic_set_eswitch_port_config(adapter)) 18728c2ecf20Sopenharmony_ci return -EIO; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci qlcnic_get_lro_mss_capability(adapter); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci if (qlcnic_fw_create_ctx(adapter)) 18778c2ecf20Sopenharmony_ci return -EIO; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->max_rds_rings; ring++) { 18808c2ecf20Sopenharmony_ci rds_ring = &adapter->recv_ctx->rds_rings[ring]; 18818c2ecf20Sopenharmony_ci qlcnic_post_rx_buffers(adapter, rds_ring, ring); 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci qlcnic_set_multi(netdev); 18858c2ecf20Sopenharmony_ci qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci adapter->ahw->linkup = 0; 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci if (adapter->drv_sds_rings > 1) 18908c2ecf20Sopenharmony_ci qlcnic_config_rss(adapter, 1); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci qlcnic_config_def_intr_coalesce(adapter); 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (netdev->features & NETIF_F_LRO) 18958c2ecf20Sopenharmony_ci qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci set_bit(__QLCNIC_DEV_UP, &adapter->state); 18988c2ecf20Sopenharmony_ci qlcnic_napi_enable(adapter); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci qlcnic_linkevent_request(adapter, 1); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci adapter->ahw->reset_context = 0; 19038c2ecf20Sopenharmony_ci netif_tx_start_all_queues(netdev); 19048c2ecf20Sopenharmony_ci return 0; 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ciint qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) 19088c2ecf20Sopenharmony_ci{ 19098c2ecf20Sopenharmony_ci int err = 0; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci rtnl_lock(); 19128c2ecf20Sopenharmony_ci if (netif_running(netdev)) 19138c2ecf20Sopenharmony_ci err = __qlcnic_up(adapter, netdev); 19148c2ecf20Sopenharmony_ci rtnl_unlock(); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci return err; 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_civoid __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci int ring; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 19248c2ecf20Sopenharmony_ci return; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state)) 19278c2ecf20Sopenharmony_ci return; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci smp_mb(); 19308c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 19318c2ecf20Sopenharmony_ci adapter->ahw->linkup = 0; 19328c2ecf20Sopenharmony_ci netif_tx_disable(netdev); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci qlcnic_free_mac_list(adapter); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (adapter->fhash.fnum) 19378c2ecf20Sopenharmony_ci qlcnic_delete_lb_filters(adapter); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE); 19408c2ecf20Sopenharmony_ci if (qlcnic_sriov_vf_check(adapter)) 19418c2ecf20Sopenharmony_ci qlcnic_sriov_cleanup_async_list(&adapter->ahw->sriov->bc); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci qlcnic_napi_disable(adapter); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci qlcnic_fw_destroy_ctx(adapter); 19468c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci qlcnic_reset_rx_buffers_list(adapter); 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) 19518c2ecf20Sopenharmony_ci qlcnic_release_tx_buffers(adapter, &adapter->tx_ring[ring]); 19528c2ecf20Sopenharmony_ci} 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci/* Usage: During suspend and firmware recovery module */ 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_civoid qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci rtnl_lock(); 19598c2ecf20Sopenharmony_ci if (netif_running(netdev)) 19608c2ecf20Sopenharmony_ci __qlcnic_down(adapter, netdev); 19618c2ecf20Sopenharmony_ci rtnl_unlock(); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci} 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ciint 19668c2ecf20Sopenharmony_ciqlcnic_attach(struct qlcnic_adapter *adapter) 19678c2ecf20Sopenharmony_ci{ 19688c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 19698c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 19708c2ecf20Sopenharmony_ci int err; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) 19738c2ecf20Sopenharmony_ci return 0; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci err = qlcnic_napi_add(adapter, netdev); 19768c2ecf20Sopenharmony_ci if (err) 19778c2ecf20Sopenharmony_ci return err; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci err = qlcnic_alloc_sw_resources(adapter); 19808c2ecf20Sopenharmony_ci if (err) { 19818c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error in setting sw resources\n"); 19828c2ecf20Sopenharmony_ci goto err_out_napi_del; 19838c2ecf20Sopenharmony_ci } 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci err = qlcnic_alloc_hw_resources(adapter); 19868c2ecf20Sopenharmony_ci if (err) { 19878c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error in setting hw resources\n"); 19888c2ecf20Sopenharmony_ci goto err_out_free_sw; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci err = qlcnic_request_irq(adapter); 19928c2ecf20Sopenharmony_ci if (err) { 19938c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to setup interrupt\n"); 19948c2ecf20Sopenharmony_ci goto err_out_free_hw; 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci qlcnic_create_sysfs_entries(adapter); 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci if (qlcnic_encap_rx_offload(adapter)) 20008c2ecf20Sopenharmony_ci udp_tunnel_nic_reset_ntf(netdev); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; 20038c2ecf20Sopenharmony_ci return 0; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_cierr_out_free_hw: 20068c2ecf20Sopenharmony_ci qlcnic_free_hw_resources(adapter); 20078c2ecf20Sopenharmony_cierr_out_free_sw: 20088c2ecf20Sopenharmony_ci qlcnic_free_sw_resources(adapter); 20098c2ecf20Sopenharmony_cierr_out_napi_del: 20108c2ecf20Sopenharmony_ci qlcnic_napi_del(adapter); 20118c2ecf20Sopenharmony_ci return err; 20128c2ecf20Sopenharmony_ci} 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_civoid qlcnic_detach(struct qlcnic_adapter *adapter) 20158c2ecf20Sopenharmony_ci{ 20168c2ecf20Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 20178c2ecf20Sopenharmony_ci return; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci qlcnic_remove_sysfs_entries(adapter); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci qlcnic_free_hw_resources(adapter); 20228c2ecf20Sopenharmony_ci qlcnic_release_rx_buffers(adapter); 20238c2ecf20Sopenharmony_ci qlcnic_free_irq(adapter); 20248c2ecf20Sopenharmony_ci qlcnic_napi_del(adapter); 20258c2ecf20Sopenharmony_ci qlcnic_free_sw_resources(adapter); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci adapter->is_up = 0; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_civoid qlcnic_diag_free_res(struct net_device *netdev, int drv_sds_rings) 20318c2ecf20Sopenharmony_ci{ 20328c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 20338c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 20348c2ecf20Sopenharmony_ci int drv_tx_rings = adapter->drv_tx_rings; 20358c2ecf20Sopenharmony_ci int ring; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_DEV_UP, &adapter->state); 20388c2ecf20Sopenharmony_ci if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { 20398c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 20408c2ecf20Sopenharmony_ci sds_ring = &adapter->recv_ctx->sds_rings[ring]; 20418c2ecf20Sopenharmony_ci qlcnic_disable_sds_intr(adapter, sds_ring); 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci qlcnic_fw_destroy_ctx(adapter); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci adapter->ahw->diag_test = 0; 20508c2ecf20Sopenharmony_ci adapter->drv_sds_rings = drv_sds_rings; 20518c2ecf20Sopenharmony_ci adapter->drv_tx_rings = drv_tx_rings; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci if (qlcnic_attach(adapter)) 20548c2ecf20Sopenharmony_ci goto out; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci if (netif_running(netdev)) 20578c2ecf20Sopenharmony_ci __qlcnic_up(adapter, netdev); 20588c2ecf20Sopenharmony_ciout: 20598c2ecf20Sopenharmony_ci netif_device_attach(netdev); 20608c2ecf20Sopenharmony_ci} 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_cistatic int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 20658c2ecf20Sopenharmony_ci int err = 0; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context), 20688c2ecf20Sopenharmony_ci GFP_KERNEL); 20698c2ecf20Sopenharmony_ci if (!adapter->recv_ctx) { 20708c2ecf20Sopenharmony_ci err = -ENOMEM; 20718c2ecf20Sopenharmony_ci goto err_out; 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 20758c2ecf20Sopenharmony_ci ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX; 20768c2ecf20Sopenharmony_ci ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; 20778c2ecf20Sopenharmony_ci ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; 20788c2ecf20Sopenharmony_ci ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; 20798c2ecf20Sopenharmony_ci ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; 20808c2ecf20Sopenharmony_ci } else { 20818c2ecf20Sopenharmony_ci ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; 20828c2ecf20Sopenharmony_ci ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; 20838c2ecf20Sopenharmony_ci ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* clear stats */ 20878c2ecf20Sopenharmony_ci memset(&adapter->stats, 0, sizeof(adapter->stats)); 20888c2ecf20Sopenharmony_cierr_out: 20898c2ecf20Sopenharmony_ci return err; 20908c2ecf20Sopenharmony_ci} 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cistatic void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter) 20938c2ecf20Sopenharmony_ci{ 20948c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci kfree(adapter->recv_ctx); 20978c2ecf20Sopenharmony_ci adapter->recv_ctx = NULL; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci if (fw_dump->tmpl_hdr) { 21008c2ecf20Sopenharmony_ci vfree(fw_dump->tmpl_hdr); 21018c2ecf20Sopenharmony_ci fw_dump->tmpl_hdr = NULL; 21028c2ecf20Sopenharmony_ci } 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci if (fw_dump->dma_buffer) { 21058c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, QLC_PEX_DMA_READ_SIZE, 21068c2ecf20Sopenharmony_ci fw_dump->dma_buffer, fw_dump->phys_addr); 21078c2ecf20Sopenharmony_ci fw_dump->dma_buffer = NULL; 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci kfree(adapter->ahw->reset.buff); 21118c2ecf20Sopenharmony_ci adapter->ahw->fw_dump.tmpl_hdr = NULL; 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ciint qlcnic_diag_alloc_res(struct net_device *netdev, int test) 21158c2ecf20Sopenharmony_ci{ 21168c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 21178c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 21188c2ecf20Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 21198c2ecf20Sopenharmony_ci int ring; 21208c2ecf20Sopenharmony_ci int ret; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci netif_device_detach(netdev); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci if (netif_running(netdev)) 21258c2ecf20Sopenharmony_ci __qlcnic_down(adapter, netdev); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci adapter->drv_sds_rings = QLCNIC_SINGLE_RING; 21308c2ecf20Sopenharmony_ci adapter->ahw->diag_test = test; 21318c2ecf20Sopenharmony_ci adapter->ahw->linkup = 0; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci ret = qlcnic_attach(adapter); 21348c2ecf20Sopenharmony_ci if (ret) { 21358c2ecf20Sopenharmony_ci netif_device_attach(netdev); 21368c2ecf20Sopenharmony_ci return ret; 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci ret = qlcnic_fw_create_ctx(adapter); 21408c2ecf20Sopenharmony_ci if (ret) { 21418c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 21428c2ecf20Sopenharmony_ci netif_device_attach(netdev); 21438c2ecf20Sopenharmony_ci return ret; 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->max_rds_rings; ring++) { 21478c2ecf20Sopenharmony_ci rds_ring = &adapter->recv_ctx->rds_rings[ring]; 21488c2ecf20Sopenharmony_ci qlcnic_post_rx_buffers(adapter, rds_ring, ring); 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { 21528c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 21538c2ecf20Sopenharmony_ci sds_ring = &adapter->recv_ctx->sds_rings[ring]; 21548c2ecf20Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { 21598c2ecf20Sopenharmony_ci adapter->ahw->loopback_state = 0; 21608c2ecf20Sopenharmony_ci qlcnic_linkevent_request(adapter, 1); 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci set_bit(__QLCNIC_DEV_UP, &adapter->state); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci return 0; 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci/* Reset context in hardware only */ 21698c2ecf20Sopenharmony_cistatic int 21708c2ecf20Sopenharmony_ciqlcnic_reset_hw_context(struct qlcnic_adapter *adapter) 21718c2ecf20Sopenharmony_ci{ 21728c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 21758c2ecf20Sopenharmony_ci return -EBUSY; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci netif_device_detach(netdev); 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci qlcnic_down(adapter, netdev); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci qlcnic_up(adapter, netdev); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci netif_device_attach(netdev); 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 21868c2ecf20Sopenharmony_ci netdev_info(adapter->netdev, "%s: soft reset complete\n", __func__); 21878c2ecf20Sopenharmony_ci return 0; 21888c2ecf20Sopenharmony_ci} 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ciint 21918c2ecf20Sopenharmony_ciqlcnic_reset_context(struct qlcnic_adapter *adapter) 21928c2ecf20Sopenharmony_ci{ 21938c2ecf20Sopenharmony_ci int err = 0; 21948c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 21978c2ecf20Sopenharmony_ci return -EBUSY; 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) { 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci netif_device_detach(netdev); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (netif_running(netdev)) 22048c2ecf20Sopenharmony_ci __qlcnic_down(adapter, netdev); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 22098c2ecf20Sopenharmony_ci err = qlcnic_attach(adapter); 22108c2ecf20Sopenharmony_ci if (!err) { 22118c2ecf20Sopenharmony_ci __qlcnic_up(adapter, netdev); 22128c2ecf20Sopenharmony_ci qlcnic_restore_indev_addr(netdev, NETDEV_UP); 22138c2ecf20Sopenharmony_ci } 22148c2ecf20Sopenharmony_ci } 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci netif_device_attach(netdev); 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 22208c2ecf20Sopenharmony_ci return err; 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_cistatic void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 22268c2ecf20Sopenharmony_ci u16 act_pci_fn = ahw->total_nic_func; 22278c2ecf20Sopenharmony_ci u16 count; 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci ahw->max_mc_count = QLCNIC_MAX_MC_COUNT; 22308c2ecf20Sopenharmony_ci if (act_pci_fn <= 2) 22318c2ecf20Sopenharmony_ci count = (QLCNIC_MAX_UC_COUNT - QLCNIC_MAX_MC_COUNT) / 22328c2ecf20Sopenharmony_ci act_pci_fn; 22338c2ecf20Sopenharmony_ci else 22348c2ecf20Sopenharmony_ci count = (QLCNIC_LB_MAX_FILTERS - QLCNIC_MAX_MC_COUNT) / 22358c2ecf20Sopenharmony_ci act_pci_fn; 22368c2ecf20Sopenharmony_ci ahw->max_uc_count = count; 22378c2ecf20Sopenharmony_ci} 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_cistatic int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter, 22408c2ecf20Sopenharmony_ci u8 tx_queues, u8 rx_queues) 22418c2ecf20Sopenharmony_ci{ 22428c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 22438c2ecf20Sopenharmony_ci int err = 0; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (tx_queues) { 22468c2ecf20Sopenharmony_ci err = netif_set_real_num_tx_queues(netdev, tx_queues); 22478c2ecf20Sopenharmony_ci if (err) { 22488c2ecf20Sopenharmony_ci netdev_err(netdev, "failed to set %d Tx queues\n", 22498c2ecf20Sopenharmony_ci tx_queues); 22508c2ecf20Sopenharmony_ci return err; 22518c2ecf20Sopenharmony_ci } 22528c2ecf20Sopenharmony_ci } 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (rx_queues) { 22558c2ecf20Sopenharmony_ci err = netif_set_real_num_rx_queues(netdev, rx_queues); 22568c2ecf20Sopenharmony_ci if (err) 22578c2ecf20Sopenharmony_ci netdev_err(netdev, "failed to set %d Rx queues\n", 22588c2ecf20Sopenharmony_ci rx_queues); 22598c2ecf20Sopenharmony_ci } 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci return err; 22628c2ecf20Sopenharmony_ci} 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ciint 22658c2ecf20Sopenharmony_ciqlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev, 22668c2ecf20Sopenharmony_ci int pci_using_dac) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci int err; 22698c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci adapter->rx_csum = 1; 22728c2ecf20Sopenharmony_ci adapter->ahw->mc_enabled = 0; 22738c2ecf20Sopenharmony_ci qlcnic_set_mac_filter_count(adapter); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci netdev->netdev_ops = &qlcnic_netdev_ops; 22768c2ecf20Sopenharmony_ci netdev->watchdog_timeo = QLCNIC_WATCHDOG_TIMEOUTVALUE * HZ; 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci qlcnic_change_mtu(netdev, netdev->mtu); 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci netdev->ethtool_ops = (qlcnic_sriov_vf_check(adapter)) ? 22818c2ecf20Sopenharmony_ci &qlcnic_sriov_vf_ethtool_ops : &qlcnic_ethtool_ops; 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | 22848c2ecf20Sopenharmony_ci NETIF_F_IPV6_CSUM | NETIF_F_GRO | 22858c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX); 22868c2ecf20Sopenharmony_ci netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | 22878c2ecf20Sopenharmony_ci NETIF_F_IPV6_CSUM); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (QLCNIC_IS_TSO_CAPABLE(adapter)) { 22908c2ecf20Sopenharmony_ci netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6); 22918c2ecf20Sopenharmony_ci netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci if (pci_using_dac) { 22958c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_HIGHDMA; 22968c2ecf20Sopenharmony_ci netdev->vlan_features |= NETIF_F_HIGHDMA; 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (qlcnic_vlan_tx_check(adapter)) 23008c2ecf20Sopenharmony_ci netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX); 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci if (qlcnic_sriov_vf_check(adapter)) 23038c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) 23068c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_LRO; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci if (qlcnic_encap_tx_offload(adapter)) { 23098c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_GSO_UDP_TUNNEL; 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci /* encapsulation Tx offload supported by Adapter */ 23128c2ecf20Sopenharmony_ci netdev->hw_enc_features = NETIF_F_IP_CSUM | 23138c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | 23148c2ecf20Sopenharmony_ci NETIF_F_TSO | 23158c2ecf20Sopenharmony_ci NETIF_F_TSO6; 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci if (qlcnic_encap_rx_offload(adapter)) { 23198c2ecf20Sopenharmony_ci netdev->hw_enc_features |= NETIF_F_RXCSUM; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci netdev->udp_tunnel_nic_info = &qlcnic_udp_tunnels; 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci netdev->hw_features = netdev->features; 23258c2ecf20Sopenharmony_ci netdev->priv_flags |= IFF_UNICAST_FLT; 23268c2ecf20Sopenharmony_ci netdev->irq = adapter->msix_entries[0].vector; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci /* MTU range: 68 - 9600 */ 23298c2ecf20Sopenharmony_ci netdev->min_mtu = P3P_MIN_MTU; 23308c2ecf20Sopenharmony_ci netdev->max_mtu = P3P_MAX_MTU; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci err = qlcnic_set_real_num_queues(adapter, adapter->drv_tx_rings, 23338c2ecf20Sopenharmony_ci adapter->drv_sds_rings); 23348c2ecf20Sopenharmony_ci if (err) 23358c2ecf20Sopenharmony_ci return err; 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci qlcnic_dcb_init_dcbnl_ops(adapter->dcb); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci err = register_netdev(netdev); 23408c2ecf20Sopenharmony_ci if (err) { 23418c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register net device\n"); 23428c2ecf20Sopenharmony_ci return err; 23438c2ecf20Sopenharmony_ci } 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci return 0; 23468c2ecf20Sopenharmony_ci} 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_cistatic int qlcnic_set_dma_mask(struct pci_dev *pdev, int *pci_using_dac) 23498c2ecf20Sopenharmony_ci{ 23508c2ecf20Sopenharmony_ci if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && 23518c2ecf20Sopenharmony_ci !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) 23528c2ecf20Sopenharmony_ci *pci_using_dac = 1; 23538c2ecf20Sopenharmony_ci else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) && 23548c2ecf20Sopenharmony_ci !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) 23558c2ecf20Sopenharmony_ci *pci_using_dac = 0; 23568c2ecf20Sopenharmony_ci else { 23578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to set DMA mask, aborting\n"); 23588c2ecf20Sopenharmony_ci return -EIO; 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci return 0; 23628c2ecf20Sopenharmony_ci} 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_civoid qlcnic_free_tx_rings(struct qlcnic_adapter *adapter) 23658c2ecf20Sopenharmony_ci{ 23668c2ecf20Sopenharmony_ci int ring; 23678c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 23708c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 23718c2ecf20Sopenharmony_ci if (tx_ring) { 23728c2ecf20Sopenharmony_ci vfree(tx_ring->cmd_buf_arr); 23738c2ecf20Sopenharmony_ci tx_ring->cmd_buf_arr = NULL; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci } 23768c2ecf20Sopenharmony_ci kfree(adapter->tx_ring); 23778c2ecf20Sopenharmony_ci} 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ciint qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter, 23808c2ecf20Sopenharmony_ci struct net_device *netdev) 23818c2ecf20Sopenharmony_ci{ 23828c2ecf20Sopenharmony_ci int ring, vector, index; 23838c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 23848c2ecf20Sopenharmony_ci struct qlcnic_cmd_buffer *cmd_buf_arr; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci tx_ring = kcalloc(adapter->drv_tx_rings, 23878c2ecf20Sopenharmony_ci sizeof(struct qlcnic_host_tx_ring), GFP_KERNEL); 23888c2ecf20Sopenharmony_ci if (tx_ring == NULL) 23898c2ecf20Sopenharmony_ci return -ENOMEM; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci adapter->tx_ring = tx_ring; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 23948c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 23958c2ecf20Sopenharmony_ci tx_ring->num_desc = adapter->num_txd; 23968c2ecf20Sopenharmony_ci tx_ring->txq = netdev_get_tx_queue(netdev, ring); 23978c2ecf20Sopenharmony_ci cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring)); 23988c2ecf20Sopenharmony_ci if (cmd_buf_arr == NULL) { 23998c2ecf20Sopenharmony_ci qlcnic_free_tx_rings(adapter); 24008c2ecf20Sopenharmony_ci return -ENOMEM; 24018c2ecf20Sopenharmony_ci } 24028c2ecf20Sopenharmony_ci tx_ring->cmd_buf_arr = cmd_buf_arr; 24038c2ecf20Sopenharmony_ci spin_lock_init(&tx_ring->tx_clean_lock); 24048c2ecf20Sopenharmony_ci } 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter) || 24078c2ecf20Sopenharmony_ci (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter))) { 24088c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 24098c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 24108c2ecf20Sopenharmony_ci tx_ring->adapter = adapter; 24118c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_MSIX_ENABLED) { 24128c2ecf20Sopenharmony_ci index = adapter->drv_sds_rings + ring; 24138c2ecf20Sopenharmony_ci vector = adapter->msix_entries[index].vector; 24148c2ecf20Sopenharmony_ci tx_ring->irq = vector; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci } 24178c2ecf20Sopenharmony_ci } 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci return 0; 24208c2ecf20Sopenharmony_ci} 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_civoid qlcnic_set_drv_version(struct qlcnic_adapter *adapter) 24238c2ecf20Sopenharmony_ci{ 24248c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 24258c2ecf20Sopenharmony_ci u32 fw_cmd = 0; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 24288c2ecf20Sopenharmony_ci fw_cmd = QLCNIC_CMD_82XX_SET_DRV_VER; 24298c2ecf20Sopenharmony_ci else if (qlcnic_83xx_check(adapter)) 24308c2ecf20Sopenharmony_ci fw_cmd = QLCNIC_CMD_83XX_SET_DRV_VER; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_SET_DRV_VER) 24338c2ecf20Sopenharmony_ci qlcnic_fw_cmd_set_drv_version(adapter, fw_cmd); 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci/* Reset firmware API lock */ 24378c2ecf20Sopenharmony_cistatic void qlcnic_reset_api_lock(struct qlcnic_adapter *adapter) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci qlcnic_api_lock(adapter); 24408c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 24418c2ecf20Sopenharmony_ci} 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_cistatic int 24458c2ecf20Sopenharmony_ciqlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 24468c2ecf20Sopenharmony_ci{ 24478c2ecf20Sopenharmony_ci struct net_device *netdev = NULL; 24488c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = NULL; 24498c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw; 24508c2ecf20Sopenharmony_ci int err, pci_using_dac = -1; 24518c2ecf20Sopenharmony_ci char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */ 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 24548c2ecf20Sopenharmony_ci if (err) 24558c2ecf20Sopenharmony_ci return err; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 24588c2ecf20Sopenharmony_ci err = -ENODEV; 24598c2ecf20Sopenharmony_ci goto err_out_disable_pdev; 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci err = qlcnic_set_dma_mask(pdev, &pci_using_dac); 24638c2ecf20Sopenharmony_ci if (err) 24648c2ecf20Sopenharmony_ci goto err_out_disable_pdev; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, qlcnic_driver_name); 24678c2ecf20Sopenharmony_ci if (err) 24688c2ecf20Sopenharmony_ci goto err_out_disable_pdev; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci pci_set_master(pdev); 24718c2ecf20Sopenharmony_ci pci_enable_pcie_error_reporting(pdev); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL); 24748c2ecf20Sopenharmony_ci if (!ahw) { 24758c2ecf20Sopenharmony_ci err = -ENOMEM; 24768c2ecf20Sopenharmony_ci goto err_out_free_res; 24778c2ecf20Sopenharmony_ci } 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci switch (ent->device) { 24808c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE824X: 24818c2ecf20Sopenharmony_ci ahw->hw_ops = &qlcnic_hw_ops; 24828c2ecf20Sopenharmony_ci ahw->reg_tbl = (u32 *) qlcnic_reg_tbl; 24838c2ecf20Sopenharmony_ci break; 24848c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE834X: 24858c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE8830: 24868c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_QLE844X: 24878c2ecf20Sopenharmony_ci qlcnic_83xx_register_map(ahw); 24888c2ecf20Sopenharmony_ci break; 24898c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_VF_QLE834X: 24908c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_VF_QLE8C30: 24918c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_VF_QLE844X: 24928c2ecf20Sopenharmony_ci qlcnic_sriov_vf_register_map(ahw); 24938c2ecf20Sopenharmony_ci break; 24948c2ecf20Sopenharmony_ci default: 24958c2ecf20Sopenharmony_ci err = -EINVAL; 24968c2ecf20Sopenharmony_ci goto err_out_free_hw_res; 24978c2ecf20Sopenharmony_ci } 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci err = qlcnic_setup_pci_map(pdev, ahw); 25008c2ecf20Sopenharmony_ci if (err) 25018c2ecf20Sopenharmony_ci goto err_out_free_hw_res; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci netdev = alloc_etherdev_mq(sizeof(struct qlcnic_adapter), 25048c2ecf20Sopenharmony_ci QLCNIC_MAX_TX_RINGS); 25058c2ecf20Sopenharmony_ci if (!netdev) { 25068c2ecf20Sopenharmony_ci err = -ENOMEM; 25078c2ecf20Sopenharmony_ci goto err_out_iounmap; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci adapter = netdev_priv(netdev); 25138c2ecf20Sopenharmony_ci adapter->netdev = netdev; 25148c2ecf20Sopenharmony_ci adapter->pdev = pdev; 25158c2ecf20Sopenharmony_ci adapter->ahw = ahw; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic"); 25188c2ecf20Sopenharmony_ci if (adapter->qlcnic_wq == NULL) { 25198c2ecf20Sopenharmony_ci err = -ENOMEM; 25208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to create workqueue\n"); 25218c2ecf20Sopenharmony_ci goto err_out_free_netdev; 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci err = qlcnic_alloc_adapter_resources(adapter); 25258c2ecf20Sopenharmony_ci if (err) 25268c2ecf20Sopenharmony_ci goto err_out_free_wq; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci adapter->dev_rst_time = jiffies; 25298c2ecf20Sopenharmony_ci ahw->revision_id = pdev->revision; 25308c2ecf20Sopenharmony_ci ahw->max_vnic_func = qlcnic_get_vnic_func_count(adapter); 25318c2ecf20Sopenharmony_ci if (qlcnic_mac_learn == FDB_MAC_LEARN) 25328c2ecf20Sopenharmony_ci adapter->fdb_mac_learn = true; 25338c2ecf20Sopenharmony_ci else if (qlcnic_mac_learn == DRV_MAC_LEARN) 25348c2ecf20Sopenharmony_ci adapter->drv_mac_learn = true; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci rwlock_init(&adapter->ahw->crb_lock); 25378c2ecf20Sopenharmony_ci mutex_init(&adapter->ahw->mem_lock); 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->mac_list); 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci qlcnic_register_dcb(adapter); 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) { 25448c2ecf20Sopenharmony_ci qlcnic_check_vf(adapter, ent); 25458c2ecf20Sopenharmony_ci adapter->portnum = adapter->ahw->pci_func; 25468c2ecf20Sopenharmony_ci qlcnic_reset_api_lock(adapter); 25478c2ecf20Sopenharmony_ci err = qlcnic_start_firmware(adapter); 25488c2ecf20Sopenharmony_ci if (err) { 25498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n" 25508c2ecf20Sopenharmony_ci "\t\tIf reboot doesn't help, try flashing the card\n"); 25518c2ecf20Sopenharmony_ci goto err_out_maintenance_mode; 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci /* compute and set default and max tx/sds rings */ 25558c2ecf20Sopenharmony_ci if (adapter->ahw->msix_supported) { 25568c2ecf20Sopenharmony_ci if (qlcnic_check_multi_tx_capability(adapter) == 1) 25578c2ecf20Sopenharmony_ci qlcnic_set_tx_ring_count(adapter, 25588c2ecf20Sopenharmony_ci QLCNIC_SINGLE_RING); 25598c2ecf20Sopenharmony_ci else 25608c2ecf20Sopenharmony_ci qlcnic_set_tx_ring_count(adapter, 25618c2ecf20Sopenharmony_ci QLCNIC_DEF_TX_RINGS); 25628c2ecf20Sopenharmony_ci qlcnic_set_sds_ring_count(adapter, 25638c2ecf20Sopenharmony_ci QLCNIC_DEF_SDS_RINGS); 25648c2ecf20Sopenharmony_ci } else { 25658c2ecf20Sopenharmony_ci qlcnic_set_tx_ring_count(adapter, QLCNIC_SINGLE_RING); 25668c2ecf20Sopenharmony_ci qlcnic_set_sds_ring_count(adapter, QLCNIC_SINGLE_RING); 25678c2ecf20Sopenharmony_ci } 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci err = qlcnic_setup_idc_param(adapter); 25708c2ecf20Sopenharmony_ci if (err) 25718c2ecf20Sopenharmony_ci goto err_out_free_hw; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_NEED_FLR; 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci } else if (qlcnic_83xx_check(adapter)) { 25768c2ecf20Sopenharmony_ci qlcnic_83xx_check_vf(adapter, ent); 25778c2ecf20Sopenharmony_ci adapter->portnum = adapter->ahw->pci_func; 25788c2ecf20Sopenharmony_ci err = qlcnic_83xx_init(adapter, pci_using_dac); 25798c2ecf20Sopenharmony_ci if (err) { 25808c2ecf20Sopenharmony_ci switch (err) { 25818c2ecf20Sopenharmony_ci case -ENOTRECOVERABLE: 25828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n"); 25838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n"); 25848c2ecf20Sopenharmony_ci goto err_out_free_hw; 25858c2ecf20Sopenharmony_ci case -ENOMEM: 25868c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n"); 25878c2ecf20Sopenharmony_ci goto err_out_free_hw; 25888c2ecf20Sopenharmony_ci case -EOPNOTSUPP: 25898c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Adapter initialization failed\n"); 25908c2ecf20Sopenharmony_ci goto err_out_free_hw; 25918c2ecf20Sopenharmony_ci default: 25928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Adapter initialization failed. Driver will load in maintenance mode to recover the adapter using the application\n"); 25938c2ecf20Sopenharmony_ci goto err_out_maintenance_mode; 25948c2ecf20Sopenharmony_ci } 25958c2ecf20Sopenharmony_ci } 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci if (qlcnic_sriov_vf_check(adapter)) 25988c2ecf20Sopenharmony_ci return 0; 25998c2ecf20Sopenharmony_ci } else { 26008c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 26018c2ecf20Sopenharmony_ci "%s: failed. Please Reboot\n", __func__); 26028c2ecf20Sopenharmony_ci err = -ENODEV; 26038c2ecf20Sopenharmony_ci goto err_out_free_hw; 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci if (qlcnic_read_mac_addr(adapter)) 26078c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "failed to read mac addr\n"); 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci qlcnic_read_phys_port_id(adapter); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci if (adapter->portnum == 0) { 26128c2ecf20Sopenharmony_ci qlcnic_get_board_name(adapter, board_name); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci pr_info("%s: %s Board Chip rev 0x%x\n", 26158c2ecf20Sopenharmony_ci module_name(THIS_MODULE), 26168c2ecf20Sopenharmony_ci board_name, adapter->ahw->revision_id); 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x && 26208c2ecf20Sopenharmony_ci !!qlcnic_use_msi) 26218c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 26228c2ecf20Sopenharmony_ci "Device does not support MSI interrupts\n"); 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) { 26258c2ecf20Sopenharmony_ci err = qlcnic_dcb_enable(adapter->dcb); 26268c2ecf20Sopenharmony_ci if (err) { 26278c2ecf20Sopenharmony_ci qlcnic_dcb_free(adapter->dcb); 26288c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to enable DCB\n"); 26298c2ecf20Sopenharmony_ci goto err_out_free_hw; 26308c2ecf20Sopenharmony_ci } 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci qlcnic_dcb_get_info(adapter->dcb); 26338c2ecf20Sopenharmony_ci err = qlcnic_setup_intr(adapter); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci if (err) { 26368c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup interrupt\n"); 26378c2ecf20Sopenharmony_ci goto err_out_disable_msi; 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci err = qlcnic_get_act_pci_func(adapter); 26428c2ecf20Sopenharmony_ci if (err) 26438c2ecf20Sopenharmony_ci goto err_out_disable_mbx_intr; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (adapter->portnum == 0) 26468c2ecf20Sopenharmony_ci qlcnic_set_drv_version(adapter); 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac); 26498c2ecf20Sopenharmony_ci if (err) 26508c2ecf20Sopenharmony_ci goto err_out_disable_mbx_intr; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, adapter); 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 26558c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, 26568c2ecf20Sopenharmony_ci FW_POLL_DELAY); 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci switch (adapter->ahw->port_type) { 26598c2ecf20Sopenharmony_ci case QLCNIC_GBE: 26608c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", 26618c2ecf20Sopenharmony_ci adapter->netdev->name); 26628c2ecf20Sopenharmony_ci break; 26638c2ecf20Sopenharmony_ci case QLCNIC_XGBE: 26648c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", 26658c2ecf20Sopenharmony_ci adapter->netdev->name); 26668c2ecf20Sopenharmony_ci break; 26678c2ecf20Sopenharmony_ci } 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci if (adapter->drv_mac_learn) 26708c2ecf20Sopenharmony_ci qlcnic_alloc_lb_filters_mem(adapter); 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci qlcnic_add_sysfs(adapter); 26738c2ecf20Sopenharmony_ci qlcnic_register_hwmon_dev(adapter); 26748c2ecf20Sopenharmony_ci return 0; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_cierr_out_disable_mbx_intr: 26778c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 26788c2ecf20Sopenharmony_ci qlcnic_83xx_free_mbx_intr(adapter); 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_cierr_out_disable_msi: 26818c2ecf20Sopenharmony_ci qlcnic_teardown_intr(adapter); 26828c2ecf20Sopenharmony_ci qlcnic_cancel_idc_work(adapter); 26838c2ecf20Sopenharmony_ci qlcnic_clr_all_drv_state(adapter, 0); 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_cierr_out_free_hw: 26868c2ecf20Sopenharmony_ci qlcnic_free_adapter_resources(adapter); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_cierr_out_free_wq: 26898c2ecf20Sopenharmony_ci destroy_workqueue(adapter->qlcnic_wq); 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_cierr_out_free_netdev: 26928c2ecf20Sopenharmony_ci free_netdev(netdev); 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_cierr_out_iounmap: 26958c2ecf20Sopenharmony_ci qlcnic_cleanup_pci_map(ahw); 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_cierr_out_free_hw_res: 26988c2ecf20Sopenharmony_ci kfree(ahw); 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_cierr_out_free_res: 27018c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 27028c2ecf20Sopenharmony_ci pci_release_regions(pdev); 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_cierr_out_disable_pdev: 27058c2ecf20Sopenharmony_ci pci_disable_device(pdev); 27068c2ecf20Sopenharmony_ci return err; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_cierr_out_maintenance_mode: 27098c2ecf20Sopenharmony_ci set_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state); 27108c2ecf20Sopenharmony_ci netdev->netdev_ops = &qlcnic_netdev_failed_ops; 27118c2ecf20Sopenharmony_ci netdev->ethtool_ops = &qlcnic_ethtool_failed_ops; 27128c2ecf20Sopenharmony_ci ahw->port_type = QLCNIC_XGBE; 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 27158c2ecf20Sopenharmony_ci adapter->tgt_status_reg = NULL; 27168c2ecf20Sopenharmony_ci else 27178c2ecf20Sopenharmony_ci ahw->board_type = QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci err = register_netdev(netdev); 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci if (err) { 27228c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register net device\n"); 27238c2ecf20Sopenharmony_ci qlcnic_clr_all_drv_state(adapter, 0); 27248c2ecf20Sopenharmony_ci goto err_out_free_hw; 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, adapter); 27288c2ecf20Sopenharmony_ci qlcnic_add_sysfs(adapter); 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci return 0; 27318c2ecf20Sopenharmony_ci} 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_cistatic void qlcnic_remove(struct pci_dev *pdev) 27348c2ecf20Sopenharmony_ci{ 27358c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter; 27368c2ecf20Sopenharmony_ci struct net_device *netdev; 27378c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci adapter = pci_get_drvdata(pdev); 27408c2ecf20Sopenharmony_ci if (adapter == NULL) 27418c2ecf20Sopenharmony_ci return; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci netdev = adapter->netdev; 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci qlcnic_cancel_idc_work(adapter); 27468c2ecf20Sopenharmony_ci qlcnic_sriov_pf_disable(adapter); 27478c2ecf20Sopenharmony_ci ahw = adapter->ahw; 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci unregister_netdev(netdev); 27508c2ecf20Sopenharmony_ci qlcnic_sriov_cleanup(adapter); 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 27538c2ecf20Sopenharmony_ci qlcnic_83xx_initialize_nic(adapter, 0); 27548c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->idc_aen_work); 27558c2ecf20Sopenharmony_ci qlcnic_83xx_free_mbx_intr(adapter); 27568c2ecf20Sopenharmony_ci qlcnic_83xx_detach_mailbox_work(adapter); 27578c2ecf20Sopenharmony_ci qlcnic_83xx_free_mailbox(ahw->mailbox); 27588c2ecf20Sopenharmony_ci kfree(ahw->fw_info); 27598c2ecf20Sopenharmony_ci } 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci qlcnic_dcb_free(adapter->dcb); 27628c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 27638c2ecf20Sopenharmony_ci kfree(adapter->npars); 27648c2ecf20Sopenharmony_ci kfree(adapter->eswitch); 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 27678c2ecf20Sopenharmony_ci qlcnic_clr_all_drv_state(adapter, 0); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci qlcnic_free_lb_filters_mem(adapter); 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci qlcnic_teardown_intr(adapter); 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci qlcnic_remove_sysfs(adapter); 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci qlcnic_unregister_hwmon_dev(adapter); 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci qlcnic_cleanup_pci_map(adapter->ahw); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci qlcnic_release_firmware(adapter); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 27848c2ecf20Sopenharmony_ci pci_release_regions(pdev); 27858c2ecf20Sopenharmony_ci pci_disable_device(pdev); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci if (adapter->qlcnic_wq) { 27888c2ecf20Sopenharmony_ci destroy_workqueue(adapter->qlcnic_wq); 27898c2ecf20Sopenharmony_ci adapter->qlcnic_wq = NULL; 27908c2ecf20Sopenharmony_ci } 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci qlcnic_free_adapter_resources(adapter); 27938c2ecf20Sopenharmony_ci kfree(ahw); 27948c2ecf20Sopenharmony_ci free_netdev(netdev); 27958c2ecf20Sopenharmony_ci} 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_cistatic void qlcnic_shutdown(struct pci_dev *pdev) 27988c2ecf20Sopenharmony_ci{ 27998c2ecf20Sopenharmony_ci if (__qlcnic_shutdown(pdev)) 28008c2ecf20Sopenharmony_ci return; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci pci_disable_device(pdev); 28038c2ecf20Sopenharmony_ci} 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_cistatic int __maybe_unused qlcnic_suspend(struct device *dev_d) 28068c2ecf20Sopenharmony_ci{ 28078c2ecf20Sopenharmony_ci return __qlcnic_shutdown(to_pci_dev(dev_d)); 28088c2ecf20Sopenharmony_ci} 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_cistatic int __maybe_unused qlcnic_resume(struct device *dev_d) 28118c2ecf20Sopenharmony_ci{ 28128c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = dev_get_drvdata(dev_d); 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci return __qlcnic_resume(adapter); 28158c2ecf20Sopenharmony_ci} 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_cistatic int qlcnic_open(struct net_device *netdev) 28188c2ecf20Sopenharmony_ci{ 28198c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 28208c2ecf20Sopenharmony_ci int err; 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) { 28238c2ecf20Sopenharmony_ci netdev_err(netdev, "%s: Device is in non-operational state\n", 28248c2ecf20Sopenharmony_ci __func__); 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci return -EIO; 28278c2ecf20Sopenharmony_ci } 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci err = qlcnic_attach(adapter); 28328c2ecf20Sopenharmony_ci if (err) 28338c2ecf20Sopenharmony_ci return err; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci err = __qlcnic_up(adapter, netdev); 28368c2ecf20Sopenharmony_ci if (err) 28378c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci return err; 28408c2ecf20Sopenharmony_ci} 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci/* 28438c2ecf20Sopenharmony_ci * qlcnic_close - Disables a network interface entry point 28448c2ecf20Sopenharmony_ci */ 28458c2ecf20Sopenharmony_cistatic int qlcnic_close(struct net_device *netdev) 28468c2ecf20Sopenharmony_ci{ 28478c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci __qlcnic_down(adapter, netdev); 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci return 0; 28528c2ecf20Sopenharmony_ci} 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci#define QLCNIC_VF_LB_BUCKET_SIZE 1 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_civoid qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter) 28578c2ecf20Sopenharmony_ci{ 28588c2ecf20Sopenharmony_ci void *head; 28598c2ecf20Sopenharmony_ci int i; 28608c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 28618c2ecf20Sopenharmony_ci u32 filter_size = 0; 28628c2ecf20Sopenharmony_ci u16 act_pci_func = 0; 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci if (adapter->fhash.fmax && adapter->fhash.fhead) 28658c2ecf20Sopenharmony_ci return; 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci act_pci_func = adapter->ahw->total_nic_func; 28688c2ecf20Sopenharmony_ci spin_lock_init(&adapter->mac_learn_lock); 28698c2ecf20Sopenharmony_ci spin_lock_init(&adapter->rx_mac_learn_lock); 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci if (qlcnic_sriov_vf_check(adapter)) { 28728c2ecf20Sopenharmony_ci filter_size = QLCNIC_83XX_SRIOV_VF_MAX_MAC - 1; 28738c2ecf20Sopenharmony_ci adapter->fhash.fbucket_size = QLCNIC_VF_LB_BUCKET_SIZE; 28748c2ecf20Sopenharmony_ci } else if (qlcnic_82xx_check(adapter)) { 28758c2ecf20Sopenharmony_ci filter_size = QLCNIC_LB_MAX_FILTERS; 28768c2ecf20Sopenharmony_ci adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE; 28778c2ecf20Sopenharmony_ci } else { 28788c2ecf20Sopenharmony_ci filter_size = QLC_83XX_LB_MAX_FILTERS; 28798c2ecf20Sopenharmony_ci adapter->fhash.fbucket_size = QLC_83XX_LB_BUCKET_SIZE; 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci head = kcalloc(adapter->fhash.fbucket_size, 28838c2ecf20Sopenharmony_ci sizeof(struct hlist_head), GFP_ATOMIC); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci if (!head) 28868c2ecf20Sopenharmony_ci return; 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci adapter->fhash.fmax = (filter_size / act_pci_func); 28898c2ecf20Sopenharmony_ci adapter->fhash.fhead = head; 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci netdev_info(netdev, "active nic func = %d, mac filter size=%d\n", 28928c2ecf20Sopenharmony_ci act_pci_func, adapter->fhash.fmax); 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci for (i = 0; i < adapter->fhash.fbucket_size; i++) 28958c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&adapter->fhash.fhead[i]); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci adapter->rx_fhash.fbucket_size = adapter->fhash.fbucket_size; 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci head = kcalloc(adapter->rx_fhash.fbucket_size, 29008c2ecf20Sopenharmony_ci sizeof(struct hlist_head), GFP_ATOMIC); 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci if (!head) 29038c2ecf20Sopenharmony_ci return; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci adapter->rx_fhash.fmax = (filter_size / act_pci_func); 29068c2ecf20Sopenharmony_ci adapter->rx_fhash.fhead = head; 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) 29098c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&adapter->rx_fhash.fhead[i]); 29108c2ecf20Sopenharmony_ci} 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_cistatic void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter) 29138c2ecf20Sopenharmony_ci{ 29148c2ecf20Sopenharmony_ci if (adapter->fhash.fmax) 29158c2ecf20Sopenharmony_ci kfree(adapter->fhash.fhead); 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci adapter->fhash.fhead = NULL; 29188c2ecf20Sopenharmony_ci adapter->fhash.fmax = 0; 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci if (adapter->rx_fhash.fmax) 29218c2ecf20Sopenharmony_ci kfree(adapter->rx_fhash.fhead); 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci adapter->rx_fhash.fmax = 0; 29248c2ecf20Sopenharmony_ci adapter->rx_fhash.fhead = NULL; 29258c2ecf20Sopenharmony_ci} 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ciint qlcnic_check_temp(struct qlcnic_adapter *adapter) 29288c2ecf20Sopenharmony_ci{ 29298c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 29308c2ecf20Sopenharmony_ci u32 temp_state, temp_val, temp = 0; 29318c2ecf20Sopenharmony_ci int rv = 0; 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 29348c2ecf20Sopenharmony_ci temp = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP); 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 29378c2ecf20Sopenharmony_ci temp = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP); 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci temp_state = qlcnic_get_temp_state(temp); 29408c2ecf20Sopenharmony_ci temp_val = qlcnic_get_temp_val(temp); 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci if (temp_state == QLCNIC_TEMP_PANIC) { 29438c2ecf20Sopenharmony_ci dev_err(&netdev->dev, 29448c2ecf20Sopenharmony_ci "Device temperature %d degrees C exceeds" 29458c2ecf20Sopenharmony_ci " maximum allowed. Hardware has been shut down.\n", 29468c2ecf20Sopenharmony_ci temp_val); 29478c2ecf20Sopenharmony_ci rv = 1; 29488c2ecf20Sopenharmony_ci } else if (temp_state == QLCNIC_TEMP_WARN) { 29498c2ecf20Sopenharmony_ci if (adapter->ahw->temp == QLCNIC_TEMP_NORMAL) { 29508c2ecf20Sopenharmony_ci dev_err(&netdev->dev, 29518c2ecf20Sopenharmony_ci "Device temperature %d degrees C " 29528c2ecf20Sopenharmony_ci "exceeds operating range." 29538c2ecf20Sopenharmony_ci " Immediate action needed.\n", 29548c2ecf20Sopenharmony_ci temp_val); 29558c2ecf20Sopenharmony_ci } 29568c2ecf20Sopenharmony_ci } else { 29578c2ecf20Sopenharmony_ci if (adapter->ahw->temp == QLCNIC_TEMP_WARN) { 29588c2ecf20Sopenharmony_ci dev_info(&netdev->dev, 29598c2ecf20Sopenharmony_ci "Device temperature is now %d degrees C" 29608c2ecf20Sopenharmony_ci " in normal range.\n", temp_val); 29618c2ecf20Sopenharmony_ci } 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci adapter->ahw->temp = temp_state; 29648c2ecf20Sopenharmony_ci return rv; 29658c2ecf20Sopenharmony_ci} 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_cistatic inline void dump_tx_ring_desc(struct qlcnic_host_tx_ring *tx_ring) 29688c2ecf20Sopenharmony_ci{ 29698c2ecf20Sopenharmony_ci int i; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci for (i = 0; i < tx_ring->num_desc; i++) { 29728c2ecf20Sopenharmony_ci pr_info("TX Desc: %d\n", i); 29738c2ecf20Sopenharmony_ci print_hex_dump(KERN_INFO, "TX: ", DUMP_PREFIX_OFFSET, 16, 1, 29748c2ecf20Sopenharmony_ci &tx_ring->desc_head[i], 29758c2ecf20Sopenharmony_ci sizeof(struct cmd_desc_type0), true); 29768c2ecf20Sopenharmony_ci } 29778c2ecf20Sopenharmony_ci} 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_cistatic void qlcnic_dump_rings(struct qlcnic_adapter *adapter) 29808c2ecf20Sopenharmony_ci{ 29818c2ecf20Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 29828c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 29838c2ecf20Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 29848c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 29858c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 29868c2ecf20Sopenharmony_ci int ring; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci if (!netdev || !netif_running(netdev)) 29898c2ecf20Sopenharmony_ci return; 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->max_rds_rings; ring++) { 29928c2ecf20Sopenharmony_ci rds_ring = &recv_ctx->rds_rings[ring]; 29938c2ecf20Sopenharmony_ci if (!rds_ring) 29948c2ecf20Sopenharmony_ci continue; 29958c2ecf20Sopenharmony_ci netdev_info(netdev, 29968c2ecf20Sopenharmony_ci "rds_ring=%d crb_rcv_producer=%d producer=%u num_desc=%u\n", 29978c2ecf20Sopenharmony_ci ring, readl(rds_ring->crb_rcv_producer), 29988c2ecf20Sopenharmony_ci rds_ring->producer, rds_ring->num_desc); 29998c2ecf20Sopenharmony_ci } 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 30028c2ecf20Sopenharmony_ci sds_ring = &(recv_ctx->sds_rings[ring]); 30038c2ecf20Sopenharmony_ci if (!sds_ring) 30048c2ecf20Sopenharmony_ci continue; 30058c2ecf20Sopenharmony_ci netdev_info(netdev, 30068c2ecf20Sopenharmony_ci "sds_ring=%d crb_sts_consumer=%d consumer=%u crb_intr_mask=%d num_desc=%u\n", 30078c2ecf20Sopenharmony_ci ring, readl(sds_ring->crb_sts_consumer), 30088c2ecf20Sopenharmony_ci sds_ring->consumer, readl(sds_ring->crb_intr_mask), 30098c2ecf20Sopenharmony_ci sds_ring->num_desc); 30108c2ecf20Sopenharmony_ci } 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 30138c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 30148c2ecf20Sopenharmony_ci if (!tx_ring) 30158c2ecf20Sopenharmony_ci continue; 30168c2ecf20Sopenharmony_ci netdev_info(netdev, "Tx ring=%d Context Id=0x%x\n", 30178c2ecf20Sopenharmony_ci ring, tx_ring->ctx_id); 30188c2ecf20Sopenharmony_ci netdev_info(netdev, 30198c2ecf20Sopenharmony_ci "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n", 30208c2ecf20Sopenharmony_ci tx_ring->tx_stats.xmit_finished, 30218c2ecf20Sopenharmony_ci tx_ring->tx_stats.xmit_called, 30228c2ecf20Sopenharmony_ci tx_ring->tx_stats.xmit_on, 30238c2ecf20Sopenharmony_ci tx_ring->tx_stats.xmit_off); 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (tx_ring->crb_intr_mask) 30268c2ecf20Sopenharmony_ci netdev_info(netdev, "crb_intr_mask=%d\n", 30278c2ecf20Sopenharmony_ci readl(tx_ring->crb_intr_mask)); 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci netdev_info(netdev, 30308c2ecf20Sopenharmony_ci "hw_producer=%d, sw_producer=%d sw_consumer=%d, hw_consumer=%d\n", 30318c2ecf20Sopenharmony_ci readl(tx_ring->crb_cmd_producer), 30328c2ecf20Sopenharmony_ci tx_ring->producer, tx_ring->sw_consumer, 30338c2ecf20Sopenharmony_ci le32_to_cpu(*(tx_ring->hw_consumer))); 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci netdev_info(netdev, "Total desc=%d, Available desc=%d\n", 30368c2ecf20Sopenharmony_ci tx_ring->num_desc, qlcnic_tx_avail(tx_ring)); 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci if (netif_msg_tx_err(adapter->ahw)) 30398c2ecf20Sopenharmony_ci dump_tx_ring_desc(tx_ring); 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci} 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_cistatic void qlcnic_tx_timeout(struct net_device *netdev, unsigned int txqueue) 30458c2ecf20Sopenharmony_ci{ 30468c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_RESETTING, &adapter->state)) 30498c2ecf20Sopenharmony_ci return; 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci qlcnic_dump_rings(adapter); 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS || 30548c2ecf20Sopenharmony_ci netif_msg_tx_err(adapter->ahw)) { 30558c2ecf20Sopenharmony_ci netdev_err(netdev, "Tx timeout, reset the adapter.\n"); 30568c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 30578c2ecf20Sopenharmony_ci adapter->need_fw_reset = 1; 30588c2ecf20Sopenharmony_ci else if (qlcnic_83xx_check(adapter)) 30598c2ecf20Sopenharmony_ci qlcnic_83xx_idc_request_reset(adapter, 30608c2ecf20Sopenharmony_ci QLCNIC_FORCE_FW_DUMP_KEY); 30618c2ecf20Sopenharmony_ci } else { 30628c2ecf20Sopenharmony_ci netdev_err(netdev, "Tx timeout, reset adapter context.\n"); 30638c2ecf20Sopenharmony_ci adapter->ahw->reset_context = 1; 30648c2ecf20Sopenharmony_ci } 30658c2ecf20Sopenharmony_ci} 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_cistatic struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) 30688c2ecf20Sopenharmony_ci{ 30698c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 30708c2ecf20Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) 30738c2ecf20Sopenharmony_ci qlcnic_update_stats(adapter); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; 30768c2ecf20Sopenharmony_ci stats->tx_packets = adapter->stats.xmitfinished; 30778c2ecf20Sopenharmony_ci stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes; 30788c2ecf20Sopenharmony_ci stats->tx_bytes = adapter->stats.txbytes; 30798c2ecf20Sopenharmony_ci stats->rx_dropped = adapter->stats.rxdropped; 30808c2ecf20Sopenharmony_ci stats->tx_dropped = adapter->stats.txdropped; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci return stats; 30838c2ecf20Sopenharmony_ci} 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter) 30868c2ecf20Sopenharmony_ci{ 30878c2ecf20Sopenharmony_ci u32 status; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci status = readl(adapter->isr_int_vec); 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci if (!(status & adapter->ahw->int_vec_bit)) 30928c2ecf20Sopenharmony_ci return IRQ_NONE; 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci /* check interrupt state machine, to be sure */ 30958c2ecf20Sopenharmony_ci status = readl(adapter->crb_int_state_reg); 30968c2ecf20Sopenharmony_ci if (!ISR_LEGACY_INT_TRIGGERED(status)) 30978c2ecf20Sopenharmony_ci return IRQ_NONE; 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci writel(0xffffffff, adapter->tgt_status_reg); 31008c2ecf20Sopenharmony_ci /* read twice to ensure write is flushed */ 31018c2ecf20Sopenharmony_ci readl(adapter->isr_int_vec); 31028c2ecf20Sopenharmony_ci readl(adapter->isr_int_vec); 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci return IRQ_HANDLED; 31058c2ecf20Sopenharmony_ci} 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_tmp_intr(int irq, void *data) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring = data; 31108c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = sds_ring->adapter; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_MSIX_ENABLED) 31138c2ecf20Sopenharmony_ci goto done; 31148c2ecf20Sopenharmony_ci else if (adapter->flags & QLCNIC_MSI_ENABLED) { 31158c2ecf20Sopenharmony_ci writel(0xffffffff, adapter->tgt_status_reg); 31168c2ecf20Sopenharmony_ci goto done; 31178c2ecf20Sopenharmony_ci } 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) 31208c2ecf20Sopenharmony_ci return IRQ_NONE; 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_cidone: 31238c2ecf20Sopenharmony_ci adapter->ahw->diag_cnt++; 31248c2ecf20Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 31258c2ecf20Sopenharmony_ci return IRQ_HANDLED; 31268c2ecf20Sopenharmony_ci} 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_intr(int irq, void *data) 31298c2ecf20Sopenharmony_ci{ 31308c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring = data; 31318c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = sds_ring->adapter; 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE) 31348c2ecf20Sopenharmony_ci return IRQ_NONE; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci napi_schedule(&sds_ring->napi); 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci return IRQ_HANDLED; 31398c2ecf20Sopenharmony_ci} 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_msi_intr(int irq, void *data) 31428c2ecf20Sopenharmony_ci{ 31438c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring = data; 31448c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = sds_ring->adapter; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci /* clear interrupt */ 31478c2ecf20Sopenharmony_ci writel(0xffffffff, adapter->tgt_status_reg); 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci napi_schedule(&sds_ring->napi); 31508c2ecf20Sopenharmony_ci return IRQ_HANDLED; 31518c2ecf20Sopenharmony_ci} 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_msix_intr(int irq, void *data) 31548c2ecf20Sopenharmony_ci{ 31558c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring = data; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci napi_schedule(&sds_ring->napi); 31588c2ecf20Sopenharmony_ci return IRQ_HANDLED; 31598c2ecf20Sopenharmony_ci} 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_cistatic irqreturn_t qlcnic_msix_tx_intr(int irq, void *data) 31628c2ecf20Sopenharmony_ci{ 31638c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring = data; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci napi_schedule(&tx_ring->napi); 31668c2ecf20Sopenharmony_ci return IRQ_HANDLED; 31678c2ecf20Sopenharmony_ci} 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_cistatic void 31708c2ecf20Sopenharmony_ciqlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding) 31718c2ecf20Sopenharmony_ci{ 31728c2ecf20Sopenharmony_ci u32 val; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci val = adapter->portnum & 0xf; 31758c2ecf20Sopenharmony_ci val |= encoding << 7; 31768c2ecf20Sopenharmony_ci val |= (jiffies - adapter->dev_rst_time) << 8; 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val); 31798c2ecf20Sopenharmony_ci adapter->dev_rst_time = jiffies; 31808c2ecf20Sopenharmony_ci} 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_cistatic int 31838c2ecf20Sopenharmony_ciqlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state) 31848c2ecf20Sopenharmony_ci{ 31858c2ecf20Sopenharmony_ci u32 val; 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci WARN_ON(state != QLCNIC_DEV_NEED_RESET && 31888c2ecf20Sopenharmony_ci state != QLCNIC_DEV_NEED_QUISCENT); 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 31918c2ecf20Sopenharmony_ci return -EIO; 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE); 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci if (state == QLCNIC_DEV_NEED_RESET) 31968c2ecf20Sopenharmony_ci QLC_DEV_SET_RST_RDY(val, adapter->portnum); 31978c2ecf20Sopenharmony_ci else if (state == QLCNIC_DEV_NEED_QUISCENT) 31988c2ecf20Sopenharmony_ci QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum); 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val); 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci return 0; 32058c2ecf20Sopenharmony_ci} 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_cistatic int 32088c2ecf20Sopenharmony_ciqlcnic_clr_drv_state(struct qlcnic_adapter *adapter) 32098c2ecf20Sopenharmony_ci{ 32108c2ecf20Sopenharmony_ci u32 val; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 32138c2ecf20Sopenharmony_ci return -EBUSY; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE); 32168c2ecf20Sopenharmony_ci QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum); 32178c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val); 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci return 0; 32228c2ecf20Sopenharmony_ci} 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_civoid qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed) 32258c2ecf20Sopenharmony_ci{ 32268c2ecf20Sopenharmony_ci u32 val; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 32298c2ecf20Sopenharmony_ci goto err; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE); 32328c2ecf20Sopenharmony_ci QLC_DEV_CLR_REF_CNT(val, adapter->portnum); 32338c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val); 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci if (failed) { 32368c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, 32378c2ecf20Sopenharmony_ci QLCNIC_DEV_FAILED); 32388c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, 32398c2ecf20Sopenharmony_ci "Device state set to Failed. Please Reboot\n"); 32408c2ecf20Sopenharmony_ci } else if (!(val & 0x11111111)) 32418c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, 32428c2ecf20Sopenharmony_ci QLCNIC_DEV_COLD); 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE); 32458c2ecf20Sopenharmony_ci QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum); 32468c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val); 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 32498c2ecf20Sopenharmony_cierr: 32508c2ecf20Sopenharmony_ci adapter->fw_fail_cnt = 0; 32518c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_FW_HANG; 32528c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_START_FW, &adapter->state); 32538c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 32548c2ecf20Sopenharmony_ci} 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci/* Grab api lock, before checking state */ 32578c2ecf20Sopenharmony_cistatic int 32588c2ecf20Sopenharmony_ciqlcnic_check_drv_state(struct qlcnic_adapter *adapter) 32598c2ecf20Sopenharmony_ci{ 32608c2ecf20Sopenharmony_ci int act, state, active_mask; 32618c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE); 32648c2ecf20Sopenharmony_ci act = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE); 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_FW_RESET_OWNER) { 32678c2ecf20Sopenharmony_ci active_mask = (~(1 << (ahw->pci_func * 4))); 32688c2ecf20Sopenharmony_ci act = act & active_mask; 32698c2ecf20Sopenharmony_ci } 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci if (((state & 0x11111111) == (act & 0x11111111)) || 32728c2ecf20Sopenharmony_ci ((act & 0x11111111) == ((state >> 1) & 0x11111111))) 32738c2ecf20Sopenharmony_ci return 0; 32748c2ecf20Sopenharmony_ci else 32758c2ecf20Sopenharmony_ci return 1; 32768c2ecf20Sopenharmony_ci} 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_cistatic int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter) 32798c2ecf20Sopenharmony_ci{ 32808c2ecf20Sopenharmony_ci u32 val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_IDC_VER); 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci if (val != QLCNIC_DRV_IDC_VER) { 32838c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's" 32848c2ecf20Sopenharmony_ci " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val); 32858c2ecf20Sopenharmony_ci } 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci return 0; 32888c2ecf20Sopenharmony_ci} 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_cistatic int 32918c2ecf20Sopenharmony_ciqlcnic_can_start_firmware(struct qlcnic_adapter *adapter) 32928c2ecf20Sopenharmony_ci{ 32938c2ecf20Sopenharmony_ci u32 val, prev_state; 32948c2ecf20Sopenharmony_ci u8 dev_init_timeo = adapter->dev_init_timeo; 32958c2ecf20Sopenharmony_ci u8 portnum = adapter->portnum; 32968c2ecf20Sopenharmony_ci u8 ret; 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) 32998c2ecf20Sopenharmony_ci return 1; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 33028c2ecf20Sopenharmony_ci return -1; 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE); 33058c2ecf20Sopenharmony_ci if (!(val & (1 << (portnum * 4)))) { 33068c2ecf20Sopenharmony_ci QLC_DEV_SET_REF_CNT(val, portnum); 33078c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val); 33088c2ecf20Sopenharmony_ci } 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 33118c2ecf20Sopenharmony_ci QLCDB(adapter, HW, "Device state = %u\n", prev_state); 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci switch (prev_state) { 33148c2ecf20Sopenharmony_ci case QLCNIC_DEV_COLD: 33158c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, 33168c2ecf20Sopenharmony_ci QLCNIC_DEV_INITIALIZING); 33178c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_IDC_VER, 33188c2ecf20Sopenharmony_ci QLCNIC_DRV_IDC_VER); 33198c2ecf20Sopenharmony_ci qlcnic_idc_debug_info(adapter, 0); 33208c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 33218c2ecf20Sopenharmony_ci return 1; 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci case QLCNIC_DEV_READY: 33248c2ecf20Sopenharmony_ci ret = qlcnic_check_idc_ver(adapter); 33258c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 33268c2ecf20Sopenharmony_ci return ret; 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci case QLCNIC_DEV_NEED_RESET: 33298c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE); 33308c2ecf20Sopenharmony_ci QLC_DEV_SET_RST_RDY(val, portnum); 33318c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val); 33328c2ecf20Sopenharmony_ci break; 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci case QLCNIC_DEV_NEED_QUISCENT: 33358c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE); 33368c2ecf20Sopenharmony_ci QLC_DEV_SET_QSCNT_RDY(val, portnum); 33378c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val); 33388c2ecf20Sopenharmony_ci break; 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci case QLCNIC_DEV_FAILED: 33418c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "Device in failed state.\n"); 33428c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 33438c2ecf20Sopenharmony_ci return -1; 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci case QLCNIC_DEV_INITIALIZING: 33468c2ecf20Sopenharmony_ci case QLCNIC_DEV_QUISCENT: 33478c2ecf20Sopenharmony_ci break; 33488c2ecf20Sopenharmony_ci } 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci do { 33538c2ecf20Sopenharmony_ci msleep(1000); 33548c2ecf20Sopenharmony_ci prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci if (prev_state == QLCNIC_DEV_QUISCENT) 33578c2ecf20Sopenharmony_ci continue; 33588c2ecf20Sopenharmony_ci } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci if (!dev_init_timeo) { 33618c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 33628c2ecf20Sopenharmony_ci "Waiting for device to initialize timeout\n"); 33638c2ecf20Sopenharmony_ci return -1; 33648c2ecf20Sopenharmony_ci } 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 33678c2ecf20Sopenharmony_ci return -1; 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE); 33708c2ecf20Sopenharmony_ci QLC_DEV_CLR_RST_QSCNT(val, portnum); 33718c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val); 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci ret = qlcnic_check_idc_ver(adapter); 33748c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci return ret; 33778c2ecf20Sopenharmony_ci} 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_cistatic void 33808c2ecf20Sopenharmony_ciqlcnic_fwinit_work(struct work_struct *work) 33818c2ecf20Sopenharmony_ci{ 33828c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = container_of(work, 33838c2ecf20Sopenharmony_ci struct qlcnic_adapter, fw_work.work); 33848c2ecf20Sopenharmony_ci u32 dev_state = 0xf; 33858c2ecf20Sopenharmony_ci u32 val; 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 33888c2ecf20Sopenharmony_ci goto err_ret; 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 33918c2ecf20Sopenharmony_ci if (dev_state == QLCNIC_DEV_QUISCENT || 33928c2ecf20Sopenharmony_ci dev_state == QLCNIC_DEV_NEED_QUISCENT) { 33938c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 33948c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_fwinit_work, 33958c2ecf20Sopenharmony_ci FW_POLL_DELAY * 2); 33968c2ecf20Sopenharmony_ci return; 33978c2ecf20Sopenharmony_ci } 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { 34008c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 34018c2ecf20Sopenharmony_ci goto wait_npar; 34028c2ecf20Sopenharmony_ci } 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci if (dev_state == QLCNIC_DEV_INITIALIZING || 34058c2ecf20Sopenharmony_ci dev_state == QLCNIC_DEV_READY) { 34068c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "Detected state change from " 34078c2ecf20Sopenharmony_ci "DEV_NEED_RESET, skipping ack check\n"); 34088c2ecf20Sopenharmony_ci goto skip_ack_check; 34098c2ecf20Sopenharmony_ci } 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) { 34128c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n", 34138c2ecf20Sopenharmony_ci adapter->reset_ack_timeo); 34148c2ecf20Sopenharmony_ci goto skip_ack_check; 34158c2ecf20Sopenharmony_ci } 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci if (!qlcnic_check_drv_state(adapter)) { 34188c2ecf20Sopenharmony_ciskip_ack_check: 34198c2ecf20Sopenharmony_ci dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci if (dev_state == QLCNIC_DEV_NEED_RESET) { 34228c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, 34238c2ecf20Sopenharmony_ci QLCNIC_DEV_INITIALIZING); 34248c2ecf20Sopenharmony_ci set_bit(__QLCNIC_START_FW, &adapter->state); 34258c2ecf20Sopenharmony_ci QLCDB(adapter, DRV, "Restarting fw\n"); 34268c2ecf20Sopenharmony_ci qlcnic_idc_debug_info(adapter, 0); 34278c2ecf20Sopenharmony_ci val = QLC_SHARED_REG_RD32(adapter, 34288c2ecf20Sopenharmony_ci QLCNIC_CRB_DRV_STATE); 34298c2ecf20Sopenharmony_ci QLC_DEV_SET_RST_RDY(val, adapter->portnum); 34308c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, 34318c2ecf20Sopenharmony_ci QLCNIC_CRB_DRV_STATE, val); 34328c2ecf20Sopenharmony_ci } 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 34358c2ecf20Sopenharmony_ci 34368c2ecf20Sopenharmony_ci rtnl_lock(); 34378c2ecf20Sopenharmony_ci if (qlcnic_check_fw_dump_state(adapter) && 34388c2ecf20Sopenharmony_ci (adapter->flags & QLCNIC_FW_RESET_OWNER)) { 34398c2ecf20Sopenharmony_ci QLCDB(adapter, DRV, "Take FW dump\n"); 34408c2ecf20Sopenharmony_ci qlcnic_dump_fw(adapter); 34418c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_FW_HANG; 34428c2ecf20Sopenharmony_ci } 34438c2ecf20Sopenharmony_ci rtnl_unlock(); 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_FW_RESET_OWNER; 34468c2ecf20Sopenharmony_ci if (!adapter->nic_ops->start_firmware(adapter)) { 34478c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); 34488c2ecf20Sopenharmony_ci adapter->fw_wait_cnt = 0; 34498c2ecf20Sopenharmony_ci return; 34508c2ecf20Sopenharmony_ci } 34518c2ecf20Sopenharmony_ci goto err_ret; 34528c2ecf20Sopenharmony_ci } 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ciwait_npar: 34578c2ecf20Sopenharmony_ci dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 34588c2ecf20Sopenharmony_ci QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state); 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci switch (dev_state) { 34618c2ecf20Sopenharmony_ci case QLCNIC_DEV_READY: 34628c2ecf20Sopenharmony_ci if (!qlcnic_start_firmware(adapter)) { 34638c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); 34648c2ecf20Sopenharmony_ci adapter->fw_wait_cnt = 0; 34658c2ecf20Sopenharmony_ci return; 34668c2ecf20Sopenharmony_ci } 34678c2ecf20Sopenharmony_ci case QLCNIC_DEV_FAILED: 34688c2ecf20Sopenharmony_ci break; 34698c2ecf20Sopenharmony_ci default: 34708c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, 34718c2ecf20Sopenharmony_ci qlcnic_fwinit_work, FW_POLL_DELAY); 34728c2ecf20Sopenharmony_ci return; 34738c2ecf20Sopenharmony_ci } 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_cierr_ret: 34768c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u " 34778c2ecf20Sopenharmony_ci "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt); 34788c2ecf20Sopenharmony_ci netif_device_attach(adapter->netdev); 34798c2ecf20Sopenharmony_ci qlcnic_clr_all_drv_state(adapter, 0); 34808c2ecf20Sopenharmony_ci} 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_cistatic void 34838c2ecf20Sopenharmony_ciqlcnic_detach_work(struct work_struct *work) 34848c2ecf20Sopenharmony_ci{ 34858c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = container_of(work, 34868c2ecf20Sopenharmony_ci struct qlcnic_adapter, fw_work.work); 34878c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 34888c2ecf20Sopenharmony_ci u32 status; 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_ci netif_device_detach(netdev); 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ci /* Dont grab rtnl lock during Quiscent mode */ 34938c2ecf20Sopenharmony_ci if (adapter->dev_state == QLCNIC_DEV_NEED_QUISCENT) { 34948c2ecf20Sopenharmony_ci if (netif_running(netdev)) 34958c2ecf20Sopenharmony_ci __qlcnic_down(adapter, netdev); 34968c2ecf20Sopenharmony_ci } else 34978c2ecf20Sopenharmony_ci qlcnic_down(adapter, netdev); 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1); 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci if (status & QLCNIC_RCODE_FATAL_ERROR) { 35028c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 35038c2ecf20Sopenharmony_ci "Detaching the device: peg halt status1=0x%x\n", 35048c2ecf20Sopenharmony_ci status); 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) { 35078c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 35088c2ecf20Sopenharmony_ci "On board active cooling fan failed. " 35098c2ecf20Sopenharmony_ci "Device has been halted.\n"); 35108c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 35118c2ecf20Sopenharmony_ci "Replace the adapter.\n"); 35128c2ecf20Sopenharmony_ci } 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_ci goto err_ret; 35158c2ecf20Sopenharmony_ci } 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci if (adapter->ahw->temp == QLCNIC_TEMP_PANIC) { 35188c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "Detaching the device: temp=%d\n", 35198c2ecf20Sopenharmony_ci adapter->ahw->temp); 35208c2ecf20Sopenharmony_ci goto err_ret; 35218c2ecf20Sopenharmony_ci } 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci /* Dont ack if this instance is the reset owner */ 35248c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_FW_RESET_OWNER)) { 35258c2ecf20Sopenharmony_ci if (qlcnic_set_drv_state(adapter, adapter->dev_state)) { 35268c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 35278c2ecf20Sopenharmony_ci "Failed to set driver state," 35288c2ecf20Sopenharmony_ci "detaching the device.\n"); 35298c2ecf20Sopenharmony_ci goto err_ret; 35308c2ecf20Sopenharmony_ci } 35318c2ecf20Sopenharmony_ci } 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_ci adapter->fw_wait_cnt = 0; 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY); 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci return; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_cierr_ret: 35408c2ecf20Sopenharmony_ci netif_device_attach(netdev); 35418c2ecf20Sopenharmony_ci qlcnic_clr_all_drv_state(adapter, 1); 35428c2ecf20Sopenharmony_ci} 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci/*Transit NPAR state to NON Operational */ 35458c2ecf20Sopenharmony_cistatic void 35468c2ecf20Sopenharmony_ciqlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter) 35478c2ecf20Sopenharmony_ci{ 35488c2ecf20Sopenharmony_ci u32 state; 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE); 35518c2ecf20Sopenharmony_ci if (state == QLCNIC_DEV_NPAR_NON_OPER) 35528c2ecf20Sopenharmony_ci return; 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 35558c2ecf20Sopenharmony_ci return; 35568c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, 35578c2ecf20Sopenharmony_ci QLCNIC_DEV_NPAR_NON_OPER); 35588c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 35598c2ecf20Sopenharmony_ci} 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_cistatic void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, 35628c2ecf20Sopenharmony_ci u32 key) 35638c2ecf20Sopenharmony_ci{ 35648c2ecf20Sopenharmony_ci u32 state, xg_val = 0, gb_val = 0; 35658c2ecf20Sopenharmony_ci 35668c2ecf20Sopenharmony_ci qlcnic_xg_set_xg0_mask(xg_val); 35678c2ecf20Sopenharmony_ci qlcnic_xg_set_xg1_mask(xg_val); 35688c2ecf20Sopenharmony_ci QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, xg_val); 35698c2ecf20Sopenharmony_ci qlcnic_gb_set_gb0_mask(gb_val); 35708c2ecf20Sopenharmony_ci qlcnic_gb_set_gb1_mask(gb_val); 35718c2ecf20Sopenharmony_ci qlcnic_gb_set_gb2_mask(gb_val); 35728c2ecf20Sopenharmony_ci qlcnic_gb_set_gb3_mask(gb_val); 35738c2ecf20Sopenharmony_ci QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, gb_val); 35748c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "Pause control frames disabled" 35758c2ecf20Sopenharmony_ci " on all ports\n"); 35768c2ecf20Sopenharmony_ci adapter->need_fw_reset = 1; 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 35798c2ecf20Sopenharmony_ci return; 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) { 35848c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, "%s: Device is in non-operational state\n", 35858c2ecf20Sopenharmony_ci __func__); 35868c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci return; 35898c2ecf20Sopenharmony_ci } 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci if (state == QLCNIC_DEV_READY) { 35928c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, 35938c2ecf20Sopenharmony_ci QLCNIC_DEV_NEED_RESET); 35948c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_FW_RESET_OWNER; 35958c2ecf20Sopenharmony_ci QLCDB(adapter, DRV, "NEED_RESET state set\n"); 35968c2ecf20Sopenharmony_ci qlcnic_idc_debug_info(adapter, 0); 35978c2ecf20Sopenharmony_ci } 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, 36008c2ecf20Sopenharmony_ci QLCNIC_DEV_NPAR_NON_OPER); 36018c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 36028c2ecf20Sopenharmony_ci} 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_ci/* Transit to NPAR READY state from NPAR NOT READY state */ 36058c2ecf20Sopenharmony_cistatic void 36068c2ecf20Sopenharmony_ciqlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter) 36078c2ecf20Sopenharmony_ci{ 36088c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 36098c2ecf20Sopenharmony_ci return; 36108c2ecf20Sopenharmony_ci 36118c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, 36128c2ecf20Sopenharmony_ci QLCNIC_DEV_NPAR_OPER); 36138c2ecf20Sopenharmony_ci QLCDB(adapter, DRV, "NPAR operational state set\n"); 36148c2ecf20Sopenharmony_ci 36158c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 36168c2ecf20Sopenharmony_ci} 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_civoid qlcnic_schedule_work(struct qlcnic_adapter *adapter, 36198c2ecf20Sopenharmony_ci work_func_t func, int delay) 36208c2ecf20Sopenharmony_ci{ 36218c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_AER, &adapter->state)) 36228c2ecf20Sopenharmony_ci return; 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&adapter->fw_work, func); 36258c2ecf20Sopenharmony_ci queue_delayed_work(adapter->qlcnic_wq, &adapter->fw_work, 36268c2ecf20Sopenharmony_ci round_jiffies_relative(delay)); 36278c2ecf20Sopenharmony_ci} 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_cistatic void 36308c2ecf20Sopenharmony_ciqlcnic_attach_work(struct work_struct *work) 36318c2ecf20Sopenharmony_ci{ 36328c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = container_of(work, 36338c2ecf20Sopenharmony_ci struct qlcnic_adapter, fw_work.work); 36348c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 36358c2ecf20Sopenharmony_ci u32 npar_state; 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_ci if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) { 36388c2ecf20Sopenharmony_ci npar_state = QLC_SHARED_REG_RD32(adapter, 36398c2ecf20Sopenharmony_ci QLCNIC_CRB_DEV_NPAR_STATE); 36408c2ecf20Sopenharmony_ci if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO) 36418c2ecf20Sopenharmony_ci qlcnic_clr_all_drv_state(adapter, 0); 36428c2ecf20Sopenharmony_ci else if (npar_state != QLCNIC_DEV_NPAR_OPER) 36438c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_attach_work, 36448c2ecf20Sopenharmony_ci FW_POLL_DELAY); 36458c2ecf20Sopenharmony_ci else 36468c2ecf20Sopenharmony_ci goto attach; 36478c2ecf20Sopenharmony_ci QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n"); 36488c2ecf20Sopenharmony_ci return; 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ciattach: 36518c2ecf20Sopenharmony_ci qlcnic_dcb_get_info(adapter->dcb); 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 36548c2ecf20Sopenharmony_ci if (qlcnic_up(adapter, netdev)) 36558c2ecf20Sopenharmony_ci goto done; 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci qlcnic_restore_indev_addr(netdev, NETDEV_UP); 36588c2ecf20Sopenharmony_ci } 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_cidone: 36618c2ecf20Sopenharmony_ci netif_device_attach(netdev); 36628c2ecf20Sopenharmony_ci adapter->fw_fail_cnt = 0; 36638c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_FW_HANG; 36648c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 36658c2ecf20Sopenharmony_ci if (adapter->portnum == 0) 36668c2ecf20Sopenharmony_ci qlcnic_set_drv_version(adapter); 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci if (!qlcnic_clr_drv_state(adapter)) 36698c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, 36708c2ecf20Sopenharmony_ci FW_POLL_DELAY); 36718c2ecf20Sopenharmony_ci} 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_cistatic int 36748c2ecf20Sopenharmony_ciqlcnic_check_health(struct qlcnic_adapter *adapter) 36758c2ecf20Sopenharmony_ci{ 36768c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 36778c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump; 36788c2ecf20Sopenharmony_ci u32 state = 0, heartbeat; 36798c2ecf20Sopenharmony_ci u32 peg_status; 36808c2ecf20Sopenharmony_ci int err = 0; 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci if (qlcnic_check_temp(adapter)) 36838c2ecf20Sopenharmony_ci goto detach; 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci if (adapter->need_fw_reset) 36868c2ecf20Sopenharmony_ci qlcnic_dev_request_reset(adapter, 0); 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_ci state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 36898c2ecf20Sopenharmony_ci if (state == QLCNIC_DEV_NEED_RESET) { 36908c2ecf20Sopenharmony_ci qlcnic_set_npar_non_operational(adapter); 36918c2ecf20Sopenharmony_ci adapter->need_fw_reset = 1; 36928c2ecf20Sopenharmony_ci } else if (state == QLCNIC_DEV_NEED_QUISCENT) 36938c2ecf20Sopenharmony_ci goto detach; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci heartbeat = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); 36968c2ecf20Sopenharmony_ci if (heartbeat != adapter->heartbeat) { 36978c2ecf20Sopenharmony_ci adapter->heartbeat = heartbeat; 36988c2ecf20Sopenharmony_ci adapter->fw_fail_cnt = 0; 36998c2ecf20Sopenharmony_ci if (adapter->need_fw_reset) 37008c2ecf20Sopenharmony_ci goto detach; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci if (ahw->reset_context && qlcnic_auto_fw_reset) 37038c2ecf20Sopenharmony_ci qlcnic_reset_hw_context(adapter); 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci return 0; 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) 37098c2ecf20Sopenharmony_ci return 0; 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_FW_HANG; 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci qlcnic_dev_request_reset(adapter, 0); 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci if (qlcnic_auto_fw_reset) 37168c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state); 37178c2ecf20Sopenharmony_ci 37188c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "firmware hang detected\n"); 37198c2ecf20Sopenharmony_ci peg_status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1); 37208c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n" 37218c2ecf20Sopenharmony_ci "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n" 37228c2ecf20Sopenharmony_ci "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n" 37238c2ecf20Sopenharmony_ci "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n" 37248c2ecf20Sopenharmony_ci "PEG_NET_4_PC: 0x%x\n", 37258c2ecf20Sopenharmony_ci peg_status, 37268c2ecf20Sopenharmony_ci QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2), 37278c2ecf20Sopenharmony_ci QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err), 37288c2ecf20Sopenharmony_ci QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err), 37298c2ecf20Sopenharmony_ci QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err), 37308c2ecf20Sopenharmony_ci QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err), 37318c2ecf20Sopenharmony_ci QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err)); 37328c2ecf20Sopenharmony_ci if (QLCNIC_FWERROR_CODE(peg_status) == 0x67) 37338c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 37348c2ecf20Sopenharmony_ci "Firmware aborted with error code 0x00006700. " 37358c2ecf20Sopenharmony_ci "Device is being reset.\n"); 37368c2ecf20Sopenharmony_cidetach: 37378c2ecf20Sopenharmony_ci adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state : 37388c2ecf20Sopenharmony_ci QLCNIC_DEV_NEED_RESET; 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci if (qlcnic_auto_fw_reset && !test_and_set_bit(__QLCNIC_RESETTING, 37418c2ecf20Sopenharmony_ci &adapter->state)) { 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_detach_work, 0); 37448c2ecf20Sopenharmony_ci QLCDB(adapter, DRV, "fw recovery scheduled.\n"); 37458c2ecf20Sopenharmony_ci } else if (!qlcnic_auto_fw_reset && fw_dump->enable && 37468c2ecf20Sopenharmony_ci adapter->flags & QLCNIC_FW_RESET_OWNER) { 37478c2ecf20Sopenharmony_ci qlcnic_dump_fw(adapter); 37488c2ecf20Sopenharmony_ci } 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_ci return 1; 37518c2ecf20Sopenharmony_ci} 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_civoid qlcnic_fw_poll_work(struct work_struct *work) 37548c2ecf20Sopenharmony_ci{ 37558c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = container_of(work, 37568c2ecf20Sopenharmony_ci struct qlcnic_adapter, fw_work.work); 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_RESETTING, &adapter->state)) 37598c2ecf20Sopenharmony_ci goto reschedule; 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci 37628c2ecf20Sopenharmony_ci if (qlcnic_check_health(adapter)) 37638c2ecf20Sopenharmony_ci return; 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci if (adapter->fhash.fnum) 37668c2ecf20Sopenharmony_ci qlcnic_prune_lb_filters(adapter); 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_cireschedule: 37698c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); 37708c2ecf20Sopenharmony_ci} 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_cistatic int qlcnic_is_first_func(struct pci_dev *pdev) 37738c2ecf20Sopenharmony_ci{ 37748c2ecf20Sopenharmony_ci struct pci_dev *oth_pdev; 37758c2ecf20Sopenharmony_ci int val = pdev->devfn; 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci while (val-- > 0) { 37788c2ecf20Sopenharmony_ci oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr 37798c2ecf20Sopenharmony_ci (pdev->bus), pdev->bus->number, 37808c2ecf20Sopenharmony_ci PCI_DEVFN(PCI_SLOT(pdev->devfn), val)); 37818c2ecf20Sopenharmony_ci if (!oth_pdev) 37828c2ecf20Sopenharmony_ci continue; 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci if (oth_pdev->current_state != PCI_D3cold) { 37858c2ecf20Sopenharmony_ci pci_dev_put(oth_pdev); 37868c2ecf20Sopenharmony_ci return 0; 37878c2ecf20Sopenharmony_ci } 37888c2ecf20Sopenharmony_ci pci_dev_put(oth_pdev); 37898c2ecf20Sopenharmony_ci } 37908c2ecf20Sopenharmony_ci return 1; 37918c2ecf20Sopenharmony_ci} 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_cistatic int qlcnic_attach_func(struct pci_dev *pdev) 37948c2ecf20Sopenharmony_ci{ 37958c2ecf20Sopenharmony_ci int err, first_func; 37968c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); 37978c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci pdev->error_state = pci_channel_io_normal; 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 38028c2ecf20Sopenharmony_ci if (err) 38038c2ecf20Sopenharmony_ci return err; 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci pci_set_master(pdev); 38068c2ecf20Sopenharmony_ci pci_restore_state(pdev); 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci first_func = qlcnic_is_first_func(pdev); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci if (qlcnic_api_lock(adapter)) 38118c2ecf20Sopenharmony_ci return -EINVAL; 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) { 38148c2ecf20Sopenharmony_ci adapter->need_fw_reset = 1; 38158c2ecf20Sopenharmony_ci set_bit(__QLCNIC_START_FW, &adapter->state); 38168c2ecf20Sopenharmony_ci QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, 38178c2ecf20Sopenharmony_ci QLCNIC_DEV_INITIALIZING); 38188c2ecf20Sopenharmony_ci QLCDB(adapter, DRV, "Restarting fw\n"); 38198c2ecf20Sopenharmony_ci } 38208c2ecf20Sopenharmony_ci qlcnic_api_unlock(adapter); 38218c2ecf20Sopenharmony_ci 38228c2ecf20Sopenharmony_ci err = qlcnic_start_firmware(adapter); 38238c2ecf20Sopenharmony_ci if (err) 38248c2ecf20Sopenharmony_ci return err; 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci qlcnic_clr_drv_state(adapter); 38278c2ecf20Sopenharmony_ci kfree(adapter->msix_entries); 38288c2ecf20Sopenharmony_ci adapter->msix_entries = NULL; 38298c2ecf20Sopenharmony_ci err = qlcnic_setup_intr(adapter); 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci if (err) { 38328c2ecf20Sopenharmony_ci kfree(adapter->msix_entries); 38338c2ecf20Sopenharmony_ci netdev_err(netdev, "failed to setup interrupt\n"); 38348c2ecf20Sopenharmony_ci return err; 38358c2ecf20Sopenharmony_ci } 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 38388c2ecf20Sopenharmony_ci err = qlcnic_attach(adapter); 38398c2ecf20Sopenharmony_ci if (err) { 38408c2ecf20Sopenharmony_ci qlcnic_clr_all_drv_state(adapter, 1); 38418c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_AER, &adapter->state); 38428c2ecf20Sopenharmony_ci netif_device_attach(netdev); 38438c2ecf20Sopenharmony_ci return err; 38448c2ecf20Sopenharmony_ci } 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci err = qlcnic_up(adapter, netdev); 38478c2ecf20Sopenharmony_ci if (err) 38488c2ecf20Sopenharmony_ci goto done; 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci qlcnic_restore_indev_addr(netdev, NETDEV_UP); 38518c2ecf20Sopenharmony_ci } 38528c2ecf20Sopenharmony_ci done: 38538c2ecf20Sopenharmony_ci netif_device_attach(netdev); 38548c2ecf20Sopenharmony_ci return err; 38558c2ecf20Sopenharmony_ci} 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev, 38588c2ecf20Sopenharmony_ci pci_channel_state_t state) 38598c2ecf20Sopenharmony_ci{ 38608c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); 38618c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci if (state == pci_channel_io_perm_failure) 38648c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci if (state == pci_channel_io_normal) 38678c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci set_bit(__QLCNIC_AER, &adapter->state); 38708c2ecf20Sopenharmony_ci netif_device_detach(netdev); 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->fw_work); 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci if (netif_running(netdev)) 38758c2ecf20Sopenharmony_ci qlcnic_down(adapter, netdev); 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 38788c2ecf20Sopenharmony_ci qlcnic_teardown_intr(adapter); 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci pci_save_state(pdev); 38838c2ecf20Sopenharmony_ci pci_disable_device(pdev); 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 38868c2ecf20Sopenharmony_ci} 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_cistatic pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *pdev) 38898c2ecf20Sopenharmony_ci{ 38908c2ecf20Sopenharmony_ci pci_ers_result_t res; 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci rtnl_lock(); 38938c2ecf20Sopenharmony_ci res = qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT : 38948c2ecf20Sopenharmony_ci PCI_ERS_RESULT_RECOVERED; 38958c2ecf20Sopenharmony_ci rtnl_unlock(); 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci return res; 38988c2ecf20Sopenharmony_ci} 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_cistatic void qlcnic_82xx_io_resume(struct pci_dev *pdev) 39018c2ecf20Sopenharmony_ci{ 39028c2ecf20Sopenharmony_ci u32 state; 39038c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ci state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); 39068c2ecf20Sopenharmony_ci if (state == QLCNIC_DEV_READY && test_and_clear_bit(__QLCNIC_AER, 39078c2ecf20Sopenharmony_ci &adapter->state)) 39088c2ecf20Sopenharmony_ci qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, 39098c2ecf20Sopenharmony_ci FW_POLL_DELAY); 39108c2ecf20Sopenharmony_ci} 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_cistatic pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev, 39138c2ecf20Sopenharmony_ci pci_channel_state_t state) 39148c2ecf20Sopenharmony_ci{ 39158c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); 39168c2ecf20Sopenharmony_ci struct qlcnic_hardware_ops *hw_ops = adapter->ahw->hw_ops; 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_ci if (hw_ops->io_error_detected) { 39198c2ecf20Sopenharmony_ci return hw_ops->io_error_detected(pdev, state); 39208c2ecf20Sopenharmony_ci } else { 39218c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "AER error_detected handler not registered.\n"); 39228c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 39238c2ecf20Sopenharmony_ci } 39248c2ecf20Sopenharmony_ci} 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_cistatic pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev) 39278c2ecf20Sopenharmony_ci{ 39288c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); 39298c2ecf20Sopenharmony_ci struct qlcnic_hardware_ops *hw_ops = adapter->ahw->hw_ops; 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_ci if (hw_ops->io_slot_reset) { 39328c2ecf20Sopenharmony_ci return hw_ops->io_slot_reset(pdev); 39338c2ecf20Sopenharmony_ci } else { 39348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "AER slot_reset handler not registered.\n"); 39358c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 39368c2ecf20Sopenharmony_ci } 39378c2ecf20Sopenharmony_ci} 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_cistatic void qlcnic_io_resume(struct pci_dev *pdev) 39408c2ecf20Sopenharmony_ci{ 39418c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); 39428c2ecf20Sopenharmony_ci struct qlcnic_hardware_ops *hw_ops = adapter->ahw->hw_ops; 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci if (hw_ops->io_resume) 39458c2ecf20Sopenharmony_ci hw_ops->io_resume(pdev); 39468c2ecf20Sopenharmony_ci else 39478c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "AER resume handler not registered.\n"); 39488c2ecf20Sopenharmony_ci} 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_cistatic int 39528c2ecf20Sopenharmony_ciqlcnicvf_start_firmware(struct qlcnic_adapter *adapter) 39538c2ecf20Sopenharmony_ci{ 39548c2ecf20Sopenharmony_ci int err; 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_ci err = qlcnic_can_start_firmware(adapter); 39578c2ecf20Sopenharmony_ci if (err) 39588c2ecf20Sopenharmony_ci return err; 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_ci err = qlcnic_check_npar_opertional(adapter); 39618c2ecf20Sopenharmony_ci if (err) 39628c2ecf20Sopenharmony_ci return err; 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ci err = qlcnic_initialize_nic(adapter); 39658c2ecf20Sopenharmony_ci if (err) 39668c2ecf20Sopenharmony_ci return err; 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci qlcnic_check_options(adapter); 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci err = qlcnic_set_eswitch_port_config(adapter); 39718c2ecf20Sopenharmony_ci if (err) 39728c2ecf20Sopenharmony_ci return err; 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci adapter->need_fw_reset = 0; 39758c2ecf20Sopenharmony_ci 39768c2ecf20Sopenharmony_ci return err; 39778c2ecf20Sopenharmony_ci} 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ciint qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt, 39808c2ecf20Sopenharmony_ci int queue_type) 39818c2ecf20Sopenharmony_ci{ 39828c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 39838c2ecf20Sopenharmony_ci char buf[8]; 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci if (queue_type == QLCNIC_RX_QUEUE) 39868c2ecf20Sopenharmony_ci strcpy(buf, "SDS"); 39878c2ecf20Sopenharmony_ci else 39888c2ecf20Sopenharmony_ci strcpy(buf, "Tx"); 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci if (!is_power_of_2(ring_cnt)) { 39918c2ecf20Sopenharmony_ci netdev_err(netdev, "%s rings value should be a power of 2\n", 39928c2ecf20Sopenharmony_ci buf); 39938c2ecf20Sopenharmony_ci return -EINVAL; 39948c2ecf20Sopenharmony_ci } 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter) && (queue_type == QLCNIC_TX_QUEUE) && 39978c2ecf20Sopenharmony_ci !qlcnic_check_multi_tx(adapter)) { 39988c2ecf20Sopenharmony_ci netdev_err(netdev, "No Multi Tx queue support\n"); 39998c2ecf20Sopenharmony_ci return -EINVAL; 40008c2ecf20Sopenharmony_ci } 40018c2ecf20Sopenharmony_ci 40028c2ecf20Sopenharmony_ci if (ring_cnt > num_online_cpus()) { 40038c2ecf20Sopenharmony_ci netdev_err(netdev, 40048c2ecf20Sopenharmony_ci "%s value[%u] should not be higher than, number of online CPUs\n", 40058c2ecf20Sopenharmony_ci buf, num_online_cpus()); 40068c2ecf20Sopenharmony_ci return -EINVAL; 40078c2ecf20Sopenharmony_ci } 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ci return 0; 40108c2ecf20Sopenharmony_ci} 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ciint qlcnic_setup_rings(struct qlcnic_adapter *adapter) 40138c2ecf20Sopenharmony_ci{ 40148c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 40158c2ecf20Sopenharmony_ci u8 tx_rings, rx_rings; 40168c2ecf20Sopenharmony_ci int err; 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_RESETTING, &adapter->state)) 40198c2ecf20Sopenharmony_ci return -EBUSY; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci tx_rings = adapter->drv_tss_rings; 40228c2ecf20Sopenharmony_ci rx_rings = adapter->drv_rss_rings; 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci netif_device_detach(netdev); 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci err = qlcnic_set_real_num_queues(adapter, tx_rings, rx_rings); 40278c2ecf20Sopenharmony_ci if (err) 40288c2ecf20Sopenharmony_ci goto done; 40298c2ecf20Sopenharmony_ci 40308c2ecf20Sopenharmony_ci if (netif_running(netdev)) 40318c2ecf20Sopenharmony_ci __qlcnic_down(adapter, netdev); 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci qlcnic_detach(adapter); 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 40368c2ecf20Sopenharmony_ci qlcnic_83xx_free_mbx_intr(adapter); 40378c2ecf20Sopenharmony_ci qlcnic_83xx_enable_mbx_poll(adapter); 40388c2ecf20Sopenharmony_ci } 40398c2ecf20Sopenharmony_ci 40408c2ecf20Sopenharmony_ci qlcnic_teardown_intr(adapter); 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci err = qlcnic_setup_intr(adapter); 40438c2ecf20Sopenharmony_ci if (err) { 40448c2ecf20Sopenharmony_ci kfree(adapter->msix_entries); 40458c2ecf20Sopenharmony_ci netdev_err(netdev, "failed to setup interrupt\n"); 40468c2ecf20Sopenharmony_ci return err; 40478c2ecf20Sopenharmony_ci } 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_ci /* Check if we need to update real_num_{tx|rx}_queues because 40508c2ecf20Sopenharmony_ci * qlcnic_setup_intr() may change Tx/Rx rings size 40518c2ecf20Sopenharmony_ci */ 40528c2ecf20Sopenharmony_ci if ((tx_rings != adapter->drv_tx_rings) || 40538c2ecf20Sopenharmony_ci (rx_rings != adapter->drv_sds_rings)) { 40548c2ecf20Sopenharmony_ci err = qlcnic_set_real_num_queues(adapter, 40558c2ecf20Sopenharmony_ci adapter->drv_tx_rings, 40568c2ecf20Sopenharmony_ci adapter->drv_sds_rings); 40578c2ecf20Sopenharmony_ci if (err) 40588c2ecf20Sopenharmony_ci goto done; 40598c2ecf20Sopenharmony_ci } 40608c2ecf20Sopenharmony_ci 40618c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 40628c2ecf20Sopenharmony_ci qlcnic_83xx_initialize_nic(adapter, 1); 40638c2ecf20Sopenharmony_ci err = qlcnic_83xx_setup_mbx_intr(adapter); 40648c2ecf20Sopenharmony_ci qlcnic_83xx_disable_mbx_poll(adapter); 40658c2ecf20Sopenharmony_ci if (err) { 40668c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 40678c2ecf20Sopenharmony_ci "failed to setup mbx interrupt\n"); 40688c2ecf20Sopenharmony_ci goto done; 40698c2ecf20Sopenharmony_ci } 40708c2ecf20Sopenharmony_ci } 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 40738c2ecf20Sopenharmony_ci err = qlcnic_attach(adapter); 40748c2ecf20Sopenharmony_ci if (err) 40758c2ecf20Sopenharmony_ci goto done; 40768c2ecf20Sopenharmony_ci err = __qlcnic_up(adapter, netdev); 40778c2ecf20Sopenharmony_ci if (err) 40788c2ecf20Sopenharmony_ci goto done; 40798c2ecf20Sopenharmony_ci qlcnic_restore_indev_addr(netdev, NETDEV_UP); 40808c2ecf20Sopenharmony_ci } 40818c2ecf20Sopenharmony_cidone: 40828c2ecf20Sopenharmony_ci netif_device_attach(netdev); 40838c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 40848c2ecf20Sopenharmony_ci return err; 40858c2ecf20Sopenharmony_ci} 40868c2ecf20Sopenharmony_ci 40878c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ci#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops) 40908c2ecf20Sopenharmony_ci 40918c2ecf20Sopenharmony_cistatic void 40928c2ecf20Sopenharmony_ciqlcnic_config_indev_addr(struct qlcnic_adapter *adapter, 40938c2ecf20Sopenharmony_ci struct net_device *dev, unsigned long event) 40948c2ecf20Sopenharmony_ci{ 40958c2ecf20Sopenharmony_ci const struct in_ifaddr *ifa; 40968c2ecf20Sopenharmony_ci struct in_device *indev; 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci indev = in_dev_get(dev); 40998c2ecf20Sopenharmony_ci if (!indev) 41008c2ecf20Sopenharmony_ci return; 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci in_dev_for_each_ifa_rtnl(ifa, indev) { 41038c2ecf20Sopenharmony_ci switch (event) { 41048c2ecf20Sopenharmony_ci case NETDEV_UP: 41058c2ecf20Sopenharmony_ci qlcnic_config_ipaddr(adapter, 41068c2ecf20Sopenharmony_ci ifa->ifa_address, QLCNIC_IP_UP); 41078c2ecf20Sopenharmony_ci break; 41088c2ecf20Sopenharmony_ci case NETDEV_DOWN: 41098c2ecf20Sopenharmony_ci qlcnic_config_ipaddr(adapter, 41108c2ecf20Sopenharmony_ci ifa->ifa_address, QLCNIC_IP_DOWN); 41118c2ecf20Sopenharmony_ci break; 41128c2ecf20Sopenharmony_ci default: 41138c2ecf20Sopenharmony_ci break; 41148c2ecf20Sopenharmony_ci } 41158c2ecf20Sopenharmony_ci } 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci in_dev_put(indev); 41188c2ecf20Sopenharmony_ci} 41198c2ecf20Sopenharmony_ci 41208c2ecf20Sopenharmony_civoid qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event) 41218c2ecf20Sopenharmony_ci{ 41228c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 41238c2ecf20Sopenharmony_ci struct net_device *dev; 41248c2ecf20Sopenharmony_ci u16 vid; 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci qlcnic_config_indev_addr(adapter, netdev, event); 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci rcu_read_lock(); 41298c2ecf20Sopenharmony_ci for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) { 41308c2ecf20Sopenharmony_ci dev = __vlan_find_dev_deep_rcu(netdev, htons(ETH_P_8021Q), vid); 41318c2ecf20Sopenharmony_ci if (!dev) 41328c2ecf20Sopenharmony_ci continue; 41338c2ecf20Sopenharmony_ci qlcnic_config_indev_addr(adapter, dev, event); 41348c2ecf20Sopenharmony_ci } 41358c2ecf20Sopenharmony_ci rcu_read_unlock(); 41368c2ecf20Sopenharmony_ci} 41378c2ecf20Sopenharmony_ci 41388c2ecf20Sopenharmony_cistatic int qlcnic_netdev_event(struct notifier_block *this, 41398c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 41408c2ecf20Sopenharmony_ci{ 41418c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter; 41428c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 41438c2ecf20Sopenharmony_ci 41448c2ecf20Sopenharmony_cirecheck: 41458c2ecf20Sopenharmony_ci if (dev == NULL) 41468c2ecf20Sopenharmony_ci goto done; 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_ci if (is_vlan_dev(dev)) { 41498c2ecf20Sopenharmony_ci dev = vlan_dev_real_dev(dev); 41508c2ecf20Sopenharmony_ci goto recheck; 41518c2ecf20Sopenharmony_ci } 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci if (!is_qlcnic_netdev(dev)) 41548c2ecf20Sopenharmony_ci goto done; 41558c2ecf20Sopenharmony_ci 41568c2ecf20Sopenharmony_ci adapter = netdev_priv(dev); 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci if (!adapter) 41598c2ecf20Sopenharmony_ci goto done; 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) 41628c2ecf20Sopenharmony_ci goto done; 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ci qlcnic_config_indev_addr(adapter, dev, event); 41658c2ecf20Sopenharmony_cidone: 41668c2ecf20Sopenharmony_ci return NOTIFY_DONE; 41678c2ecf20Sopenharmony_ci} 41688c2ecf20Sopenharmony_ci 41698c2ecf20Sopenharmony_cistatic int 41708c2ecf20Sopenharmony_ciqlcnic_inetaddr_event(struct notifier_block *this, 41718c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 41728c2ecf20Sopenharmony_ci{ 41738c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter; 41748c2ecf20Sopenharmony_ci struct net_device *dev; 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; 41778c2ecf20Sopenharmony_ci 41788c2ecf20Sopenharmony_ci dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_cirecheck: 41818c2ecf20Sopenharmony_ci if (dev == NULL) 41828c2ecf20Sopenharmony_ci goto done; 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci if (is_vlan_dev(dev)) { 41858c2ecf20Sopenharmony_ci dev = vlan_dev_real_dev(dev); 41868c2ecf20Sopenharmony_ci goto recheck; 41878c2ecf20Sopenharmony_ci } 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_ci if (!is_qlcnic_netdev(dev)) 41908c2ecf20Sopenharmony_ci goto done; 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_ci adapter = netdev_priv(dev); 41938c2ecf20Sopenharmony_ci 41948c2ecf20Sopenharmony_ci if (!adapter) 41958c2ecf20Sopenharmony_ci goto done; 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ci if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) 41988c2ecf20Sopenharmony_ci goto done; 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci switch (event) { 42018c2ecf20Sopenharmony_ci case NETDEV_UP: 42028c2ecf20Sopenharmony_ci qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP); 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_ci break; 42058c2ecf20Sopenharmony_ci case NETDEV_DOWN: 42068c2ecf20Sopenharmony_ci qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN); 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci break; 42098c2ecf20Sopenharmony_ci default: 42108c2ecf20Sopenharmony_ci break; 42118c2ecf20Sopenharmony_ci } 42128c2ecf20Sopenharmony_ci 42138c2ecf20Sopenharmony_cidone: 42148c2ecf20Sopenharmony_ci return NOTIFY_DONE; 42158c2ecf20Sopenharmony_ci} 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_cistatic struct notifier_block qlcnic_netdev_cb = { 42188c2ecf20Sopenharmony_ci .notifier_call = qlcnic_netdev_event, 42198c2ecf20Sopenharmony_ci}; 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_cistatic struct notifier_block qlcnic_inetaddr_cb = { 42228c2ecf20Sopenharmony_ci .notifier_call = qlcnic_inetaddr_event, 42238c2ecf20Sopenharmony_ci}; 42248c2ecf20Sopenharmony_ci#else 42258c2ecf20Sopenharmony_civoid qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event) 42268c2ecf20Sopenharmony_ci{ } 42278c2ecf20Sopenharmony_ci#endif 42288c2ecf20Sopenharmony_cistatic const struct pci_error_handlers qlcnic_err_handler = { 42298c2ecf20Sopenharmony_ci .error_detected = qlcnic_io_error_detected, 42308c2ecf20Sopenharmony_ci .slot_reset = qlcnic_io_slot_reset, 42318c2ecf20Sopenharmony_ci .resume = qlcnic_io_resume, 42328c2ecf20Sopenharmony_ci}; 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(qlcnic_pm_ops, qlcnic_suspend, qlcnic_resume); 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_cistatic struct pci_driver qlcnic_driver = { 42378c2ecf20Sopenharmony_ci .name = qlcnic_driver_name, 42388c2ecf20Sopenharmony_ci .id_table = qlcnic_pci_tbl, 42398c2ecf20Sopenharmony_ci .probe = qlcnic_probe, 42408c2ecf20Sopenharmony_ci .remove = qlcnic_remove, 42418c2ecf20Sopenharmony_ci .driver.pm = &qlcnic_pm_ops, 42428c2ecf20Sopenharmony_ci .shutdown = qlcnic_shutdown, 42438c2ecf20Sopenharmony_ci .err_handler = &qlcnic_err_handler, 42448c2ecf20Sopenharmony_ci#ifdef CONFIG_QLCNIC_SRIOV 42458c2ecf20Sopenharmony_ci .sriov_configure = qlcnic_pci_sriov_configure, 42468c2ecf20Sopenharmony_ci#endif 42478c2ecf20Sopenharmony_ci 42488c2ecf20Sopenharmony_ci}; 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_cistatic int __init qlcnic_init_module(void) 42518c2ecf20Sopenharmony_ci{ 42528c2ecf20Sopenharmony_ci int ret; 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci printk(KERN_INFO "%s\n", qlcnic_driver_string); 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 42578c2ecf20Sopenharmony_ci register_netdevice_notifier(&qlcnic_netdev_cb); 42588c2ecf20Sopenharmony_ci register_inetaddr_notifier(&qlcnic_inetaddr_cb); 42598c2ecf20Sopenharmony_ci#endif 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_ci ret = pci_register_driver(&qlcnic_driver); 42628c2ecf20Sopenharmony_ci if (ret) { 42638c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 42648c2ecf20Sopenharmony_ci unregister_inetaddr_notifier(&qlcnic_inetaddr_cb); 42658c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&qlcnic_netdev_cb); 42668c2ecf20Sopenharmony_ci#endif 42678c2ecf20Sopenharmony_ci } 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_ci return ret; 42708c2ecf20Sopenharmony_ci} 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_cimodule_init(qlcnic_init_module); 42738c2ecf20Sopenharmony_ci 42748c2ecf20Sopenharmony_cistatic void __exit qlcnic_exit_module(void) 42758c2ecf20Sopenharmony_ci{ 42768c2ecf20Sopenharmony_ci pci_unregister_driver(&qlcnic_driver); 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 42798c2ecf20Sopenharmony_ci unregister_inetaddr_notifier(&qlcnic_inetaddr_cb); 42808c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&qlcnic_netdev_cb); 42818c2ecf20Sopenharmony_ci#endif 42828c2ecf20Sopenharmony_ci} 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_cimodule_exit(qlcnic_exit_module); 4285