162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "iavf.h" 562306a36Sopenharmony_ci#include "iavf_prototype.h" 662306a36Sopenharmony_ci#include "iavf_client.h" 762306a36Sopenharmony_ci/* All iavf tracepoints are defined by the include below, which must 862306a36Sopenharmony_ci * be included exactly once across the whole kernel with 962306a36Sopenharmony_ci * CREATE_TRACE_POINTS defined 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 1262306a36Sopenharmony_ci#include "iavf_trace.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int iavf_setup_all_tx_resources(struct iavf_adapter *adapter); 1562306a36Sopenharmony_cistatic int iavf_setup_all_rx_resources(struct iavf_adapter *adapter); 1662306a36Sopenharmony_cistatic int iavf_close(struct net_device *netdev); 1762306a36Sopenharmony_cistatic void iavf_init_get_resources(struct iavf_adapter *adapter); 1862306a36Sopenharmony_cistatic int iavf_check_reset_complete(struct iavf_hw *hw); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cichar iavf_driver_name[] = "iavf"; 2162306a36Sopenharmony_cistatic const char iavf_driver_string[] = 2262306a36Sopenharmony_ci "Intel(R) Ethernet Adaptive Virtual Function Network Driver"; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const char iavf_copyright[] = 2562306a36Sopenharmony_ci "Copyright (c) 2013 - 2018 Intel Corporation."; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* iavf_pci_tbl - PCI Device ID Table 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last 3062306a36Sopenharmony_ci * Last entry must be all 0s 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, 3362306a36Sopenharmony_ci * Class, Class Mask, private data (not used) } 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic const struct pci_device_id iavf_pci_tbl[] = { 3662306a36Sopenharmony_ci {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF), 0}, 3762306a36Sopenharmony_ci {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF_HV), 0}, 3862306a36Sopenharmony_ci {PCI_VDEVICE(INTEL, IAVF_DEV_ID_X722_VF), 0}, 3962306a36Sopenharmony_ci {PCI_VDEVICE(INTEL, IAVF_DEV_ID_ADAPTIVE_VF), 0}, 4062306a36Sopenharmony_ci /* required last entry */ 4162306a36Sopenharmony_ci {0, } 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, iavf_pci_tbl); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciMODULE_ALIAS("i40evf"); 4762306a36Sopenharmony_ciMODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>"); 4862306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel(R) Ethernet Adaptive Virtual Function Network Driver"); 4962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic const struct net_device_ops iavf_netdev_ops; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciint iavf_status_to_errno(enum iavf_status status) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci switch (status) { 5662306a36Sopenharmony_ci case IAVF_SUCCESS: 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci case IAVF_ERR_PARAM: 5962306a36Sopenharmony_ci case IAVF_ERR_MAC_TYPE: 6062306a36Sopenharmony_ci case IAVF_ERR_INVALID_MAC_ADDR: 6162306a36Sopenharmony_ci case IAVF_ERR_INVALID_LINK_SETTINGS: 6262306a36Sopenharmony_ci case IAVF_ERR_INVALID_PD_ID: 6362306a36Sopenharmony_ci case IAVF_ERR_INVALID_QP_ID: 6462306a36Sopenharmony_ci case IAVF_ERR_INVALID_CQ_ID: 6562306a36Sopenharmony_ci case IAVF_ERR_INVALID_CEQ_ID: 6662306a36Sopenharmony_ci case IAVF_ERR_INVALID_AEQ_ID: 6762306a36Sopenharmony_ci case IAVF_ERR_INVALID_SIZE: 6862306a36Sopenharmony_ci case IAVF_ERR_INVALID_ARP_INDEX: 6962306a36Sopenharmony_ci case IAVF_ERR_INVALID_FPM_FUNC_ID: 7062306a36Sopenharmony_ci case IAVF_ERR_QP_INVALID_MSG_SIZE: 7162306a36Sopenharmony_ci case IAVF_ERR_INVALID_FRAG_COUNT: 7262306a36Sopenharmony_ci case IAVF_ERR_INVALID_ALIGNMENT: 7362306a36Sopenharmony_ci case IAVF_ERR_INVALID_PUSH_PAGE_INDEX: 7462306a36Sopenharmony_ci case IAVF_ERR_INVALID_IMM_DATA_SIZE: 7562306a36Sopenharmony_ci case IAVF_ERR_INVALID_VF_ID: 7662306a36Sopenharmony_ci case IAVF_ERR_INVALID_HMCFN_ID: 7762306a36Sopenharmony_ci case IAVF_ERR_INVALID_PBLE_INDEX: 7862306a36Sopenharmony_ci case IAVF_ERR_INVALID_SD_INDEX: 7962306a36Sopenharmony_ci case IAVF_ERR_INVALID_PAGE_DESC_INDEX: 8062306a36Sopenharmony_ci case IAVF_ERR_INVALID_SD_TYPE: 8162306a36Sopenharmony_ci case IAVF_ERR_INVALID_HMC_OBJ_INDEX: 8262306a36Sopenharmony_ci case IAVF_ERR_INVALID_HMC_OBJ_COUNT: 8362306a36Sopenharmony_ci case IAVF_ERR_INVALID_SRQ_ARM_LIMIT: 8462306a36Sopenharmony_ci return -EINVAL; 8562306a36Sopenharmony_ci case IAVF_ERR_NVM: 8662306a36Sopenharmony_ci case IAVF_ERR_NVM_CHECKSUM: 8762306a36Sopenharmony_ci case IAVF_ERR_PHY: 8862306a36Sopenharmony_ci case IAVF_ERR_CONFIG: 8962306a36Sopenharmony_ci case IAVF_ERR_UNKNOWN_PHY: 9062306a36Sopenharmony_ci case IAVF_ERR_LINK_SETUP: 9162306a36Sopenharmony_ci case IAVF_ERR_ADAPTER_STOPPED: 9262306a36Sopenharmony_ci case IAVF_ERR_PRIMARY_REQUESTS_PENDING: 9362306a36Sopenharmony_ci case IAVF_ERR_AUTONEG_NOT_COMPLETE: 9462306a36Sopenharmony_ci case IAVF_ERR_RESET_FAILED: 9562306a36Sopenharmony_ci case IAVF_ERR_BAD_PTR: 9662306a36Sopenharmony_ci case IAVF_ERR_SWFW_SYNC: 9762306a36Sopenharmony_ci case IAVF_ERR_QP_TOOMANY_WRS_POSTED: 9862306a36Sopenharmony_ci case IAVF_ERR_QUEUE_EMPTY: 9962306a36Sopenharmony_ci case IAVF_ERR_FLUSHED_QUEUE: 10062306a36Sopenharmony_ci case IAVF_ERR_OPCODE_MISMATCH: 10162306a36Sopenharmony_ci case IAVF_ERR_CQP_COMPL_ERROR: 10262306a36Sopenharmony_ci case IAVF_ERR_BACKING_PAGE_ERROR: 10362306a36Sopenharmony_ci case IAVF_ERR_NO_PBLCHUNKS_AVAILABLE: 10462306a36Sopenharmony_ci case IAVF_ERR_MEMCPY_FAILED: 10562306a36Sopenharmony_ci case IAVF_ERR_SRQ_ENABLED: 10662306a36Sopenharmony_ci case IAVF_ERR_ADMIN_QUEUE_ERROR: 10762306a36Sopenharmony_ci case IAVF_ERR_ADMIN_QUEUE_FULL: 10862306a36Sopenharmony_ci case IAVF_ERR_BAD_RDMA_CQE: 10962306a36Sopenharmony_ci case IAVF_ERR_NVM_BLANK_MODE: 11062306a36Sopenharmony_ci case IAVF_ERR_PE_DOORBELL_NOT_ENABLED: 11162306a36Sopenharmony_ci case IAVF_ERR_DIAG_TEST_FAILED: 11262306a36Sopenharmony_ci case IAVF_ERR_FIRMWARE_API_VERSION: 11362306a36Sopenharmony_ci case IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR: 11462306a36Sopenharmony_ci return -EIO; 11562306a36Sopenharmony_ci case IAVF_ERR_DEVICE_NOT_SUPPORTED: 11662306a36Sopenharmony_ci return -ENODEV; 11762306a36Sopenharmony_ci case IAVF_ERR_NO_AVAILABLE_VSI: 11862306a36Sopenharmony_ci case IAVF_ERR_RING_FULL: 11962306a36Sopenharmony_ci return -ENOSPC; 12062306a36Sopenharmony_ci case IAVF_ERR_NO_MEMORY: 12162306a36Sopenharmony_ci return -ENOMEM; 12262306a36Sopenharmony_ci case IAVF_ERR_TIMEOUT: 12362306a36Sopenharmony_ci case IAVF_ERR_ADMIN_QUEUE_TIMEOUT: 12462306a36Sopenharmony_ci return -ETIMEDOUT; 12562306a36Sopenharmony_ci case IAVF_ERR_NOT_IMPLEMENTED: 12662306a36Sopenharmony_ci case IAVF_NOT_SUPPORTED: 12762306a36Sopenharmony_ci return -EOPNOTSUPP; 12862306a36Sopenharmony_ci case IAVF_ERR_ADMIN_QUEUE_NO_WORK: 12962306a36Sopenharmony_ci return -EALREADY; 13062306a36Sopenharmony_ci case IAVF_ERR_NOT_READY: 13162306a36Sopenharmony_ci return -EBUSY; 13262306a36Sopenharmony_ci case IAVF_ERR_BUF_TOO_SHORT: 13362306a36Sopenharmony_ci return -EMSGSIZE; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return -EIO; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciint virtchnl_status_to_errno(enum virtchnl_status_code v_status) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci switch (v_status) { 14262306a36Sopenharmony_ci case VIRTCHNL_STATUS_SUCCESS: 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci case VIRTCHNL_STATUS_ERR_PARAM: 14562306a36Sopenharmony_ci case VIRTCHNL_STATUS_ERR_INVALID_VF_ID: 14662306a36Sopenharmony_ci return -EINVAL; 14762306a36Sopenharmony_ci case VIRTCHNL_STATUS_ERR_NO_MEMORY: 14862306a36Sopenharmony_ci return -ENOMEM; 14962306a36Sopenharmony_ci case VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH: 15062306a36Sopenharmony_ci case VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR: 15162306a36Sopenharmony_ci case VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR: 15262306a36Sopenharmony_ci return -EIO; 15362306a36Sopenharmony_ci case VIRTCHNL_STATUS_ERR_NOT_SUPPORTED: 15462306a36Sopenharmony_ci return -EOPNOTSUPP; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return -EIO; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/** 16162306a36Sopenharmony_ci * iavf_pdev_to_adapter - go from pci_dev to adapter 16262306a36Sopenharmony_ci * @pdev: pci_dev pointer 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic struct iavf_adapter *iavf_pdev_to_adapter(struct pci_dev *pdev) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci return netdev_priv(pci_get_drvdata(pdev)); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * iavf_is_reset_in_progress - Check if a reset is in progress 17162306a36Sopenharmony_ci * @adapter: board private structure 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_cistatic bool iavf_is_reset_in_progress(struct iavf_adapter *adapter) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci if (adapter->state == __IAVF_RESETTING || 17662306a36Sopenharmony_ci adapter->flags & (IAVF_FLAG_RESET_PENDING | 17762306a36Sopenharmony_ci IAVF_FLAG_RESET_NEEDED)) 17862306a36Sopenharmony_ci return true; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return false; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/** 18462306a36Sopenharmony_ci * iavf_wait_for_reset - Wait for reset to finish. 18562306a36Sopenharmony_ci * @adapter: board private structure 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * Returns 0 if reset finished successfully, negative on timeout or interrupt. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ciint iavf_wait_for_reset(struct iavf_adapter *adapter) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci int ret = wait_event_interruptible_timeout(adapter->reset_waitqueue, 19262306a36Sopenharmony_ci !iavf_is_reset_in_progress(adapter), 19362306a36Sopenharmony_ci msecs_to_jiffies(5000)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* If ret < 0 then it means wait was interrupted. 19662306a36Sopenharmony_ci * If ret == 0 then it means we got a timeout while waiting 19762306a36Sopenharmony_ci * for reset to finish. 19862306a36Sopenharmony_ci * If ret > 0 it means reset has finished. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci if (ret > 0) 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci else if (ret < 0) 20362306a36Sopenharmony_ci return -EINTR; 20462306a36Sopenharmony_ci else 20562306a36Sopenharmony_ci return -EBUSY; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/** 20962306a36Sopenharmony_ci * iavf_allocate_dma_mem_d - OS specific memory alloc for shared code 21062306a36Sopenharmony_ci * @hw: pointer to the HW structure 21162306a36Sopenharmony_ci * @mem: ptr to mem struct to fill out 21262306a36Sopenharmony_ci * @size: size of memory requested 21362306a36Sopenharmony_ci * @alignment: what to align the allocation to 21462306a36Sopenharmony_ci **/ 21562306a36Sopenharmony_cienum iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw, 21662306a36Sopenharmony_ci struct iavf_dma_mem *mem, 21762306a36Sopenharmony_ci u64 size, u32 alignment) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (!mem) 22262306a36Sopenharmony_ci return IAVF_ERR_PARAM; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci mem->size = ALIGN(size, alignment); 22562306a36Sopenharmony_ci mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, 22662306a36Sopenharmony_ci (dma_addr_t *)&mem->pa, GFP_KERNEL); 22762306a36Sopenharmony_ci if (mem->va) 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci else 23062306a36Sopenharmony_ci return IAVF_ERR_NO_MEMORY; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/** 23462306a36Sopenharmony_ci * iavf_free_dma_mem - wrapper for DMA memory freeing 23562306a36Sopenharmony_ci * @hw: pointer to the HW structure 23662306a36Sopenharmony_ci * @mem: ptr to mem struct to free 23762306a36Sopenharmony_ci **/ 23862306a36Sopenharmony_cienum iavf_status iavf_free_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (!mem || !mem->va) 24362306a36Sopenharmony_ci return IAVF_ERR_PARAM; 24462306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, mem->size, 24562306a36Sopenharmony_ci mem->va, (dma_addr_t)mem->pa); 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/** 25062306a36Sopenharmony_ci * iavf_allocate_virt_mem - virt memory alloc wrapper 25162306a36Sopenharmony_ci * @hw: pointer to the HW structure 25262306a36Sopenharmony_ci * @mem: ptr to mem struct to fill out 25362306a36Sopenharmony_ci * @size: size of memory requested 25462306a36Sopenharmony_ci **/ 25562306a36Sopenharmony_cienum iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw, 25662306a36Sopenharmony_ci struct iavf_virt_mem *mem, u32 size) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci if (!mem) 25962306a36Sopenharmony_ci return IAVF_ERR_PARAM; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci mem->size = size; 26262306a36Sopenharmony_ci mem->va = kzalloc(size, GFP_KERNEL); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (mem->va) 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci else 26762306a36Sopenharmony_ci return IAVF_ERR_NO_MEMORY; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/** 27162306a36Sopenharmony_ci * iavf_free_virt_mem - virt memory free wrapper 27262306a36Sopenharmony_ci * @hw: pointer to the HW structure 27362306a36Sopenharmony_ci * @mem: ptr to mem struct to free 27462306a36Sopenharmony_ci **/ 27562306a36Sopenharmony_civoid iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci kfree(mem->va); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/** 28162306a36Sopenharmony_ci * iavf_schedule_reset - Set the flags and schedule a reset event 28262306a36Sopenharmony_ci * @adapter: board private structure 28362306a36Sopenharmony_ci * @flags: IAVF_FLAG_RESET_PENDING or IAVF_FLAG_RESET_NEEDED 28462306a36Sopenharmony_ci **/ 28562306a36Sopenharmony_civoid iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) && 28862306a36Sopenharmony_ci !(adapter->flags & 28962306a36Sopenharmony_ci (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) { 29062306a36Sopenharmony_ci adapter->flags |= flags; 29162306a36Sopenharmony_ci queue_work(adapter->wq, &adapter->reset_task); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/** 29662306a36Sopenharmony_ci * iavf_schedule_aq_request - Set the flags and schedule aq request 29762306a36Sopenharmony_ci * @adapter: board private structure 29862306a36Sopenharmony_ci * @flags: requested aq flags 29962306a36Sopenharmony_ci **/ 30062306a36Sopenharmony_civoid iavf_schedule_aq_request(struct iavf_adapter *adapter, u64 flags) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci adapter->aq_required |= flags; 30362306a36Sopenharmony_ci mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/** 30762306a36Sopenharmony_ci * iavf_tx_timeout - Respond to a Tx Hang 30862306a36Sopenharmony_ci * @netdev: network interface device structure 30962306a36Sopenharmony_ci * @txqueue: queue number that is timing out 31062306a36Sopenharmony_ci **/ 31162306a36Sopenharmony_cistatic void iavf_tx_timeout(struct net_device *netdev, unsigned int txqueue) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci adapter->tx_timeout_count++; 31662306a36Sopenharmony_ci iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/** 32062306a36Sopenharmony_ci * iavf_misc_irq_disable - Mask off interrupt generation on the NIC 32162306a36Sopenharmony_ci * @adapter: board private structure 32262306a36Sopenharmony_ci **/ 32362306a36Sopenharmony_cistatic void iavf_misc_irq_disable(struct iavf_adapter *adapter) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (!adapter->msix_entries) 32862306a36Sopenharmony_ci return; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci wr32(hw, IAVF_VFINT_DYN_CTL01, 0); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci iavf_flush(hw); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci synchronize_irq(adapter->msix_entries[0].vector); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/** 33862306a36Sopenharmony_ci * iavf_misc_irq_enable - Enable default interrupt generation settings 33962306a36Sopenharmony_ci * @adapter: board private structure 34062306a36Sopenharmony_ci **/ 34162306a36Sopenharmony_cistatic void iavf_misc_irq_enable(struct iavf_adapter *adapter) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci wr32(hw, IAVF_VFINT_DYN_CTL01, IAVF_VFINT_DYN_CTL01_INTENA_MASK | 34662306a36Sopenharmony_ci IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK); 34762306a36Sopenharmony_ci wr32(hw, IAVF_VFINT_ICR0_ENA1, IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci iavf_flush(hw); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/** 35362306a36Sopenharmony_ci * iavf_irq_disable - Mask off interrupt generation on the NIC 35462306a36Sopenharmony_ci * @adapter: board private structure 35562306a36Sopenharmony_ci **/ 35662306a36Sopenharmony_cistatic void iavf_irq_disable(struct iavf_adapter *adapter) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int i; 35962306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!adapter->msix_entries) 36262306a36Sopenharmony_ci return; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci for (i = 1; i < adapter->num_msix_vectors; i++) { 36562306a36Sopenharmony_ci wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1), 0); 36662306a36Sopenharmony_ci synchronize_irq(adapter->msix_entries[i].vector); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci iavf_flush(hw); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/** 37262306a36Sopenharmony_ci * iavf_irq_enable_queues - Enable interrupt for all queues 37362306a36Sopenharmony_ci * @adapter: board private structure 37462306a36Sopenharmony_ci **/ 37562306a36Sopenharmony_cistatic void iavf_irq_enable_queues(struct iavf_adapter *adapter) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 37862306a36Sopenharmony_ci int i; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci for (i = 1; i < adapter->num_msix_vectors; i++) { 38162306a36Sopenharmony_ci wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1), 38262306a36Sopenharmony_ci IAVF_VFINT_DYN_CTLN1_INTENA_MASK | 38362306a36Sopenharmony_ci IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/** 38862306a36Sopenharmony_ci * iavf_irq_enable - Enable default interrupt generation settings 38962306a36Sopenharmony_ci * @adapter: board private structure 39062306a36Sopenharmony_ci * @flush: boolean value whether to run rd32() 39162306a36Sopenharmony_ci **/ 39262306a36Sopenharmony_civoid iavf_irq_enable(struct iavf_adapter *adapter, bool flush) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci iavf_misc_irq_enable(adapter); 39762306a36Sopenharmony_ci iavf_irq_enable_queues(adapter); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (flush) 40062306a36Sopenharmony_ci iavf_flush(hw); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/** 40462306a36Sopenharmony_ci * iavf_msix_aq - Interrupt handler for vector 0 40562306a36Sopenharmony_ci * @irq: interrupt number 40662306a36Sopenharmony_ci * @data: pointer to netdev 40762306a36Sopenharmony_ci **/ 40862306a36Sopenharmony_cistatic irqreturn_t iavf_msix_aq(int irq, void *data) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct net_device *netdev = data; 41162306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 41262306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* handle non-queue interrupts, these reads clear the registers */ 41562306a36Sopenharmony_ci rd32(hw, IAVF_VFINT_ICR01); 41662306a36Sopenharmony_ci rd32(hw, IAVF_VFINT_ICR0_ENA1); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (adapter->state != __IAVF_REMOVE) 41962306a36Sopenharmony_ci /* schedule work on the private workqueue */ 42062306a36Sopenharmony_ci queue_work(adapter->wq, &adapter->adminq_task); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return IRQ_HANDLED; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/** 42662306a36Sopenharmony_ci * iavf_msix_clean_rings - MSIX mode Interrupt Handler 42762306a36Sopenharmony_ci * @irq: interrupt number 42862306a36Sopenharmony_ci * @data: pointer to a q_vector 42962306a36Sopenharmony_ci **/ 43062306a36Sopenharmony_cistatic irqreturn_t iavf_msix_clean_rings(int irq, void *data) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct iavf_q_vector *q_vector = data; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (!q_vector->tx.ring && !q_vector->rx.ring) 43562306a36Sopenharmony_ci return IRQ_HANDLED; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci napi_schedule_irqoff(&q_vector->napi); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci return IRQ_HANDLED; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci/** 44362306a36Sopenharmony_ci * iavf_map_vector_to_rxq - associate irqs with rx queues 44462306a36Sopenharmony_ci * @adapter: board private structure 44562306a36Sopenharmony_ci * @v_idx: interrupt number 44662306a36Sopenharmony_ci * @r_idx: queue number 44762306a36Sopenharmony_ci **/ 44862306a36Sopenharmony_cistatic void 44962306a36Sopenharmony_ciiavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct iavf_q_vector *q_vector = &adapter->q_vectors[v_idx]; 45262306a36Sopenharmony_ci struct iavf_ring *rx_ring = &adapter->rx_rings[r_idx]; 45362306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci rx_ring->q_vector = q_vector; 45662306a36Sopenharmony_ci rx_ring->next = q_vector->rx.ring; 45762306a36Sopenharmony_ci rx_ring->vsi = &adapter->vsi; 45862306a36Sopenharmony_ci q_vector->rx.ring = rx_ring; 45962306a36Sopenharmony_ci q_vector->rx.count++; 46062306a36Sopenharmony_ci q_vector->rx.next_update = jiffies + 1; 46162306a36Sopenharmony_ci q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting); 46262306a36Sopenharmony_ci q_vector->ring_mask |= BIT(r_idx); 46362306a36Sopenharmony_ci wr32(hw, IAVF_VFINT_ITRN1(IAVF_RX_ITR, q_vector->reg_idx), 46462306a36Sopenharmony_ci q_vector->rx.current_itr >> 1); 46562306a36Sopenharmony_ci q_vector->rx.current_itr = q_vector->rx.target_itr; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/** 46962306a36Sopenharmony_ci * iavf_map_vector_to_txq - associate irqs with tx queues 47062306a36Sopenharmony_ci * @adapter: board private structure 47162306a36Sopenharmony_ci * @v_idx: interrupt number 47262306a36Sopenharmony_ci * @t_idx: queue number 47362306a36Sopenharmony_ci **/ 47462306a36Sopenharmony_cistatic void 47562306a36Sopenharmony_ciiavf_map_vector_to_txq(struct iavf_adapter *adapter, int v_idx, int t_idx) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct iavf_q_vector *q_vector = &adapter->q_vectors[v_idx]; 47862306a36Sopenharmony_ci struct iavf_ring *tx_ring = &adapter->tx_rings[t_idx]; 47962306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci tx_ring->q_vector = q_vector; 48262306a36Sopenharmony_ci tx_ring->next = q_vector->tx.ring; 48362306a36Sopenharmony_ci tx_ring->vsi = &adapter->vsi; 48462306a36Sopenharmony_ci q_vector->tx.ring = tx_ring; 48562306a36Sopenharmony_ci q_vector->tx.count++; 48662306a36Sopenharmony_ci q_vector->tx.next_update = jiffies + 1; 48762306a36Sopenharmony_ci q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting); 48862306a36Sopenharmony_ci q_vector->num_ringpairs++; 48962306a36Sopenharmony_ci wr32(hw, IAVF_VFINT_ITRN1(IAVF_TX_ITR, q_vector->reg_idx), 49062306a36Sopenharmony_ci q_vector->tx.target_itr >> 1); 49162306a36Sopenharmony_ci q_vector->tx.current_itr = q_vector->tx.target_itr; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci/** 49562306a36Sopenharmony_ci * iavf_map_rings_to_vectors - Maps descriptor rings to vectors 49662306a36Sopenharmony_ci * @adapter: board private structure to initialize 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * This function maps descriptor rings to the queue-specific vectors 49962306a36Sopenharmony_ci * we were allotted through the MSI-X enabling code. Ideally, we'd have 50062306a36Sopenharmony_ci * one vector per ring/queue, but on a constrained vector budget, we 50162306a36Sopenharmony_ci * group the rings as "efficiently" as possible. You would add new 50262306a36Sopenharmony_ci * mapping configurations in here. 50362306a36Sopenharmony_ci **/ 50462306a36Sopenharmony_cistatic void iavf_map_rings_to_vectors(struct iavf_adapter *adapter) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci int rings_remaining = adapter->num_active_queues; 50762306a36Sopenharmony_ci int ridx = 0, vidx = 0; 50862306a36Sopenharmony_ci int q_vectors; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci q_vectors = adapter->num_msix_vectors - NONQ_VECS; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci for (; ridx < rings_remaining; ridx++) { 51362306a36Sopenharmony_ci iavf_map_vector_to_rxq(adapter, vidx, ridx); 51462306a36Sopenharmony_ci iavf_map_vector_to_txq(adapter, vidx, ridx); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* In the case where we have more queues than vectors, continue 51762306a36Sopenharmony_ci * round-robin on vectors until all queues are mapped. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci if (++vidx >= q_vectors) 52062306a36Sopenharmony_ci vidx = 0; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/** 52762306a36Sopenharmony_ci * iavf_irq_affinity_notify - Callback for affinity changes 52862306a36Sopenharmony_ci * @notify: context as to what irq was changed 52962306a36Sopenharmony_ci * @mask: the new affinity mask 53062306a36Sopenharmony_ci * 53162306a36Sopenharmony_ci * This is a callback function used by the irq_set_affinity_notifier function 53262306a36Sopenharmony_ci * so that we may register to receive changes to the irq affinity masks. 53362306a36Sopenharmony_ci **/ 53462306a36Sopenharmony_cistatic void iavf_irq_affinity_notify(struct irq_affinity_notify *notify, 53562306a36Sopenharmony_ci const cpumask_t *mask) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci struct iavf_q_vector *q_vector = 53862306a36Sopenharmony_ci container_of(notify, struct iavf_q_vector, affinity_notify); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci cpumask_copy(&q_vector->affinity_mask, mask); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/** 54462306a36Sopenharmony_ci * iavf_irq_affinity_release - Callback for affinity notifier release 54562306a36Sopenharmony_ci * @ref: internal core kernel usage 54662306a36Sopenharmony_ci * 54762306a36Sopenharmony_ci * This is a callback function used by the irq_set_affinity_notifier function 54862306a36Sopenharmony_ci * to inform the current notification subscriber that they will no longer 54962306a36Sopenharmony_ci * receive notifications. 55062306a36Sopenharmony_ci **/ 55162306a36Sopenharmony_cistatic void iavf_irq_affinity_release(struct kref *ref) {} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/** 55462306a36Sopenharmony_ci * iavf_request_traffic_irqs - Initialize MSI-X interrupts 55562306a36Sopenharmony_ci * @adapter: board private structure 55662306a36Sopenharmony_ci * @basename: device basename 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci * Allocates MSI-X vectors for tx and rx handling, and requests 55962306a36Sopenharmony_ci * interrupts from the kernel. 56062306a36Sopenharmony_ci **/ 56162306a36Sopenharmony_cistatic int 56262306a36Sopenharmony_ciiavf_request_traffic_irqs(struct iavf_adapter *adapter, char *basename) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci unsigned int vector, q_vectors; 56562306a36Sopenharmony_ci unsigned int rx_int_idx = 0, tx_int_idx = 0; 56662306a36Sopenharmony_ci int irq_num, err; 56762306a36Sopenharmony_ci int cpu; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci iavf_irq_disable(adapter); 57062306a36Sopenharmony_ci /* Decrement for Other and TCP Timer vectors */ 57162306a36Sopenharmony_ci q_vectors = adapter->num_msix_vectors - NONQ_VECS; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci for (vector = 0; vector < q_vectors; vector++) { 57462306a36Sopenharmony_ci struct iavf_q_vector *q_vector = &adapter->q_vectors[vector]; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci irq_num = adapter->msix_entries[vector + NONQ_VECS].vector; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (q_vector->tx.ring && q_vector->rx.ring) { 57962306a36Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name), 58062306a36Sopenharmony_ci "iavf-%s-TxRx-%u", basename, rx_int_idx++); 58162306a36Sopenharmony_ci tx_int_idx++; 58262306a36Sopenharmony_ci } else if (q_vector->rx.ring) { 58362306a36Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name), 58462306a36Sopenharmony_ci "iavf-%s-rx-%u", basename, rx_int_idx++); 58562306a36Sopenharmony_ci } else if (q_vector->tx.ring) { 58662306a36Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name), 58762306a36Sopenharmony_ci "iavf-%s-tx-%u", basename, tx_int_idx++); 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci /* skip this unused q_vector */ 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci err = request_irq(irq_num, 59362306a36Sopenharmony_ci iavf_msix_clean_rings, 59462306a36Sopenharmony_ci 0, 59562306a36Sopenharmony_ci q_vector->name, 59662306a36Sopenharmony_ci q_vector); 59762306a36Sopenharmony_ci if (err) { 59862306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, 59962306a36Sopenharmony_ci "Request_irq failed, error: %d\n", err); 60062306a36Sopenharmony_ci goto free_queue_irqs; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci /* register for affinity change notifications */ 60362306a36Sopenharmony_ci q_vector->affinity_notify.notify = iavf_irq_affinity_notify; 60462306a36Sopenharmony_ci q_vector->affinity_notify.release = 60562306a36Sopenharmony_ci iavf_irq_affinity_release; 60662306a36Sopenharmony_ci irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify); 60762306a36Sopenharmony_ci /* Spread the IRQ affinity hints across online CPUs. Note that 60862306a36Sopenharmony_ci * get_cpu_mask returns a mask with a permanent lifetime so 60962306a36Sopenharmony_ci * it's safe to use as a hint for irq_update_affinity_hint. 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_ci cpu = cpumask_local_spread(q_vector->v_idx, -1); 61262306a36Sopenharmony_ci irq_update_affinity_hint(irq_num, get_cpu_mask(cpu)); 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cifree_queue_irqs: 61862306a36Sopenharmony_ci while (vector) { 61962306a36Sopenharmony_ci vector--; 62062306a36Sopenharmony_ci irq_num = adapter->msix_entries[vector + NONQ_VECS].vector; 62162306a36Sopenharmony_ci irq_set_affinity_notifier(irq_num, NULL); 62262306a36Sopenharmony_ci irq_update_affinity_hint(irq_num, NULL); 62362306a36Sopenharmony_ci free_irq(irq_num, &adapter->q_vectors[vector]); 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci return err; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/** 62962306a36Sopenharmony_ci * iavf_request_misc_irq - Initialize MSI-X interrupts 63062306a36Sopenharmony_ci * @adapter: board private structure 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * Allocates MSI-X vector 0 and requests interrupts from the kernel. This 63362306a36Sopenharmony_ci * vector is only for the admin queue, and stays active even when the netdev 63462306a36Sopenharmony_ci * is closed. 63562306a36Sopenharmony_ci **/ 63662306a36Sopenharmony_cistatic int iavf_request_misc_irq(struct iavf_adapter *adapter) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 63962306a36Sopenharmony_ci int err; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci snprintf(adapter->misc_vector_name, 64262306a36Sopenharmony_ci sizeof(adapter->misc_vector_name) - 1, "iavf-%s:mbx", 64362306a36Sopenharmony_ci dev_name(&adapter->pdev->dev)); 64462306a36Sopenharmony_ci err = request_irq(adapter->msix_entries[0].vector, 64562306a36Sopenharmony_ci &iavf_msix_aq, 0, 64662306a36Sopenharmony_ci adapter->misc_vector_name, netdev); 64762306a36Sopenharmony_ci if (err) { 64862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 64962306a36Sopenharmony_ci "request_irq for %s failed: %d\n", 65062306a36Sopenharmony_ci adapter->misc_vector_name, err); 65162306a36Sopenharmony_ci free_irq(adapter->msix_entries[0].vector, netdev); 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci return err; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci/** 65762306a36Sopenharmony_ci * iavf_free_traffic_irqs - Free MSI-X interrupts 65862306a36Sopenharmony_ci * @adapter: board private structure 65962306a36Sopenharmony_ci * 66062306a36Sopenharmony_ci * Frees all MSI-X vectors other than 0. 66162306a36Sopenharmony_ci **/ 66262306a36Sopenharmony_cistatic void iavf_free_traffic_irqs(struct iavf_adapter *adapter) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci int vector, irq_num, q_vectors; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (!adapter->msix_entries) 66762306a36Sopenharmony_ci return; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci q_vectors = adapter->num_msix_vectors - NONQ_VECS; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci for (vector = 0; vector < q_vectors; vector++) { 67262306a36Sopenharmony_ci irq_num = adapter->msix_entries[vector + NONQ_VECS].vector; 67362306a36Sopenharmony_ci irq_set_affinity_notifier(irq_num, NULL); 67462306a36Sopenharmony_ci irq_update_affinity_hint(irq_num, NULL); 67562306a36Sopenharmony_ci free_irq(irq_num, &adapter->q_vectors[vector]); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci/** 68062306a36Sopenharmony_ci * iavf_free_misc_irq - Free MSI-X miscellaneous vector 68162306a36Sopenharmony_ci * @adapter: board private structure 68262306a36Sopenharmony_ci * 68362306a36Sopenharmony_ci * Frees MSI-X vector 0. 68462306a36Sopenharmony_ci **/ 68562306a36Sopenharmony_cistatic void iavf_free_misc_irq(struct iavf_adapter *adapter) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (!adapter->msix_entries) 69062306a36Sopenharmony_ci return; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci free_irq(adapter->msix_entries[0].vector, netdev); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci/** 69662306a36Sopenharmony_ci * iavf_configure_tx - Configure Transmit Unit after Reset 69762306a36Sopenharmony_ci * @adapter: board private structure 69862306a36Sopenharmony_ci * 69962306a36Sopenharmony_ci * Configure the Tx unit of the MAC after a reset. 70062306a36Sopenharmony_ci **/ 70162306a36Sopenharmony_cistatic void iavf_configure_tx(struct iavf_adapter *adapter) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 70462306a36Sopenharmony_ci int i; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) 70762306a36Sopenharmony_ci adapter->tx_rings[i].tail = hw->hw_addr + IAVF_QTX_TAIL1(i); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci/** 71162306a36Sopenharmony_ci * iavf_configure_rx - Configure Receive Unit after Reset 71262306a36Sopenharmony_ci * @adapter: board private structure 71362306a36Sopenharmony_ci * 71462306a36Sopenharmony_ci * Configure the Rx unit of the MAC after a reset. 71562306a36Sopenharmony_ci **/ 71662306a36Sopenharmony_cistatic void iavf_configure_rx(struct iavf_adapter *adapter) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci unsigned int rx_buf_len = IAVF_RXBUFFER_2048; 71962306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 72062306a36Sopenharmony_ci int i; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* Legacy Rx will always default to a 2048 buffer size. */ 72362306a36Sopenharmony_ci#if (PAGE_SIZE < 8192) 72462306a36Sopenharmony_ci if (!(adapter->flags & IAVF_FLAG_LEGACY_RX)) { 72562306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* For jumbo frames on systems with 4K pages we have to use 72862306a36Sopenharmony_ci * an order 1 page, so we might as well increase the size 72962306a36Sopenharmony_ci * of our Rx buffer to make better use of the available space 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci rx_buf_len = IAVF_RXBUFFER_3072; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* We use a 1536 buffer size for configurations with 73462306a36Sopenharmony_ci * standard Ethernet mtu. On x86 this gives us enough room 73562306a36Sopenharmony_ci * for shared info and 192 bytes of padding. 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_ci if (!IAVF_2K_TOO_SMALL_WITH_PADDING && 73862306a36Sopenharmony_ci (netdev->mtu <= ETH_DATA_LEN)) 73962306a36Sopenharmony_ci rx_buf_len = IAVF_RXBUFFER_1536 - NET_IP_ALIGN; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci#endif 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) { 74462306a36Sopenharmony_ci adapter->rx_rings[i].tail = hw->hw_addr + IAVF_QRX_TAIL1(i); 74562306a36Sopenharmony_ci adapter->rx_rings[i].rx_buf_len = rx_buf_len; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_LEGACY_RX) 74862306a36Sopenharmony_ci clear_ring_build_skb_enabled(&adapter->rx_rings[i]); 74962306a36Sopenharmony_ci else 75062306a36Sopenharmony_ci set_ring_build_skb_enabled(&adapter->rx_rings[i]); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci/** 75562306a36Sopenharmony_ci * iavf_find_vlan - Search filter list for specific vlan filter 75662306a36Sopenharmony_ci * @adapter: board private structure 75762306a36Sopenharmony_ci * @vlan: vlan tag 75862306a36Sopenharmony_ci * 75962306a36Sopenharmony_ci * Returns ptr to the filter object or NULL. Must be called while holding the 76062306a36Sopenharmony_ci * mac_vlan_list_lock. 76162306a36Sopenharmony_ci **/ 76262306a36Sopenharmony_cistatic struct 76362306a36Sopenharmony_ciiavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter, 76462306a36Sopenharmony_ci struct iavf_vlan vlan) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct iavf_vlan_filter *f; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci list_for_each_entry(f, &adapter->vlan_filter_list, list) { 76962306a36Sopenharmony_ci if (f->vlan.vid == vlan.vid && 77062306a36Sopenharmony_ci f->vlan.tpid == vlan.tpid) 77162306a36Sopenharmony_ci return f; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return NULL; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci/** 77862306a36Sopenharmony_ci * iavf_add_vlan - Add a vlan filter to the list 77962306a36Sopenharmony_ci * @adapter: board private structure 78062306a36Sopenharmony_ci * @vlan: VLAN tag 78162306a36Sopenharmony_ci * 78262306a36Sopenharmony_ci * Returns ptr to the filter object or NULL when no memory available. 78362306a36Sopenharmony_ci **/ 78462306a36Sopenharmony_cistatic struct 78562306a36Sopenharmony_ciiavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, 78662306a36Sopenharmony_ci struct iavf_vlan vlan) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct iavf_vlan_filter *f = NULL; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci f = iavf_find_vlan(adapter, vlan); 79362306a36Sopenharmony_ci if (!f) { 79462306a36Sopenharmony_ci f = kzalloc(sizeof(*f), GFP_ATOMIC); 79562306a36Sopenharmony_ci if (!f) 79662306a36Sopenharmony_ci goto clearout; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci f->vlan = vlan; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci list_add_tail(&f->list, &adapter->vlan_filter_list); 80162306a36Sopenharmony_ci f->state = IAVF_VLAN_ADD; 80262306a36Sopenharmony_ci adapter->num_vlan_filters++; 80362306a36Sopenharmony_ci iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ciclearout: 80762306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 80862306a36Sopenharmony_ci return f; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci/** 81262306a36Sopenharmony_ci * iavf_del_vlan - Remove a vlan filter from the list 81362306a36Sopenharmony_ci * @adapter: board private structure 81462306a36Sopenharmony_ci * @vlan: VLAN tag 81562306a36Sopenharmony_ci **/ 81662306a36Sopenharmony_cistatic void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct iavf_vlan_filter *f; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci f = iavf_find_vlan(adapter, vlan); 82362306a36Sopenharmony_ci if (f) { 82462306a36Sopenharmony_ci f->state = IAVF_VLAN_REMOVE; 82562306a36Sopenharmony_ci iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_VLAN_FILTER); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci/** 83262306a36Sopenharmony_ci * iavf_restore_filters 83362306a36Sopenharmony_ci * @adapter: board private structure 83462306a36Sopenharmony_ci * 83562306a36Sopenharmony_ci * Restore existing non MAC filters when VF netdev comes back up 83662306a36Sopenharmony_ci **/ 83762306a36Sopenharmony_cistatic void iavf_restore_filters(struct iavf_adapter *adapter) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci struct iavf_vlan_filter *f; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* re-add all VLAN filters */ 84262306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci list_for_each_entry(f, &adapter->vlan_filter_list, list) { 84562306a36Sopenharmony_ci if (f->state == IAVF_VLAN_INACTIVE) 84662306a36Sopenharmony_ci f->state = IAVF_VLAN_ADD; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 85062306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci/** 85462306a36Sopenharmony_ci * iavf_get_num_vlans_added - get number of VLANs added 85562306a36Sopenharmony_ci * @adapter: board private structure 85662306a36Sopenharmony_ci */ 85762306a36Sopenharmony_ciu16 iavf_get_num_vlans_added(struct iavf_adapter *adapter) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci return adapter->num_vlan_filters; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci/** 86362306a36Sopenharmony_ci * iavf_get_max_vlans_allowed - get maximum VLANs allowed for this VF 86462306a36Sopenharmony_ci * @adapter: board private structure 86562306a36Sopenharmony_ci * 86662306a36Sopenharmony_ci * This depends on the negotiated VLAN capability. For VIRTCHNL_VF_OFFLOAD_VLAN, 86762306a36Sopenharmony_ci * do not impose a limit as that maintains current behavior and for 86862306a36Sopenharmony_ci * VIRTCHNL_VF_OFFLOAD_VLAN_V2, use the maximum allowed sent from the PF. 86962306a36Sopenharmony_ci **/ 87062306a36Sopenharmony_cistatic u16 iavf_get_max_vlans_allowed(struct iavf_adapter *adapter) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci /* don't impose any limit for VIRTCHNL_VF_OFFLOAD_VLAN since there has 87362306a36Sopenharmony_ci * never been a limit on the VF driver side 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_ci if (VLAN_ALLOWED(adapter)) 87662306a36Sopenharmony_ci return VLAN_N_VID; 87762306a36Sopenharmony_ci else if (VLAN_V2_ALLOWED(adapter)) 87862306a36Sopenharmony_ci return adapter->vlan_v2_caps.filtering.max_filters; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci return 0; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci/** 88462306a36Sopenharmony_ci * iavf_max_vlans_added - check if maximum VLANs allowed already exist 88562306a36Sopenharmony_ci * @adapter: board private structure 88662306a36Sopenharmony_ci **/ 88762306a36Sopenharmony_cistatic bool iavf_max_vlans_added(struct iavf_adapter *adapter) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci if (iavf_get_num_vlans_added(adapter) < 89062306a36Sopenharmony_ci iavf_get_max_vlans_allowed(adapter)) 89162306a36Sopenharmony_ci return false; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return true; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci/** 89762306a36Sopenharmony_ci * iavf_vlan_rx_add_vid - Add a VLAN filter to a device 89862306a36Sopenharmony_ci * @netdev: network device struct 89962306a36Sopenharmony_ci * @proto: unused protocol data 90062306a36Sopenharmony_ci * @vid: VLAN tag 90162306a36Sopenharmony_ci **/ 90262306a36Sopenharmony_cistatic int iavf_vlan_rx_add_vid(struct net_device *netdev, 90362306a36Sopenharmony_ci __always_unused __be16 proto, u16 vid) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* Do not track VLAN 0 filter, always added by the PF on VF init */ 90862306a36Sopenharmony_ci if (!vid) 90962306a36Sopenharmony_ci return 0; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (!VLAN_FILTERING_ALLOWED(adapter)) 91262306a36Sopenharmony_ci return -EIO; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (iavf_max_vlans_added(adapter)) { 91562306a36Sopenharmony_ci netdev_err(netdev, "Max allowed VLAN filters %u. Remove existing VLANs or disable filtering via Ethtool if supported.\n", 91662306a36Sopenharmony_ci iavf_get_max_vlans_allowed(adapter)); 91762306a36Sopenharmony_ci return -EIO; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (!iavf_add_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto)))) 92162306a36Sopenharmony_ci return -ENOMEM; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci return 0; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci/** 92762306a36Sopenharmony_ci * iavf_vlan_rx_kill_vid - Remove a VLAN filter from a device 92862306a36Sopenharmony_ci * @netdev: network device struct 92962306a36Sopenharmony_ci * @proto: unused protocol data 93062306a36Sopenharmony_ci * @vid: VLAN tag 93162306a36Sopenharmony_ci **/ 93262306a36Sopenharmony_cistatic int iavf_vlan_rx_kill_vid(struct net_device *netdev, 93362306a36Sopenharmony_ci __always_unused __be16 proto, u16 vid) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* We do not track VLAN 0 filter */ 93862306a36Sopenharmony_ci if (!vid) 93962306a36Sopenharmony_ci return 0; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci iavf_del_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto))); 94262306a36Sopenharmony_ci return 0; 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci/** 94662306a36Sopenharmony_ci * iavf_find_filter - Search filter list for specific mac filter 94762306a36Sopenharmony_ci * @adapter: board private structure 94862306a36Sopenharmony_ci * @macaddr: the MAC address 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * Returns ptr to the filter object or NULL. Must be called while holding the 95162306a36Sopenharmony_ci * mac_vlan_list_lock. 95262306a36Sopenharmony_ci **/ 95362306a36Sopenharmony_cistatic struct 95462306a36Sopenharmony_ciiavf_mac_filter *iavf_find_filter(struct iavf_adapter *adapter, 95562306a36Sopenharmony_ci const u8 *macaddr) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct iavf_mac_filter *f; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (!macaddr) 96062306a36Sopenharmony_ci return NULL; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci list_for_each_entry(f, &adapter->mac_filter_list, list) { 96362306a36Sopenharmony_ci if (ether_addr_equal(macaddr, f->macaddr)) 96462306a36Sopenharmony_ci return f; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci return NULL; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci/** 97062306a36Sopenharmony_ci * iavf_add_filter - Add a mac filter to the filter list 97162306a36Sopenharmony_ci * @adapter: board private structure 97262306a36Sopenharmony_ci * @macaddr: the MAC address 97362306a36Sopenharmony_ci * 97462306a36Sopenharmony_ci * Returns ptr to the filter object or NULL when no memory available. 97562306a36Sopenharmony_ci **/ 97662306a36Sopenharmony_cistruct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, 97762306a36Sopenharmony_ci const u8 *macaddr) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct iavf_mac_filter *f; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (!macaddr) 98262306a36Sopenharmony_ci return NULL; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci f = iavf_find_filter(adapter, macaddr); 98562306a36Sopenharmony_ci if (!f) { 98662306a36Sopenharmony_ci f = kzalloc(sizeof(*f), GFP_ATOMIC); 98762306a36Sopenharmony_ci if (!f) 98862306a36Sopenharmony_ci return f; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci ether_addr_copy(f->macaddr, macaddr); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci list_add_tail(&f->list, &adapter->mac_filter_list); 99362306a36Sopenharmony_ci f->add = true; 99462306a36Sopenharmony_ci f->add_handled = false; 99562306a36Sopenharmony_ci f->is_new_mac = true; 99662306a36Sopenharmony_ci f->is_primary = ether_addr_equal(macaddr, adapter->hw.mac.addr); 99762306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; 99862306a36Sopenharmony_ci } else { 99962306a36Sopenharmony_ci f->remove = false; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci return f; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci/** 100662306a36Sopenharmony_ci * iavf_replace_primary_mac - Replace current primary address 100762306a36Sopenharmony_ci * @adapter: board private structure 100862306a36Sopenharmony_ci * @new_mac: new MAC address to be applied 100962306a36Sopenharmony_ci * 101062306a36Sopenharmony_ci * Replace current dev_addr and send request to PF for removal of previous 101162306a36Sopenharmony_ci * primary MAC address filter and addition of new primary MAC filter. 101262306a36Sopenharmony_ci * Return 0 for success, -ENOMEM for failure. 101362306a36Sopenharmony_ci * 101462306a36Sopenharmony_ci * Do not call this with mac_vlan_list_lock! 101562306a36Sopenharmony_ci **/ 101662306a36Sopenharmony_cistatic int iavf_replace_primary_mac(struct iavf_adapter *adapter, 101762306a36Sopenharmony_ci const u8 *new_mac) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 102062306a36Sopenharmony_ci struct iavf_mac_filter *new_f; 102162306a36Sopenharmony_ci struct iavf_mac_filter *old_f; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci new_f = iavf_add_filter(adapter, new_mac); 102662306a36Sopenharmony_ci if (!new_f) { 102762306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 102862306a36Sopenharmony_ci return -ENOMEM; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci old_f = iavf_find_filter(adapter, hw->mac.addr); 103262306a36Sopenharmony_ci if (old_f) { 103362306a36Sopenharmony_ci old_f->is_primary = false; 103462306a36Sopenharmony_ci old_f->remove = true; 103562306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci /* Always send the request to add if changing primary MAC, 103862306a36Sopenharmony_ci * even if filter is already present on the list 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci new_f->is_primary = true; 104162306a36Sopenharmony_ci new_f->add = true; 104262306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; 104362306a36Sopenharmony_ci ether_addr_copy(hw->mac.addr, new_mac); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* schedule the watchdog task to immediately process the request */ 104862306a36Sopenharmony_ci mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci/** 105362306a36Sopenharmony_ci * iavf_is_mac_set_handled - wait for a response to set MAC from PF 105462306a36Sopenharmony_ci * @netdev: network interface device structure 105562306a36Sopenharmony_ci * @macaddr: MAC address to set 105662306a36Sopenharmony_ci * 105762306a36Sopenharmony_ci * Returns true on success, false on failure 105862306a36Sopenharmony_ci */ 105962306a36Sopenharmony_cistatic bool iavf_is_mac_set_handled(struct net_device *netdev, 106062306a36Sopenharmony_ci const u8 *macaddr) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 106362306a36Sopenharmony_ci struct iavf_mac_filter *f; 106462306a36Sopenharmony_ci bool ret = false; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci f = iavf_find_filter(adapter, macaddr); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (!f || (!f->add && f->add_handled)) 107162306a36Sopenharmony_ci ret = true; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return ret; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/** 107962306a36Sopenharmony_ci * iavf_set_mac - NDO callback to set port MAC address 108062306a36Sopenharmony_ci * @netdev: network interface device structure 108162306a36Sopenharmony_ci * @p: pointer to an address structure 108262306a36Sopenharmony_ci * 108362306a36Sopenharmony_ci * Returns 0 on success, negative on failure 108462306a36Sopenharmony_ci */ 108562306a36Sopenharmony_cistatic int iavf_set_mac(struct net_device *netdev, void *p) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 108862306a36Sopenharmony_ci struct sockaddr *addr = p; 108962306a36Sopenharmony_ci int ret; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 109262306a36Sopenharmony_ci return -EADDRNOTAVAIL; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci ret = iavf_replace_primary_mac(adapter, addr->sa_data); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (ret) 109762306a36Sopenharmony_ci return ret; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci ret = wait_event_interruptible_timeout(adapter->vc_waitqueue, 110062306a36Sopenharmony_ci iavf_is_mac_set_handled(netdev, addr->sa_data), 110162306a36Sopenharmony_ci msecs_to_jiffies(2500)); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* If ret < 0 then it means wait was interrupted. 110462306a36Sopenharmony_ci * If ret == 0 then it means we got a timeout. 110562306a36Sopenharmony_ci * else it means we got response for set MAC from PF, 110662306a36Sopenharmony_ci * check if netdev MAC was updated to requested MAC, 110762306a36Sopenharmony_ci * if yes then set MAC succeeded otherwise it failed return -EACCES 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci if (ret < 0) 111062306a36Sopenharmony_ci return ret; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci if (!ret) 111362306a36Sopenharmony_ci return -EAGAIN; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (!ether_addr_equal(netdev->dev_addr, addr->sa_data)) 111662306a36Sopenharmony_ci return -EACCES; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci/** 112262306a36Sopenharmony_ci * iavf_addr_sync - Callback for dev_(mc|uc)_sync to add address 112362306a36Sopenharmony_ci * @netdev: the netdevice 112462306a36Sopenharmony_ci * @addr: address to add 112562306a36Sopenharmony_ci * 112662306a36Sopenharmony_ci * Called by __dev_(mc|uc)_sync when an address needs to be added. We call 112762306a36Sopenharmony_ci * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock. 112862306a36Sopenharmony_ci */ 112962306a36Sopenharmony_cistatic int iavf_addr_sync(struct net_device *netdev, const u8 *addr) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci if (iavf_add_filter(adapter, addr)) 113462306a36Sopenharmony_ci return 0; 113562306a36Sopenharmony_ci else 113662306a36Sopenharmony_ci return -ENOMEM; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci/** 114062306a36Sopenharmony_ci * iavf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address 114162306a36Sopenharmony_ci * @netdev: the netdevice 114262306a36Sopenharmony_ci * @addr: address to add 114362306a36Sopenharmony_ci * 114462306a36Sopenharmony_ci * Called by __dev_(mc|uc)_sync when an address needs to be removed. We call 114562306a36Sopenharmony_ci * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock. 114662306a36Sopenharmony_ci */ 114762306a36Sopenharmony_cistatic int iavf_addr_unsync(struct net_device *netdev, const u8 *addr) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 115062306a36Sopenharmony_ci struct iavf_mac_filter *f; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci /* Under some circumstances, we might receive a request to delete 115362306a36Sopenharmony_ci * our own device address from our uc list. Because we store the 115462306a36Sopenharmony_ci * device address in the VSI's MAC/VLAN filter list, we need to ignore 115562306a36Sopenharmony_ci * such requests and not delete our device address from this list. 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_ci if (ether_addr_equal(addr, netdev->dev_addr)) 115862306a36Sopenharmony_ci return 0; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci f = iavf_find_filter(adapter, addr); 116162306a36Sopenharmony_ci if (f) { 116262306a36Sopenharmony_ci f->remove = true; 116362306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci return 0; 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci/** 116962306a36Sopenharmony_ci * iavf_promiscuous_mode_changed - check if promiscuous mode bits changed 117062306a36Sopenharmony_ci * @adapter: device specific adapter 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_cibool iavf_promiscuous_mode_changed(struct iavf_adapter *adapter) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci return (adapter->current_netdev_promisc_flags ^ adapter->netdev->flags) & 117562306a36Sopenharmony_ci (IFF_PROMISC | IFF_ALLMULTI); 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci/** 117962306a36Sopenharmony_ci * iavf_set_rx_mode - NDO callback to set the netdev filters 118062306a36Sopenharmony_ci * @netdev: network interface device structure 118162306a36Sopenharmony_ci **/ 118262306a36Sopenharmony_cistatic void iavf_set_rx_mode(struct net_device *netdev) 118362306a36Sopenharmony_ci{ 118462306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 118762306a36Sopenharmony_ci __dev_uc_sync(netdev, iavf_addr_sync, iavf_addr_unsync); 118862306a36Sopenharmony_ci __dev_mc_sync(netdev, iavf_addr_sync, iavf_addr_unsync); 118962306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci spin_lock_bh(&adapter->current_netdev_promisc_flags_lock); 119262306a36Sopenharmony_ci if (iavf_promiscuous_mode_changed(adapter)) 119362306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_PROMISC_MODE; 119462306a36Sopenharmony_ci spin_unlock_bh(&adapter->current_netdev_promisc_flags_lock); 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci/** 119862306a36Sopenharmony_ci * iavf_napi_enable_all - enable NAPI on all queue vectors 119962306a36Sopenharmony_ci * @adapter: board private structure 120062306a36Sopenharmony_ci **/ 120162306a36Sopenharmony_cistatic void iavf_napi_enable_all(struct iavf_adapter *adapter) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci int q_idx; 120462306a36Sopenharmony_ci struct iavf_q_vector *q_vector; 120562306a36Sopenharmony_ci int q_vectors = adapter->num_msix_vectors - NONQ_VECS; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci for (q_idx = 0; q_idx < q_vectors; q_idx++) { 120862306a36Sopenharmony_ci struct napi_struct *napi; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci q_vector = &adapter->q_vectors[q_idx]; 121162306a36Sopenharmony_ci napi = &q_vector->napi; 121262306a36Sopenharmony_ci napi_enable(napi); 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci/** 121762306a36Sopenharmony_ci * iavf_napi_disable_all - disable NAPI on all queue vectors 121862306a36Sopenharmony_ci * @adapter: board private structure 121962306a36Sopenharmony_ci **/ 122062306a36Sopenharmony_cistatic void iavf_napi_disable_all(struct iavf_adapter *adapter) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci int q_idx; 122362306a36Sopenharmony_ci struct iavf_q_vector *q_vector; 122462306a36Sopenharmony_ci int q_vectors = adapter->num_msix_vectors - NONQ_VECS; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci for (q_idx = 0; q_idx < q_vectors; q_idx++) { 122762306a36Sopenharmony_ci q_vector = &adapter->q_vectors[q_idx]; 122862306a36Sopenharmony_ci napi_disable(&q_vector->napi); 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci/** 123362306a36Sopenharmony_ci * iavf_configure - set up transmit and receive data structures 123462306a36Sopenharmony_ci * @adapter: board private structure 123562306a36Sopenharmony_ci **/ 123662306a36Sopenharmony_cistatic void iavf_configure(struct iavf_adapter *adapter) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 123962306a36Sopenharmony_ci int i; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci iavf_set_rx_mode(netdev); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci iavf_configure_tx(adapter); 124462306a36Sopenharmony_ci iavf_configure_rx(adapter); 124562306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) { 124862306a36Sopenharmony_ci struct iavf_ring *ring = &adapter->rx_rings[i]; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci iavf_alloc_rx_buffers(ring, IAVF_DESC_UNUSED(ring)); 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci/** 125562306a36Sopenharmony_ci * iavf_up_complete - Finish the last steps of bringing up a connection 125662306a36Sopenharmony_ci * @adapter: board private structure 125762306a36Sopenharmony_ci * 125862306a36Sopenharmony_ci * Expects to be called while holding the __IAVF_IN_CRITICAL_TASK bit lock. 125962306a36Sopenharmony_ci **/ 126062306a36Sopenharmony_cistatic void iavf_up_complete(struct iavf_adapter *adapter) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_RUNNING); 126362306a36Sopenharmony_ci clear_bit(__IAVF_VSI_DOWN, adapter->vsi.state); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci iavf_napi_enable_all(adapter); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES; 126862306a36Sopenharmony_ci if (CLIENT_ENABLED(adapter)) 126962306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_OPEN; 127062306a36Sopenharmony_ci mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci/** 127462306a36Sopenharmony_ci * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF 127562306a36Sopenharmony_ci * yet and mark other to be removed. 127662306a36Sopenharmony_ci * @adapter: board private structure 127762306a36Sopenharmony_ci **/ 127862306a36Sopenharmony_cistatic void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci struct iavf_vlan_filter *vlf, *vlftmp; 128162306a36Sopenharmony_ci struct iavf_mac_filter *f, *ftmp; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 128462306a36Sopenharmony_ci /* clear the sync flag on all filters */ 128562306a36Sopenharmony_ci __dev_uc_unsync(adapter->netdev, NULL); 128662306a36Sopenharmony_ci __dev_mc_unsync(adapter->netdev, NULL); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci /* remove all MAC filters */ 128962306a36Sopenharmony_ci list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, 129062306a36Sopenharmony_ci list) { 129162306a36Sopenharmony_ci if (f->add) { 129262306a36Sopenharmony_ci list_del(&f->list); 129362306a36Sopenharmony_ci kfree(f); 129462306a36Sopenharmony_ci } else { 129562306a36Sopenharmony_ci f->remove = true; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* disable all VLAN filters */ 130062306a36Sopenharmony_ci list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, 130162306a36Sopenharmony_ci list) 130262306a36Sopenharmony_ci vlf->state = IAVF_VLAN_DISABLE; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci/** 130862306a36Sopenharmony_ci * iavf_clear_cloud_filters - Remove cloud filters not sent to PF yet and 130962306a36Sopenharmony_ci * mark other to be removed. 131062306a36Sopenharmony_ci * @adapter: board private structure 131162306a36Sopenharmony_ci **/ 131262306a36Sopenharmony_cistatic void iavf_clear_cloud_filters(struct iavf_adapter *adapter) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci struct iavf_cloud_filter *cf, *cftmp; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci /* remove all cloud filters */ 131762306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 131862306a36Sopenharmony_ci list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, 131962306a36Sopenharmony_ci list) { 132062306a36Sopenharmony_ci if (cf->add) { 132162306a36Sopenharmony_ci list_del(&cf->list); 132262306a36Sopenharmony_ci kfree(cf); 132362306a36Sopenharmony_ci adapter->num_cloud_filters--; 132462306a36Sopenharmony_ci } else { 132562306a36Sopenharmony_ci cf->del = true; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci/** 133262306a36Sopenharmony_ci * iavf_clear_fdir_filters - Remove fdir filters not sent to PF yet and mark 133362306a36Sopenharmony_ci * other to be removed. 133462306a36Sopenharmony_ci * @adapter: board private structure 133562306a36Sopenharmony_ci **/ 133662306a36Sopenharmony_cistatic void iavf_clear_fdir_filters(struct iavf_adapter *adapter) 133762306a36Sopenharmony_ci{ 133862306a36Sopenharmony_ci struct iavf_fdir_fltr *fdir; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* remove all Flow Director filters */ 134162306a36Sopenharmony_ci spin_lock_bh(&adapter->fdir_fltr_lock); 134262306a36Sopenharmony_ci list_for_each_entry(fdir, &adapter->fdir_list_head, list) { 134362306a36Sopenharmony_ci if (fdir->state == IAVF_FDIR_FLTR_ADD_REQUEST) { 134462306a36Sopenharmony_ci /* Cancel a request, keep filter as inactive */ 134562306a36Sopenharmony_ci fdir->state = IAVF_FDIR_FLTR_INACTIVE; 134662306a36Sopenharmony_ci } else if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING || 134762306a36Sopenharmony_ci fdir->state == IAVF_FDIR_FLTR_ACTIVE) { 134862306a36Sopenharmony_ci /* Disable filters which are active or have a pending 134962306a36Sopenharmony_ci * request to PF to be added 135062306a36Sopenharmony_ci */ 135162306a36Sopenharmony_ci fdir->state = IAVF_FDIR_FLTR_DIS_REQUEST; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci spin_unlock_bh(&adapter->fdir_fltr_lock); 135562306a36Sopenharmony_ci} 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci/** 135862306a36Sopenharmony_ci * iavf_clear_adv_rss_conf - Remove adv rss conf not sent to PF yet and mark 135962306a36Sopenharmony_ci * other to be removed. 136062306a36Sopenharmony_ci * @adapter: board private structure 136162306a36Sopenharmony_ci **/ 136262306a36Sopenharmony_cistatic void iavf_clear_adv_rss_conf(struct iavf_adapter *adapter) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci struct iavf_adv_rss *rss, *rsstmp; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* remove all advance RSS configuration */ 136762306a36Sopenharmony_ci spin_lock_bh(&adapter->adv_rss_lock); 136862306a36Sopenharmony_ci list_for_each_entry_safe(rss, rsstmp, &adapter->adv_rss_list_head, 136962306a36Sopenharmony_ci list) { 137062306a36Sopenharmony_ci if (rss->state == IAVF_ADV_RSS_ADD_REQUEST) { 137162306a36Sopenharmony_ci list_del(&rss->list); 137262306a36Sopenharmony_ci kfree(rss); 137362306a36Sopenharmony_ci } else { 137462306a36Sopenharmony_ci rss->state = IAVF_ADV_RSS_DEL_REQUEST; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci spin_unlock_bh(&adapter->adv_rss_lock); 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci/** 138162306a36Sopenharmony_ci * iavf_down - Shutdown the connection processing 138262306a36Sopenharmony_ci * @adapter: board private structure 138362306a36Sopenharmony_ci * 138462306a36Sopenharmony_ci * Expects to be called while holding the __IAVF_IN_CRITICAL_TASK bit lock. 138562306a36Sopenharmony_ci **/ 138662306a36Sopenharmony_civoid iavf_down(struct iavf_adapter *adapter) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (adapter->state <= __IAVF_DOWN_PENDING) 139162306a36Sopenharmony_ci return; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci netif_carrier_off(netdev); 139462306a36Sopenharmony_ci netif_tx_disable(netdev); 139562306a36Sopenharmony_ci adapter->link_up = false; 139662306a36Sopenharmony_ci iavf_napi_disable_all(adapter); 139762306a36Sopenharmony_ci iavf_irq_disable(adapter); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci iavf_clear_mac_vlan_filters(adapter); 140062306a36Sopenharmony_ci iavf_clear_cloud_filters(adapter); 140162306a36Sopenharmony_ci iavf_clear_fdir_filters(adapter); 140262306a36Sopenharmony_ci iavf_clear_adv_rss_conf(adapter); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) && 140562306a36Sopenharmony_ci !(test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))) { 140662306a36Sopenharmony_ci /* cancel any current operation */ 140762306a36Sopenharmony_ci adapter->current_op = VIRTCHNL_OP_UNKNOWN; 140862306a36Sopenharmony_ci /* Schedule operations to close down the HW. Don't wait 140962306a36Sopenharmony_ci * here for this to complete. The watchdog is still running 141062306a36Sopenharmony_ci * and it will take care of this. 141162306a36Sopenharmony_ci */ 141262306a36Sopenharmony_ci if (!list_empty(&adapter->mac_filter_list)) 141362306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; 141462306a36Sopenharmony_ci if (!list_empty(&adapter->vlan_filter_list)) 141562306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; 141662306a36Sopenharmony_ci if (!list_empty(&adapter->cloud_filter_list)) 141762306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; 141862306a36Sopenharmony_ci if (!list_empty(&adapter->fdir_list_head)) 141962306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER; 142062306a36Sopenharmony_ci if (!list_empty(&adapter->adv_rss_list_head)) 142162306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_ADV_RSS_CFG; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES; 142562306a36Sopenharmony_ci mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci/** 142962306a36Sopenharmony_ci * iavf_acquire_msix_vectors - Setup the MSIX capability 143062306a36Sopenharmony_ci * @adapter: board private structure 143162306a36Sopenharmony_ci * @vectors: number of vectors to request 143262306a36Sopenharmony_ci * 143362306a36Sopenharmony_ci * Work with the OS to set up the MSIX vectors needed. 143462306a36Sopenharmony_ci * 143562306a36Sopenharmony_ci * Returns 0 on success, negative on failure 143662306a36Sopenharmony_ci **/ 143762306a36Sopenharmony_cistatic int 143862306a36Sopenharmony_ciiavf_acquire_msix_vectors(struct iavf_adapter *adapter, int vectors) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci int err, vector_threshold; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* We'll want at least 3 (vector_threshold): 144362306a36Sopenharmony_ci * 0) Other (Admin Queue and link, mostly) 144462306a36Sopenharmony_ci * 1) TxQ[0] Cleanup 144562306a36Sopenharmony_ci * 2) RxQ[0] Cleanup 144662306a36Sopenharmony_ci */ 144762306a36Sopenharmony_ci vector_threshold = MIN_MSIX_COUNT; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* The more we get, the more we will assign to Tx/Rx Cleanup 145062306a36Sopenharmony_ci * for the separate queues...where Rx Cleanup >= Tx Cleanup. 145162306a36Sopenharmony_ci * Right now, we simply care about how many we'll get; we'll 145262306a36Sopenharmony_ci * set them up later while requesting irq's. 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_ci err = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, 145562306a36Sopenharmony_ci vector_threshold, vectors); 145662306a36Sopenharmony_ci if (err < 0) { 145762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Unable to allocate MSI-X interrupts\n"); 145862306a36Sopenharmony_ci kfree(adapter->msix_entries); 145962306a36Sopenharmony_ci adapter->msix_entries = NULL; 146062306a36Sopenharmony_ci return err; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* Adjust for only the vectors we'll use, which is minimum 146462306a36Sopenharmony_ci * of max_msix_q_vectors + NONQ_VECS, or the number of 146562306a36Sopenharmony_ci * vectors we were allocated. 146662306a36Sopenharmony_ci */ 146762306a36Sopenharmony_ci adapter->num_msix_vectors = err; 146862306a36Sopenharmony_ci return 0; 146962306a36Sopenharmony_ci} 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci/** 147262306a36Sopenharmony_ci * iavf_free_queues - Free memory for all rings 147362306a36Sopenharmony_ci * @adapter: board private structure to initialize 147462306a36Sopenharmony_ci * 147562306a36Sopenharmony_ci * Free all of the memory associated with queue pairs. 147662306a36Sopenharmony_ci **/ 147762306a36Sopenharmony_cistatic void iavf_free_queues(struct iavf_adapter *adapter) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci if (!adapter->vsi_res) 148062306a36Sopenharmony_ci return; 148162306a36Sopenharmony_ci adapter->num_active_queues = 0; 148262306a36Sopenharmony_ci kfree(adapter->tx_rings); 148362306a36Sopenharmony_ci adapter->tx_rings = NULL; 148462306a36Sopenharmony_ci kfree(adapter->rx_rings); 148562306a36Sopenharmony_ci adapter->rx_rings = NULL; 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci/** 148962306a36Sopenharmony_ci * iavf_set_queue_vlan_tag_loc - set location for VLAN tag offload 149062306a36Sopenharmony_ci * @adapter: board private structure 149162306a36Sopenharmony_ci * 149262306a36Sopenharmony_ci * Based on negotiated capabilities, the VLAN tag needs to be inserted and/or 149362306a36Sopenharmony_ci * stripped in certain descriptor fields. Instead of checking the offload 149462306a36Sopenharmony_ci * capability bits in the hot path, cache the location the ring specific 149562306a36Sopenharmony_ci * flags. 149662306a36Sopenharmony_ci */ 149762306a36Sopenharmony_civoid iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci int i; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) { 150262306a36Sopenharmony_ci struct iavf_ring *tx_ring = &adapter->tx_rings[i]; 150362306a36Sopenharmony_ci struct iavf_ring *rx_ring = &adapter->rx_rings[i]; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci /* prevent multiple L2TAG bits being set after VFR */ 150662306a36Sopenharmony_ci tx_ring->flags &= 150762306a36Sopenharmony_ci ~(IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 | 150862306a36Sopenharmony_ci IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2); 150962306a36Sopenharmony_ci rx_ring->flags &= 151062306a36Sopenharmony_ci ~(IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 | 151162306a36Sopenharmony_ci IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if (VLAN_ALLOWED(adapter)) { 151462306a36Sopenharmony_ci tx_ring->flags |= IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1; 151562306a36Sopenharmony_ci rx_ring->flags |= IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1; 151662306a36Sopenharmony_ci } else if (VLAN_V2_ALLOWED(adapter)) { 151762306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *stripping_support; 151862306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *insertion_support; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci stripping_support = 152162306a36Sopenharmony_ci &adapter->vlan_v2_caps.offloads.stripping_support; 152262306a36Sopenharmony_ci insertion_support = 152362306a36Sopenharmony_ci &adapter->vlan_v2_caps.offloads.insertion_support; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci if (stripping_support->outer) { 152662306a36Sopenharmony_ci if (stripping_support->outer & 152762306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1) 152862306a36Sopenharmony_ci rx_ring->flags |= 152962306a36Sopenharmony_ci IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1; 153062306a36Sopenharmony_ci else if (stripping_support->outer & 153162306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2) 153262306a36Sopenharmony_ci rx_ring->flags |= 153362306a36Sopenharmony_ci IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2; 153462306a36Sopenharmony_ci } else if (stripping_support->inner) { 153562306a36Sopenharmony_ci if (stripping_support->inner & 153662306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1) 153762306a36Sopenharmony_ci rx_ring->flags |= 153862306a36Sopenharmony_ci IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1; 153962306a36Sopenharmony_ci else if (stripping_support->inner & 154062306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2) 154162306a36Sopenharmony_ci rx_ring->flags |= 154262306a36Sopenharmony_ci IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (insertion_support->outer) { 154662306a36Sopenharmony_ci if (insertion_support->outer & 154762306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1) 154862306a36Sopenharmony_ci tx_ring->flags |= 154962306a36Sopenharmony_ci IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1; 155062306a36Sopenharmony_ci else if (insertion_support->outer & 155162306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2) 155262306a36Sopenharmony_ci tx_ring->flags |= 155362306a36Sopenharmony_ci IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2; 155462306a36Sopenharmony_ci } else if (insertion_support->inner) { 155562306a36Sopenharmony_ci if (insertion_support->inner & 155662306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1) 155762306a36Sopenharmony_ci tx_ring->flags |= 155862306a36Sopenharmony_ci IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1; 155962306a36Sopenharmony_ci else if (insertion_support->inner & 156062306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2) 156162306a36Sopenharmony_ci tx_ring->flags |= 156262306a36Sopenharmony_ci IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci} 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci/** 156962306a36Sopenharmony_ci * iavf_alloc_queues - Allocate memory for all rings 157062306a36Sopenharmony_ci * @adapter: board private structure to initialize 157162306a36Sopenharmony_ci * 157262306a36Sopenharmony_ci * We allocate one ring per queue at run-time since we don't know the 157362306a36Sopenharmony_ci * number of queues at compile-time. The polling_netdev array is 157462306a36Sopenharmony_ci * intended for Multiqueue, but should work fine with a single queue. 157562306a36Sopenharmony_ci **/ 157662306a36Sopenharmony_cistatic int iavf_alloc_queues(struct iavf_adapter *adapter) 157762306a36Sopenharmony_ci{ 157862306a36Sopenharmony_ci int i, num_active_queues; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* If we're in reset reallocating queues we don't actually know yet for 158162306a36Sopenharmony_ci * certain the PF gave us the number of queues we asked for but we'll 158262306a36Sopenharmony_ci * assume it did. Once basic reset is finished we'll confirm once we 158362306a36Sopenharmony_ci * start negotiating config with PF. 158462306a36Sopenharmony_ci */ 158562306a36Sopenharmony_ci if (adapter->num_req_queues) 158662306a36Sopenharmony_ci num_active_queues = adapter->num_req_queues; 158762306a36Sopenharmony_ci else if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) && 158862306a36Sopenharmony_ci adapter->num_tc) 158962306a36Sopenharmony_ci num_active_queues = adapter->ch_config.total_qps; 159062306a36Sopenharmony_ci else 159162306a36Sopenharmony_ci num_active_queues = min_t(int, 159262306a36Sopenharmony_ci adapter->vsi_res->num_queue_pairs, 159362306a36Sopenharmony_ci (int)(num_online_cpus())); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci adapter->tx_rings = kcalloc(num_active_queues, 159762306a36Sopenharmony_ci sizeof(struct iavf_ring), GFP_KERNEL); 159862306a36Sopenharmony_ci if (!adapter->tx_rings) 159962306a36Sopenharmony_ci goto err_out; 160062306a36Sopenharmony_ci adapter->rx_rings = kcalloc(num_active_queues, 160162306a36Sopenharmony_ci sizeof(struct iavf_ring), GFP_KERNEL); 160262306a36Sopenharmony_ci if (!adapter->rx_rings) 160362306a36Sopenharmony_ci goto err_out; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci for (i = 0; i < num_active_queues; i++) { 160662306a36Sopenharmony_ci struct iavf_ring *tx_ring; 160762306a36Sopenharmony_ci struct iavf_ring *rx_ring; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci tx_ring = &adapter->tx_rings[i]; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci tx_ring->queue_index = i; 161262306a36Sopenharmony_ci tx_ring->netdev = adapter->netdev; 161362306a36Sopenharmony_ci tx_ring->dev = &adapter->pdev->dev; 161462306a36Sopenharmony_ci tx_ring->count = adapter->tx_desc_count; 161562306a36Sopenharmony_ci tx_ring->itr_setting = IAVF_ITR_TX_DEF; 161662306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_WB_ON_ITR_CAPABLE) 161762306a36Sopenharmony_ci tx_ring->flags |= IAVF_TXR_FLAGS_WB_ON_ITR; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci rx_ring = &adapter->rx_rings[i]; 162062306a36Sopenharmony_ci rx_ring->queue_index = i; 162162306a36Sopenharmony_ci rx_ring->netdev = adapter->netdev; 162262306a36Sopenharmony_ci rx_ring->dev = &adapter->pdev->dev; 162362306a36Sopenharmony_ci rx_ring->count = adapter->rx_desc_count; 162462306a36Sopenharmony_ci rx_ring->itr_setting = IAVF_ITR_RX_DEF; 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci adapter->num_active_queues = num_active_queues; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci iavf_set_queue_vlan_tag_loc(adapter); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci return 0; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_cierr_out: 163462306a36Sopenharmony_ci iavf_free_queues(adapter); 163562306a36Sopenharmony_ci return -ENOMEM; 163662306a36Sopenharmony_ci} 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci/** 163962306a36Sopenharmony_ci * iavf_set_interrupt_capability - set MSI-X or FAIL if not supported 164062306a36Sopenharmony_ci * @adapter: board private structure to initialize 164162306a36Sopenharmony_ci * 164262306a36Sopenharmony_ci * Attempt to configure the interrupts using the best available 164362306a36Sopenharmony_ci * capabilities of the hardware and the kernel. 164462306a36Sopenharmony_ci **/ 164562306a36Sopenharmony_cistatic int iavf_set_interrupt_capability(struct iavf_adapter *adapter) 164662306a36Sopenharmony_ci{ 164762306a36Sopenharmony_ci int vector, v_budget; 164862306a36Sopenharmony_ci int pairs = 0; 164962306a36Sopenharmony_ci int err = 0; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (!adapter->vsi_res) { 165262306a36Sopenharmony_ci err = -EIO; 165362306a36Sopenharmony_ci goto out; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci pairs = adapter->num_active_queues; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci /* It's easy to be greedy for MSI-X vectors, but it really doesn't do 165862306a36Sopenharmony_ci * us much good if we have more vectors than CPUs. However, we already 165962306a36Sopenharmony_ci * limit the total number of queues by the number of CPUs so we do not 166062306a36Sopenharmony_ci * need any further limiting here. 166162306a36Sopenharmony_ci */ 166262306a36Sopenharmony_ci v_budget = min_t(int, pairs + NONQ_VECS, 166362306a36Sopenharmony_ci (int)adapter->vf_res->max_vectors); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci adapter->msix_entries = kcalloc(v_budget, 166662306a36Sopenharmony_ci sizeof(struct msix_entry), GFP_KERNEL); 166762306a36Sopenharmony_ci if (!adapter->msix_entries) { 166862306a36Sopenharmony_ci err = -ENOMEM; 166962306a36Sopenharmony_ci goto out; 167062306a36Sopenharmony_ci } 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci for (vector = 0; vector < v_budget; vector++) 167362306a36Sopenharmony_ci adapter->msix_entries[vector].entry = vector; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci err = iavf_acquire_msix_vectors(adapter, v_budget); 167662306a36Sopenharmony_ci if (!err) 167762306a36Sopenharmony_ci iavf_schedule_finish_config(adapter); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ciout: 168062306a36Sopenharmony_ci return err; 168162306a36Sopenharmony_ci} 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci/** 168462306a36Sopenharmony_ci * iavf_config_rss_aq - Configure RSS keys and lut by using AQ commands 168562306a36Sopenharmony_ci * @adapter: board private structure 168662306a36Sopenharmony_ci * 168762306a36Sopenharmony_ci * Return 0 on success, negative on failure 168862306a36Sopenharmony_ci **/ 168962306a36Sopenharmony_cistatic int iavf_config_rss_aq(struct iavf_adapter *adapter) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci struct iavf_aqc_get_set_rss_key_data *rss_key = 169262306a36Sopenharmony_ci (struct iavf_aqc_get_set_rss_key_data *)adapter->rss_key; 169362306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 169462306a36Sopenharmony_ci enum iavf_status status; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { 169762306a36Sopenharmony_ci /* bail because we already have a command pending */ 169862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Cannot configure RSS, command %d pending\n", 169962306a36Sopenharmony_ci adapter->current_op); 170062306a36Sopenharmony_ci return -EBUSY; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci status = iavf_aq_set_rss_key(hw, adapter->vsi.id, rss_key); 170462306a36Sopenharmony_ci if (status) { 170562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Cannot set RSS key, err %s aq_err %s\n", 170662306a36Sopenharmony_ci iavf_stat_str(hw, status), 170762306a36Sopenharmony_ci iavf_aq_str(hw, hw->aq.asq_last_status)); 170862306a36Sopenharmony_ci return iavf_status_to_errno(status); 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci status = iavf_aq_set_rss_lut(hw, adapter->vsi.id, false, 171362306a36Sopenharmony_ci adapter->rss_lut, adapter->rss_lut_size); 171462306a36Sopenharmony_ci if (status) { 171562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Cannot set RSS lut, err %s aq_err %s\n", 171662306a36Sopenharmony_ci iavf_stat_str(hw, status), 171762306a36Sopenharmony_ci iavf_aq_str(hw, hw->aq.asq_last_status)); 171862306a36Sopenharmony_ci return iavf_status_to_errno(status); 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci return 0; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci} 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci/** 172662306a36Sopenharmony_ci * iavf_config_rss_reg - Configure RSS keys and lut by writing registers 172762306a36Sopenharmony_ci * @adapter: board private structure 172862306a36Sopenharmony_ci * 172962306a36Sopenharmony_ci * Returns 0 on success, negative on failure 173062306a36Sopenharmony_ci **/ 173162306a36Sopenharmony_cistatic int iavf_config_rss_reg(struct iavf_adapter *adapter) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 173462306a36Sopenharmony_ci u32 *dw; 173562306a36Sopenharmony_ci u16 i; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci dw = (u32 *)adapter->rss_key; 173862306a36Sopenharmony_ci for (i = 0; i <= adapter->rss_key_size / 4; i++) 173962306a36Sopenharmony_ci wr32(hw, IAVF_VFQF_HKEY(i), dw[i]); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci dw = (u32 *)adapter->rss_lut; 174262306a36Sopenharmony_ci for (i = 0; i <= adapter->rss_lut_size / 4; i++) 174362306a36Sopenharmony_ci wr32(hw, IAVF_VFQF_HLUT(i), dw[i]); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci iavf_flush(hw); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci return 0; 174862306a36Sopenharmony_ci} 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci/** 175162306a36Sopenharmony_ci * iavf_config_rss - Configure RSS keys and lut 175262306a36Sopenharmony_ci * @adapter: board private structure 175362306a36Sopenharmony_ci * 175462306a36Sopenharmony_ci * Returns 0 on success, negative on failure 175562306a36Sopenharmony_ci **/ 175662306a36Sopenharmony_ciint iavf_config_rss(struct iavf_adapter *adapter) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci if (RSS_PF(adapter)) { 176062306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_SET_RSS_LUT | 176162306a36Sopenharmony_ci IAVF_FLAG_AQ_SET_RSS_KEY; 176262306a36Sopenharmony_ci return 0; 176362306a36Sopenharmony_ci } else if (RSS_AQ(adapter)) { 176462306a36Sopenharmony_ci return iavf_config_rss_aq(adapter); 176562306a36Sopenharmony_ci } else { 176662306a36Sopenharmony_ci return iavf_config_rss_reg(adapter); 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci/** 177162306a36Sopenharmony_ci * iavf_fill_rss_lut - Fill the lut with default values 177262306a36Sopenharmony_ci * @adapter: board private structure 177362306a36Sopenharmony_ci **/ 177462306a36Sopenharmony_cistatic void iavf_fill_rss_lut(struct iavf_adapter *adapter) 177562306a36Sopenharmony_ci{ 177662306a36Sopenharmony_ci u16 i; 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci for (i = 0; i < adapter->rss_lut_size; i++) 177962306a36Sopenharmony_ci adapter->rss_lut[i] = i % adapter->num_active_queues; 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci/** 178362306a36Sopenharmony_ci * iavf_init_rss - Prepare for RSS 178462306a36Sopenharmony_ci * @adapter: board private structure 178562306a36Sopenharmony_ci * 178662306a36Sopenharmony_ci * Return 0 on success, negative on failure 178762306a36Sopenharmony_ci **/ 178862306a36Sopenharmony_cistatic int iavf_init_rss(struct iavf_adapter *adapter) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci if (!RSS_PF(adapter)) { 179362306a36Sopenharmony_ci /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ 179462306a36Sopenharmony_ci if (adapter->vf_res->vf_cap_flags & 179562306a36Sopenharmony_ci VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) 179662306a36Sopenharmony_ci adapter->hena = IAVF_DEFAULT_RSS_HENA_EXPANDED; 179762306a36Sopenharmony_ci else 179862306a36Sopenharmony_ci adapter->hena = IAVF_DEFAULT_RSS_HENA; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci wr32(hw, IAVF_VFQF_HENA(0), (u32)adapter->hena); 180162306a36Sopenharmony_ci wr32(hw, IAVF_VFQF_HENA(1), (u32)(adapter->hena >> 32)); 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci iavf_fill_rss_lut(adapter); 180562306a36Sopenharmony_ci netdev_rss_key_fill((void *)adapter->rss_key, adapter->rss_key_size); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci return iavf_config_rss(adapter); 180862306a36Sopenharmony_ci} 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci/** 181162306a36Sopenharmony_ci * iavf_alloc_q_vectors - Allocate memory for interrupt vectors 181262306a36Sopenharmony_ci * @adapter: board private structure to initialize 181362306a36Sopenharmony_ci * 181462306a36Sopenharmony_ci * We allocate one q_vector per queue interrupt. If allocation fails we 181562306a36Sopenharmony_ci * return -ENOMEM. 181662306a36Sopenharmony_ci **/ 181762306a36Sopenharmony_cistatic int iavf_alloc_q_vectors(struct iavf_adapter *adapter) 181862306a36Sopenharmony_ci{ 181962306a36Sopenharmony_ci int q_idx = 0, num_q_vectors; 182062306a36Sopenharmony_ci struct iavf_q_vector *q_vector; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; 182362306a36Sopenharmony_ci adapter->q_vectors = kcalloc(num_q_vectors, sizeof(*q_vector), 182462306a36Sopenharmony_ci GFP_KERNEL); 182562306a36Sopenharmony_ci if (!adapter->q_vectors) 182662306a36Sopenharmony_ci return -ENOMEM; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { 182962306a36Sopenharmony_ci q_vector = &adapter->q_vectors[q_idx]; 183062306a36Sopenharmony_ci q_vector->adapter = adapter; 183162306a36Sopenharmony_ci q_vector->vsi = &adapter->vsi; 183262306a36Sopenharmony_ci q_vector->v_idx = q_idx; 183362306a36Sopenharmony_ci q_vector->reg_idx = q_idx; 183462306a36Sopenharmony_ci cpumask_copy(&q_vector->affinity_mask, cpu_possible_mask); 183562306a36Sopenharmony_ci netif_napi_add(adapter->netdev, &q_vector->napi, 183662306a36Sopenharmony_ci iavf_napi_poll); 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci/** 184362306a36Sopenharmony_ci * iavf_free_q_vectors - Free memory allocated for interrupt vectors 184462306a36Sopenharmony_ci * @adapter: board private structure to initialize 184562306a36Sopenharmony_ci * 184662306a36Sopenharmony_ci * This function frees the memory allocated to the q_vectors. In addition if 184762306a36Sopenharmony_ci * NAPI is enabled it will delete any references to the NAPI struct prior 184862306a36Sopenharmony_ci * to freeing the q_vector. 184962306a36Sopenharmony_ci **/ 185062306a36Sopenharmony_cistatic void iavf_free_q_vectors(struct iavf_adapter *adapter) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci int q_idx, num_q_vectors; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (!adapter->q_vectors) 185562306a36Sopenharmony_ci return; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { 186062306a36Sopenharmony_ci struct iavf_q_vector *q_vector = &adapter->q_vectors[q_idx]; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci netif_napi_del(&q_vector->napi); 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci kfree(adapter->q_vectors); 186562306a36Sopenharmony_ci adapter->q_vectors = NULL; 186662306a36Sopenharmony_ci} 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci/** 186962306a36Sopenharmony_ci * iavf_reset_interrupt_capability - Reset MSIX setup 187062306a36Sopenharmony_ci * @adapter: board private structure 187162306a36Sopenharmony_ci * 187262306a36Sopenharmony_ci **/ 187362306a36Sopenharmony_cistatic void iavf_reset_interrupt_capability(struct iavf_adapter *adapter) 187462306a36Sopenharmony_ci{ 187562306a36Sopenharmony_ci if (!adapter->msix_entries) 187662306a36Sopenharmony_ci return; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci pci_disable_msix(adapter->pdev); 187962306a36Sopenharmony_ci kfree(adapter->msix_entries); 188062306a36Sopenharmony_ci adapter->msix_entries = NULL; 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci/** 188462306a36Sopenharmony_ci * iavf_init_interrupt_scheme - Determine if MSIX is supported and init 188562306a36Sopenharmony_ci * @adapter: board private structure to initialize 188662306a36Sopenharmony_ci * 188762306a36Sopenharmony_ci **/ 188862306a36Sopenharmony_cistatic int iavf_init_interrupt_scheme(struct iavf_adapter *adapter) 188962306a36Sopenharmony_ci{ 189062306a36Sopenharmony_ci int err; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci err = iavf_alloc_queues(adapter); 189362306a36Sopenharmony_ci if (err) { 189462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 189562306a36Sopenharmony_ci "Unable to allocate memory for queues\n"); 189662306a36Sopenharmony_ci goto err_alloc_queues; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci err = iavf_set_interrupt_capability(adapter); 190062306a36Sopenharmony_ci if (err) { 190162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 190262306a36Sopenharmony_ci "Unable to setup interrupt capabilities\n"); 190362306a36Sopenharmony_ci goto err_set_interrupt; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci err = iavf_alloc_q_vectors(adapter); 190762306a36Sopenharmony_ci if (err) { 190862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 190962306a36Sopenharmony_ci "Unable to allocate memory for queue vectors\n"); 191062306a36Sopenharmony_ci goto err_alloc_q_vectors; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci /* If we've made it so far while ADq flag being ON, then we haven't 191462306a36Sopenharmony_ci * bailed out anywhere in middle. And ADq isn't just enabled but actual 191562306a36Sopenharmony_ci * resources have been allocated in the reset path. 191662306a36Sopenharmony_ci * Now we can truly claim that ADq is enabled. 191762306a36Sopenharmony_ci */ 191862306a36Sopenharmony_ci if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) && 191962306a36Sopenharmony_ci adapter->num_tc) 192062306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "ADq Enabled, %u TCs created", 192162306a36Sopenharmony_ci adapter->num_tc); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Multiqueue %s: Queue pair count = %u", 192462306a36Sopenharmony_ci (adapter->num_active_queues > 1) ? "Enabled" : "Disabled", 192562306a36Sopenharmony_ci adapter->num_active_queues); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci return 0; 192862306a36Sopenharmony_cierr_alloc_q_vectors: 192962306a36Sopenharmony_ci iavf_reset_interrupt_capability(adapter); 193062306a36Sopenharmony_cierr_set_interrupt: 193162306a36Sopenharmony_ci iavf_free_queues(adapter); 193262306a36Sopenharmony_cierr_alloc_queues: 193362306a36Sopenharmony_ci return err; 193462306a36Sopenharmony_ci} 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci/** 193762306a36Sopenharmony_ci * iavf_free_rss - Free memory used by RSS structs 193862306a36Sopenharmony_ci * @adapter: board private structure 193962306a36Sopenharmony_ci **/ 194062306a36Sopenharmony_cistatic void iavf_free_rss(struct iavf_adapter *adapter) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci kfree(adapter->rss_key); 194362306a36Sopenharmony_ci adapter->rss_key = NULL; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci kfree(adapter->rss_lut); 194662306a36Sopenharmony_ci adapter->rss_lut = NULL; 194762306a36Sopenharmony_ci} 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci/** 195062306a36Sopenharmony_ci * iavf_reinit_interrupt_scheme - Reallocate queues and vectors 195162306a36Sopenharmony_ci * @adapter: board private structure 195262306a36Sopenharmony_ci * @running: true if adapter->state == __IAVF_RUNNING 195362306a36Sopenharmony_ci * 195462306a36Sopenharmony_ci * Returns 0 on success, negative on failure 195562306a36Sopenharmony_ci **/ 195662306a36Sopenharmony_cistatic int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter, bool running) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 195962306a36Sopenharmony_ci int err; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci if (running) 196262306a36Sopenharmony_ci iavf_free_traffic_irqs(adapter); 196362306a36Sopenharmony_ci iavf_free_misc_irq(adapter); 196462306a36Sopenharmony_ci iavf_reset_interrupt_capability(adapter); 196562306a36Sopenharmony_ci iavf_free_q_vectors(adapter); 196662306a36Sopenharmony_ci iavf_free_queues(adapter); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci err = iavf_init_interrupt_scheme(adapter); 196962306a36Sopenharmony_ci if (err) 197062306a36Sopenharmony_ci goto err; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci err = iavf_request_misc_irq(adapter); 197562306a36Sopenharmony_ci if (err) 197662306a36Sopenharmony_ci goto err; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci iavf_map_rings_to_vectors(adapter); 198162306a36Sopenharmony_cierr: 198262306a36Sopenharmony_ci return err; 198362306a36Sopenharmony_ci} 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci/** 198662306a36Sopenharmony_ci * iavf_finish_config - do all netdev work that needs RTNL 198762306a36Sopenharmony_ci * @work: our work_struct 198862306a36Sopenharmony_ci * 198962306a36Sopenharmony_ci * Do work that needs both RTNL and crit_lock. 199062306a36Sopenharmony_ci **/ 199162306a36Sopenharmony_cistatic void iavf_finish_config(struct work_struct *work) 199262306a36Sopenharmony_ci{ 199362306a36Sopenharmony_ci struct iavf_adapter *adapter; 199462306a36Sopenharmony_ci int pairs, err; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci adapter = container_of(work, struct iavf_adapter, finish_config); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci /* Always take RTNL first to prevent circular lock dependency */ 199962306a36Sopenharmony_ci rtnl_lock(); 200062306a36Sopenharmony_ci mutex_lock(&adapter->crit_lock); 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) && 200362306a36Sopenharmony_ci adapter->netdev_registered && 200462306a36Sopenharmony_ci !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) { 200562306a36Sopenharmony_ci netdev_update_features(adapter->netdev); 200662306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES; 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci switch (adapter->state) { 201062306a36Sopenharmony_ci case __IAVF_DOWN: 201162306a36Sopenharmony_ci if (!adapter->netdev_registered) { 201262306a36Sopenharmony_ci err = register_netdevice(adapter->netdev); 201362306a36Sopenharmony_ci if (err) { 201462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Unable to register netdev (%d)\n", 201562306a36Sopenharmony_ci err); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci /* go back and try again.*/ 201862306a36Sopenharmony_ci iavf_free_rss(adapter); 201962306a36Sopenharmony_ci iavf_free_misc_irq(adapter); 202062306a36Sopenharmony_ci iavf_reset_interrupt_capability(adapter); 202162306a36Sopenharmony_ci iavf_change_state(adapter, 202262306a36Sopenharmony_ci __IAVF_INIT_CONFIG_ADAPTER); 202362306a36Sopenharmony_ci goto out; 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci adapter->netdev_registered = true; 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci /* Set the real number of queues when reset occurs while 202962306a36Sopenharmony_ci * state == __IAVF_DOWN 203062306a36Sopenharmony_ci */ 203162306a36Sopenharmony_ci fallthrough; 203262306a36Sopenharmony_ci case __IAVF_RUNNING: 203362306a36Sopenharmony_ci pairs = adapter->num_active_queues; 203462306a36Sopenharmony_ci netif_set_real_num_rx_queues(adapter->netdev, pairs); 203562306a36Sopenharmony_ci netif_set_real_num_tx_queues(adapter->netdev, pairs); 203662306a36Sopenharmony_ci break; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci default: 203962306a36Sopenharmony_ci break; 204062306a36Sopenharmony_ci } 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ciout: 204362306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 204462306a36Sopenharmony_ci rtnl_unlock(); 204562306a36Sopenharmony_ci} 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci/** 204862306a36Sopenharmony_ci * iavf_schedule_finish_config - Set the flags and schedule a reset event 204962306a36Sopenharmony_ci * @adapter: board private structure 205062306a36Sopenharmony_ci **/ 205162306a36Sopenharmony_civoid iavf_schedule_finish_config(struct iavf_adapter *adapter) 205262306a36Sopenharmony_ci{ 205362306a36Sopenharmony_ci if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) 205462306a36Sopenharmony_ci queue_work(adapter->wq, &adapter->finish_config); 205562306a36Sopenharmony_ci} 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci/** 205862306a36Sopenharmony_ci * iavf_process_aq_command - process aq_required flags 205962306a36Sopenharmony_ci * and sends aq command 206062306a36Sopenharmony_ci * @adapter: pointer to iavf adapter structure 206162306a36Sopenharmony_ci * 206262306a36Sopenharmony_ci * Returns 0 on success 206362306a36Sopenharmony_ci * Returns error code if no command was sent 206462306a36Sopenharmony_ci * or error code if the command failed. 206562306a36Sopenharmony_ci **/ 206662306a36Sopenharmony_cistatic int iavf_process_aq_command(struct iavf_adapter *adapter) 206762306a36Sopenharmony_ci{ 206862306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_GET_CONFIG) 206962306a36Sopenharmony_ci return iavf_send_vf_config_msg(adapter); 207062306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS) 207162306a36Sopenharmony_ci return iavf_send_vf_offload_vlan_v2_msg(adapter); 207262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_QUEUES) { 207362306a36Sopenharmony_ci iavf_disable_queues(adapter); 207462306a36Sopenharmony_ci return 0; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_MAP_VECTORS) { 207862306a36Sopenharmony_ci iavf_map_queues(adapter); 207962306a36Sopenharmony_ci return 0; 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ADD_MAC_FILTER) { 208362306a36Sopenharmony_ci iavf_add_ether_addrs(adapter); 208462306a36Sopenharmony_ci return 0; 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ADD_VLAN_FILTER) { 208862306a36Sopenharmony_ci iavf_add_vlans(adapter); 208962306a36Sopenharmony_ci return 0; 209062306a36Sopenharmony_ci } 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DEL_MAC_FILTER) { 209362306a36Sopenharmony_ci iavf_del_ether_addrs(adapter); 209462306a36Sopenharmony_ci return 0; 209562306a36Sopenharmony_ci } 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DEL_VLAN_FILTER) { 209862306a36Sopenharmony_ci iavf_del_vlans(adapter); 209962306a36Sopenharmony_ci return 0; 210062306a36Sopenharmony_ci } 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING) { 210362306a36Sopenharmony_ci iavf_enable_vlan_stripping(adapter); 210462306a36Sopenharmony_ci return 0; 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING) { 210862306a36Sopenharmony_ci iavf_disable_vlan_stripping(adapter); 210962306a36Sopenharmony_ci return 0; 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES) { 211362306a36Sopenharmony_ci iavf_configure_queues(adapter); 211462306a36Sopenharmony_ci return 0; 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_QUEUES) { 211862306a36Sopenharmony_ci iavf_enable_queues(adapter); 211962306a36Sopenharmony_ci return 0; 212062306a36Sopenharmony_ci } 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_RSS) { 212362306a36Sopenharmony_ci /* This message goes straight to the firmware, not the 212462306a36Sopenharmony_ci * PF, so we don't have to set current_op as we will 212562306a36Sopenharmony_ci * not get a response through the ARQ. 212662306a36Sopenharmony_ci */ 212762306a36Sopenharmony_ci adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_RSS; 212862306a36Sopenharmony_ci return 0; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_GET_HENA) { 213162306a36Sopenharmony_ci iavf_get_hena(adapter); 213262306a36Sopenharmony_ci return 0; 213362306a36Sopenharmony_ci } 213462306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_SET_HENA) { 213562306a36Sopenharmony_ci iavf_set_hena(adapter); 213662306a36Sopenharmony_ci return 0; 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_KEY) { 213962306a36Sopenharmony_ci iavf_set_rss_key(adapter); 214062306a36Sopenharmony_ci return 0; 214162306a36Sopenharmony_ci } 214262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_LUT) { 214362306a36Sopenharmony_ci iavf_set_rss_lut(adapter); 214462306a36Sopenharmony_ci return 0; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_PROMISC_MODE) { 214862306a36Sopenharmony_ci iavf_set_promiscuous(adapter); 214962306a36Sopenharmony_ci return 0; 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CHANNELS) { 215362306a36Sopenharmony_ci iavf_enable_channels(adapter); 215462306a36Sopenharmony_ci return 0; 215562306a36Sopenharmony_ci } 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CHANNELS) { 215862306a36Sopenharmony_ci iavf_disable_channels(adapter); 215962306a36Sopenharmony_ci return 0; 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ADD_CLOUD_FILTER) { 216262306a36Sopenharmony_ci iavf_add_cloud_filter(adapter); 216362306a36Sopenharmony_ci return 0; 216462306a36Sopenharmony_ci } 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DEL_CLOUD_FILTER) { 216762306a36Sopenharmony_ci iavf_del_cloud_filter(adapter); 216862306a36Sopenharmony_ci return 0; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DEL_CLOUD_FILTER) { 217162306a36Sopenharmony_ci iavf_del_cloud_filter(adapter); 217262306a36Sopenharmony_ci return 0; 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ADD_CLOUD_FILTER) { 217562306a36Sopenharmony_ci iavf_add_cloud_filter(adapter); 217662306a36Sopenharmony_ci return 0; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ADD_FDIR_FILTER) { 217962306a36Sopenharmony_ci iavf_add_fdir_filter(adapter); 218062306a36Sopenharmony_ci return IAVF_SUCCESS; 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DEL_FDIR_FILTER) { 218362306a36Sopenharmony_ci iavf_del_fdir_filter(adapter); 218462306a36Sopenharmony_ci return IAVF_SUCCESS; 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ADD_ADV_RSS_CFG) { 218762306a36Sopenharmony_ci iavf_add_adv_rss_cfg(adapter); 218862306a36Sopenharmony_ci return 0; 218962306a36Sopenharmony_ci } 219062306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DEL_ADV_RSS_CFG) { 219162306a36Sopenharmony_ci iavf_del_adv_rss_cfg(adapter); 219262306a36Sopenharmony_ci return 0; 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING) { 219562306a36Sopenharmony_ci iavf_disable_vlan_stripping_v2(adapter, ETH_P_8021Q); 219662306a36Sopenharmony_ci return 0; 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING) { 219962306a36Sopenharmony_ci iavf_disable_vlan_stripping_v2(adapter, ETH_P_8021AD); 220062306a36Sopenharmony_ci return 0; 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING) { 220362306a36Sopenharmony_ci iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021Q); 220462306a36Sopenharmony_ci return 0; 220562306a36Sopenharmony_ci } 220662306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING) { 220762306a36Sopenharmony_ci iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021AD); 220862306a36Sopenharmony_ci return 0; 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION) { 221162306a36Sopenharmony_ci iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021Q); 221262306a36Sopenharmony_ci return 0; 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION) { 221562306a36Sopenharmony_ci iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021AD); 221662306a36Sopenharmony_ci return 0; 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION) { 221962306a36Sopenharmony_ci iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021Q); 222062306a36Sopenharmony_ci return 0; 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION) { 222362306a36Sopenharmony_ci iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021AD); 222462306a36Sopenharmony_ci return 0; 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_STATS) { 222862306a36Sopenharmony_ci iavf_request_stats(adapter); 222962306a36Sopenharmony_ci return 0; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci return -EAGAIN; 223362306a36Sopenharmony_ci} 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci/** 223662306a36Sopenharmony_ci * iavf_set_vlan_offload_features - set VLAN offload configuration 223762306a36Sopenharmony_ci * @adapter: board private structure 223862306a36Sopenharmony_ci * @prev_features: previous features used for comparison 223962306a36Sopenharmony_ci * @features: updated features used for configuration 224062306a36Sopenharmony_ci * 224162306a36Sopenharmony_ci * Set the aq_required bit(s) based on the requested features passed in to 224262306a36Sopenharmony_ci * configure VLAN stripping and/or VLAN insertion if supported. Also, schedule 224362306a36Sopenharmony_ci * the watchdog if any changes are requested to expedite the request via 224462306a36Sopenharmony_ci * virtchnl. 224562306a36Sopenharmony_ci **/ 224662306a36Sopenharmony_cistatic void 224762306a36Sopenharmony_ciiavf_set_vlan_offload_features(struct iavf_adapter *adapter, 224862306a36Sopenharmony_ci netdev_features_t prev_features, 224962306a36Sopenharmony_ci netdev_features_t features) 225062306a36Sopenharmony_ci{ 225162306a36Sopenharmony_ci bool enable_stripping = true, enable_insertion = true; 225262306a36Sopenharmony_ci u16 vlan_ethertype = 0; 225362306a36Sopenharmony_ci u64 aq_required = 0; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci /* keep cases separate because one ethertype for offloads can be 225662306a36Sopenharmony_ci * disabled at the same time as another is disabled, so check for an 225762306a36Sopenharmony_ci * enabled ethertype first, then check for disabled. Default to 225862306a36Sopenharmony_ci * ETH_P_8021Q so an ethertype is specified if disabling insertion and 225962306a36Sopenharmony_ci * stripping. 226062306a36Sopenharmony_ci */ 226162306a36Sopenharmony_ci if (features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX)) 226262306a36Sopenharmony_ci vlan_ethertype = ETH_P_8021AD; 226362306a36Sopenharmony_ci else if (features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX)) 226462306a36Sopenharmony_ci vlan_ethertype = ETH_P_8021Q; 226562306a36Sopenharmony_ci else if (prev_features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX)) 226662306a36Sopenharmony_ci vlan_ethertype = ETH_P_8021AD; 226762306a36Sopenharmony_ci else if (prev_features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX)) 226862306a36Sopenharmony_ci vlan_ethertype = ETH_P_8021Q; 226962306a36Sopenharmony_ci else 227062306a36Sopenharmony_ci vlan_ethertype = ETH_P_8021Q; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci if (!(features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_CTAG_RX))) 227362306a36Sopenharmony_ci enable_stripping = false; 227462306a36Sopenharmony_ci if (!(features & (NETIF_F_HW_VLAN_STAG_TX | NETIF_F_HW_VLAN_CTAG_TX))) 227562306a36Sopenharmony_ci enable_insertion = false; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci if (VLAN_ALLOWED(adapter)) { 227862306a36Sopenharmony_ci /* VIRTCHNL_VF_OFFLOAD_VLAN only has support for toggling VLAN 227962306a36Sopenharmony_ci * stripping via virtchnl. VLAN insertion can be toggled on the 228062306a36Sopenharmony_ci * netdev, but it doesn't require a virtchnl message 228162306a36Sopenharmony_ci */ 228262306a36Sopenharmony_ci if (enable_stripping) 228362306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; 228462306a36Sopenharmony_ci else 228562306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci } else if (VLAN_V2_ALLOWED(adapter)) { 228862306a36Sopenharmony_ci switch (vlan_ethertype) { 228962306a36Sopenharmony_ci case ETH_P_8021Q: 229062306a36Sopenharmony_ci if (enable_stripping) 229162306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING; 229262306a36Sopenharmony_ci else 229362306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci if (enable_insertion) 229662306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION; 229762306a36Sopenharmony_ci else 229862306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION; 229962306a36Sopenharmony_ci break; 230062306a36Sopenharmony_ci case ETH_P_8021AD: 230162306a36Sopenharmony_ci if (enable_stripping) 230262306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING; 230362306a36Sopenharmony_ci else 230462306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING; 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci if (enable_insertion) 230762306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION; 230862306a36Sopenharmony_ci else 230962306a36Sopenharmony_ci aq_required |= IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION; 231062306a36Sopenharmony_ci break; 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci } 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci if (aq_required) { 231562306a36Sopenharmony_ci adapter->aq_required |= aq_required; 231662306a36Sopenharmony_ci mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); 231762306a36Sopenharmony_ci } 231862306a36Sopenharmony_ci} 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci/** 232162306a36Sopenharmony_ci * iavf_startup - first step of driver startup 232262306a36Sopenharmony_ci * @adapter: board private structure 232362306a36Sopenharmony_ci * 232462306a36Sopenharmony_ci * Function process __IAVF_STARTUP driver state. 232562306a36Sopenharmony_ci * When success the state is changed to __IAVF_INIT_VERSION_CHECK 232662306a36Sopenharmony_ci * when fails the state is changed to __IAVF_INIT_FAILED 232762306a36Sopenharmony_ci **/ 232862306a36Sopenharmony_cistatic void iavf_startup(struct iavf_adapter *adapter) 232962306a36Sopenharmony_ci{ 233062306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 233162306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 233262306a36Sopenharmony_ci enum iavf_status status; 233362306a36Sopenharmony_ci int ret; 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci WARN_ON(adapter->state != __IAVF_STARTUP); 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci /* driver loaded, probe complete */ 233862306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED; 233962306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_RESET_PENDING; 234062306a36Sopenharmony_ci status = iavf_set_mac_type(hw); 234162306a36Sopenharmony_ci if (status) { 234262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", status); 234362306a36Sopenharmony_ci goto err; 234462306a36Sopenharmony_ci } 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci ret = iavf_check_reset_complete(hw); 234762306a36Sopenharmony_ci if (ret) { 234862306a36Sopenharmony_ci dev_info(&pdev->dev, "Device is still in reset (%d), retrying\n", 234962306a36Sopenharmony_ci ret); 235062306a36Sopenharmony_ci goto err; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci hw->aq.num_arq_entries = IAVF_AQ_LEN; 235362306a36Sopenharmony_ci hw->aq.num_asq_entries = IAVF_AQ_LEN; 235462306a36Sopenharmony_ci hw->aq.arq_buf_size = IAVF_MAX_AQ_BUF_SIZE; 235562306a36Sopenharmony_ci hw->aq.asq_buf_size = IAVF_MAX_AQ_BUF_SIZE; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci status = iavf_init_adminq(hw); 235862306a36Sopenharmony_ci if (status) { 235962306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n", 236062306a36Sopenharmony_ci status); 236162306a36Sopenharmony_ci goto err; 236262306a36Sopenharmony_ci } 236362306a36Sopenharmony_ci ret = iavf_send_api_ver(adapter); 236462306a36Sopenharmony_ci if (ret) { 236562306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to send to PF (%d)\n", ret); 236662306a36Sopenharmony_ci iavf_shutdown_adminq(hw); 236762306a36Sopenharmony_ci goto err; 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_VERSION_CHECK); 237062306a36Sopenharmony_ci return; 237162306a36Sopenharmony_cierr: 237262306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_FAILED); 237362306a36Sopenharmony_ci} 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci/** 237662306a36Sopenharmony_ci * iavf_init_version_check - second step of driver startup 237762306a36Sopenharmony_ci * @adapter: board private structure 237862306a36Sopenharmony_ci * 237962306a36Sopenharmony_ci * Function process __IAVF_INIT_VERSION_CHECK driver state. 238062306a36Sopenharmony_ci * When success the state is changed to __IAVF_INIT_GET_RESOURCES 238162306a36Sopenharmony_ci * when fails the state is changed to __IAVF_INIT_FAILED 238262306a36Sopenharmony_ci **/ 238362306a36Sopenharmony_cistatic void iavf_init_version_check(struct iavf_adapter *adapter) 238462306a36Sopenharmony_ci{ 238562306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 238662306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 238762306a36Sopenharmony_ci int err = -EAGAIN; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci WARN_ON(adapter->state != __IAVF_INIT_VERSION_CHECK); 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (!iavf_asq_done(hw)) { 239262306a36Sopenharmony_ci dev_err(&pdev->dev, "Admin queue command never completed\n"); 239362306a36Sopenharmony_ci iavf_shutdown_adminq(hw); 239462306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_STARTUP); 239562306a36Sopenharmony_ci goto err; 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci /* aq msg sent, awaiting reply */ 239962306a36Sopenharmony_ci err = iavf_verify_api_ver(adapter); 240062306a36Sopenharmony_ci if (err) { 240162306a36Sopenharmony_ci if (err == -EALREADY) 240262306a36Sopenharmony_ci err = iavf_send_api_ver(adapter); 240362306a36Sopenharmony_ci else 240462306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n", 240562306a36Sopenharmony_ci adapter->pf_version.major, 240662306a36Sopenharmony_ci adapter->pf_version.minor, 240762306a36Sopenharmony_ci VIRTCHNL_VERSION_MAJOR, 240862306a36Sopenharmony_ci VIRTCHNL_VERSION_MINOR); 240962306a36Sopenharmony_ci goto err; 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci err = iavf_send_vf_config_msg(adapter); 241262306a36Sopenharmony_ci if (err) { 241362306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to send config request (%d)\n", 241462306a36Sopenharmony_ci err); 241562306a36Sopenharmony_ci goto err; 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_GET_RESOURCES); 241862306a36Sopenharmony_ci return; 241962306a36Sopenharmony_cierr: 242062306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_FAILED); 242162306a36Sopenharmony_ci} 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci/** 242462306a36Sopenharmony_ci * iavf_parse_vf_resource_msg - parse response from VIRTCHNL_OP_GET_VF_RESOURCES 242562306a36Sopenharmony_ci * @adapter: board private structure 242662306a36Sopenharmony_ci */ 242762306a36Sopenharmony_ciint iavf_parse_vf_resource_msg(struct iavf_adapter *adapter) 242862306a36Sopenharmony_ci{ 242962306a36Sopenharmony_ci int i, num_req_queues = adapter->num_req_queues; 243062306a36Sopenharmony_ci struct iavf_vsi *vsi = &adapter->vsi; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci for (i = 0; i < adapter->vf_res->num_vsis; i++) { 243362306a36Sopenharmony_ci if (adapter->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV) 243462306a36Sopenharmony_ci adapter->vsi_res = &adapter->vf_res->vsi_res[i]; 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci if (!adapter->vsi_res) { 243762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "No LAN VSI found\n"); 243862306a36Sopenharmony_ci return -ENODEV; 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (num_req_queues && 244262306a36Sopenharmony_ci num_req_queues > adapter->vsi_res->num_queue_pairs) { 244362306a36Sopenharmony_ci /* Problem. The PF gave us fewer queues than what we had 244462306a36Sopenharmony_ci * negotiated in our request. Need a reset to see if we can't 244562306a36Sopenharmony_ci * get back to a working state. 244662306a36Sopenharmony_ci */ 244762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 244862306a36Sopenharmony_ci "Requested %d queues, but PF only gave us %d.\n", 244962306a36Sopenharmony_ci num_req_queues, 245062306a36Sopenharmony_ci adapter->vsi_res->num_queue_pairs); 245162306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_REINIT_MSIX_NEEDED; 245262306a36Sopenharmony_ci adapter->num_req_queues = adapter->vsi_res->num_queue_pairs; 245362306a36Sopenharmony_ci iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci return -EAGAIN; 245662306a36Sopenharmony_ci } 245762306a36Sopenharmony_ci adapter->num_req_queues = 0; 245862306a36Sopenharmony_ci adapter->vsi.id = adapter->vsi_res->vsi_id; 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci adapter->vsi.back = adapter; 246162306a36Sopenharmony_ci adapter->vsi.base_vector = 1; 246262306a36Sopenharmony_ci vsi->netdev = adapter->netdev; 246362306a36Sopenharmony_ci vsi->qs_handle = adapter->vsi_res->qset_handle; 246462306a36Sopenharmony_ci if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) { 246562306a36Sopenharmony_ci adapter->rss_key_size = adapter->vf_res->rss_key_size; 246662306a36Sopenharmony_ci adapter->rss_lut_size = adapter->vf_res->rss_lut_size; 246762306a36Sopenharmony_ci } else { 246862306a36Sopenharmony_ci adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE; 246962306a36Sopenharmony_ci adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE; 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci return 0; 247362306a36Sopenharmony_ci} 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci/** 247662306a36Sopenharmony_ci * iavf_init_get_resources - third step of driver startup 247762306a36Sopenharmony_ci * @adapter: board private structure 247862306a36Sopenharmony_ci * 247962306a36Sopenharmony_ci * Function process __IAVF_INIT_GET_RESOURCES driver state and 248062306a36Sopenharmony_ci * finishes driver initialization procedure. 248162306a36Sopenharmony_ci * When success the state is changed to __IAVF_DOWN 248262306a36Sopenharmony_ci * when fails the state is changed to __IAVF_INIT_FAILED 248362306a36Sopenharmony_ci **/ 248462306a36Sopenharmony_cistatic void iavf_init_get_resources(struct iavf_adapter *adapter) 248562306a36Sopenharmony_ci{ 248662306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 248762306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 248862306a36Sopenharmony_ci int err; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci WARN_ON(adapter->state != __IAVF_INIT_GET_RESOURCES); 249162306a36Sopenharmony_ci /* aq msg sent, awaiting reply */ 249262306a36Sopenharmony_ci if (!adapter->vf_res) { 249362306a36Sopenharmony_ci adapter->vf_res = kzalloc(IAVF_VIRTCHNL_VF_RESOURCE_SIZE, 249462306a36Sopenharmony_ci GFP_KERNEL); 249562306a36Sopenharmony_ci if (!adapter->vf_res) { 249662306a36Sopenharmony_ci err = -ENOMEM; 249762306a36Sopenharmony_ci goto err; 249862306a36Sopenharmony_ci } 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci err = iavf_get_vf_config(adapter); 250162306a36Sopenharmony_ci if (err == -EALREADY) { 250262306a36Sopenharmony_ci err = iavf_send_vf_config_msg(adapter); 250362306a36Sopenharmony_ci goto err; 250462306a36Sopenharmony_ci } else if (err == -EINVAL) { 250562306a36Sopenharmony_ci /* We only get -EINVAL if the device is in a very bad 250662306a36Sopenharmony_ci * state or if we've been disabled for previous bad 250762306a36Sopenharmony_ci * behavior. Either way, we're done now. 250862306a36Sopenharmony_ci */ 250962306a36Sopenharmony_ci iavf_shutdown_adminq(hw); 251062306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n"); 251162306a36Sopenharmony_ci return; 251262306a36Sopenharmony_ci } 251362306a36Sopenharmony_ci if (err) { 251462306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to get VF config (%d)\n", err); 251562306a36Sopenharmony_ci goto err_alloc; 251662306a36Sopenharmony_ci } 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci err = iavf_parse_vf_resource_msg(adapter); 251962306a36Sopenharmony_ci if (err) { 252062306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to parse VF resource message from PF (%d)\n", 252162306a36Sopenharmony_ci err); 252262306a36Sopenharmony_ci goto err_alloc; 252362306a36Sopenharmony_ci } 252462306a36Sopenharmony_ci /* Some features require additional messages to negotiate extended 252562306a36Sopenharmony_ci * capabilities. These are processed in sequence by the 252662306a36Sopenharmony_ci * __IAVF_INIT_EXTENDED_CAPS driver state. 252762306a36Sopenharmony_ci */ 252862306a36Sopenharmony_ci adapter->extended_caps = IAVF_EXTENDED_CAPS; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_EXTENDED_CAPS); 253162306a36Sopenharmony_ci return; 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_cierr_alloc: 253462306a36Sopenharmony_ci kfree(adapter->vf_res); 253562306a36Sopenharmony_ci adapter->vf_res = NULL; 253662306a36Sopenharmony_cierr: 253762306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_FAILED); 253862306a36Sopenharmony_ci} 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci/** 254162306a36Sopenharmony_ci * iavf_init_send_offload_vlan_v2_caps - part of initializing VLAN V2 caps 254262306a36Sopenharmony_ci * @adapter: board private structure 254362306a36Sopenharmony_ci * 254462306a36Sopenharmony_ci * Function processes send of the extended VLAN V2 capability message to the 254562306a36Sopenharmony_ci * PF. Must clear IAVF_EXTENDED_CAP_RECV_VLAN_V2 if the message is not sent, 254662306a36Sopenharmony_ci * e.g. due to PF not negotiating VIRTCHNL_VF_OFFLOAD_VLAN_V2. 254762306a36Sopenharmony_ci */ 254862306a36Sopenharmony_cistatic void iavf_init_send_offload_vlan_v2_caps(struct iavf_adapter *adapter) 254962306a36Sopenharmony_ci{ 255062306a36Sopenharmony_ci int ret; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci WARN_ON(!(adapter->extended_caps & IAVF_EXTENDED_CAP_SEND_VLAN_V2)); 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci ret = iavf_send_vf_offload_vlan_v2_msg(adapter); 255562306a36Sopenharmony_ci if (ret && ret == -EOPNOTSUPP) { 255662306a36Sopenharmony_ci /* PF does not support VIRTCHNL_VF_OFFLOAD_V2. In this case, 255762306a36Sopenharmony_ci * we did not send the capability exchange message and do not 255862306a36Sopenharmony_ci * expect a response. 255962306a36Sopenharmony_ci */ 256062306a36Sopenharmony_ci adapter->extended_caps &= ~IAVF_EXTENDED_CAP_RECV_VLAN_V2; 256162306a36Sopenharmony_ci } 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci /* We sent the message, so move on to the next step */ 256462306a36Sopenharmony_ci adapter->extended_caps &= ~IAVF_EXTENDED_CAP_SEND_VLAN_V2; 256562306a36Sopenharmony_ci} 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci/** 256862306a36Sopenharmony_ci * iavf_init_recv_offload_vlan_v2_caps - part of initializing VLAN V2 caps 256962306a36Sopenharmony_ci * @adapter: board private structure 257062306a36Sopenharmony_ci * 257162306a36Sopenharmony_ci * Function processes receipt of the extended VLAN V2 capability message from 257262306a36Sopenharmony_ci * the PF. 257362306a36Sopenharmony_ci **/ 257462306a36Sopenharmony_cistatic void iavf_init_recv_offload_vlan_v2_caps(struct iavf_adapter *adapter) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci int ret; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci WARN_ON(!(adapter->extended_caps & IAVF_EXTENDED_CAP_RECV_VLAN_V2)); 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci memset(&adapter->vlan_v2_caps, 0, sizeof(adapter->vlan_v2_caps)); 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci ret = iavf_get_vf_vlan_v2_caps(adapter); 258362306a36Sopenharmony_ci if (ret) 258462306a36Sopenharmony_ci goto err; 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci /* We've processed receipt of the VLAN V2 caps message */ 258762306a36Sopenharmony_ci adapter->extended_caps &= ~IAVF_EXTENDED_CAP_RECV_VLAN_V2; 258862306a36Sopenharmony_ci return; 258962306a36Sopenharmony_cierr: 259062306a36Sopenharmony_ci /* We didn't receive a reply. Make sure we try sending again when 259162306a36Sopenharmony_ci * __IAVF_INIT_FAILED attempts to recover. 259262306a36Sopenharmony_ci */ 259362306a36Sopenharmony_ci adapter->extended_caps |= IAVF_EXTENDED_CAP_SEND_VLAN_V2; 259462306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_FAILED); 259562306a36Sopenharmony_ci} 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci/** 259862306a36Sopenharmony_ci * iavf_init_process_extended_caps - Part of driver startup 259962306a36Sopenharmony_ci * @adapter: board private structure 260062306a36Sopenharmony_ci * 260162306a36Sopenharmony_ci * Function processes __IAVF_INIT_EXTENDED_CAPS driver state. This state 260262306a36Sopenharmony_ci * handles negotiating capabilities for features which require an additional 260362306a36Sopenharmony_ci * message. 260462306a36Sopenharmony_ci * 260562306a36Sopenharmony_ci * Once all extended capabilities exchanges are finished, the driver will 260662306a36Sopenharmony_ci * transition into __IAVF_INIT_CONFIG_ADAPTER. 260762306a36Sopenharmony_ci */ 260862306a36Sopenharmony_cistatic void iavf_init_process_extended_caps(struct iavf_adapter *adapter) 260962306a36Sopenharmony_ci{ 261062306a36Sopenharmony_ci WARN_ON(adapter->state != __IAVF_INIT_EXTENDED_CAPS); 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci /* Process capability exchange for VLAN V2 */ 261362306a36Sopenharmony_ci if (adapter->extended_caps & IAVF_EXTENDED_CAP_SEND_VLAN_V2) { 261462306a36Sopenharmony_ci iavf_init_send_offload_vlan_v2_caps(adapter); 261562306a36Sopenharmony_ci return; 261662306a36Sopenharmony_ci } else if (adapter->extended_caps & IAVF_EXTENDED_CAP_RECV_VLAN_V2) { 261762306a36Sopenharmony_ci iavf_init_recv_offload_vlan_v2_caps(adapter); 261862306a36Sopenharmony_ci return; 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci /* When we reach here, no further extended capabilities exchanges are 262262306a36Sopenharmony_ci * necessary, so we finally transition into __IAVF_INIT_CONFIG_ADAPTER 262362306a36Sopenharmony_ci */ 262462306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_CONFIG_ADAPTER); 262562306a36Sopenharmony_ci} 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci/** 262862306a36Sopenharmony_ci * iavf_init_config_adapter - last part of driver startup 262962306a36Sopenharmony_ci * @adapter: board private structure 263062306a36Sopenharmony_ci * 263162306a36Sopenharmony_ci * After all the supported capabilities are negotiated, then the 263262306a36Sopenharmony_ci * __IAVF_INIT_CONFIG_ADAPTER state will finish driver initialization. 263362306a36Sopenharmony_ci */ 263462306a36Sopenharmony_cistatic void iavf_init_config_adapter(struct iavf_adapter *adapter) 263562306a36Sopenharmony_ci{ 263662306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 263762306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 263862306a36Sopenharmony_ci int err; 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci WARN_ON(adapter->state != __IAVF_INIT_CONFIG_ADAPTER); 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci if (iavf_process_config(adapter)) 264362306a36Sopenharmony_ci goto err; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci adapter->current_op = VIRTCHNL_OP_UNKNOWN; 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci netdev->netdev_ops = &iavf_netdev_ops; 265062306a36Sopenharmony_ci iavf_set_ethtool_ops(netdev); 265162306a36Sopenharmony_ci netdev->watchdog_timeo = 5 * HZ; 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci /* MTU range: 68 - 9710 */ 265462306a36Sopenharmony_ci netdev->min_mtu = ETH_MIN_MTU; 265562306a36Sopenharmony_ci netdev->max_mtu = IAVF_MAX_RXBUFFER - IAVF_PACKET_HDR_PAD; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci if (!is_valid_ether_addr(adapter->hw.mac.addr)) { 265862306a36Sopenharmony_ci dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n", 265962306a36Sopenharmony_ci adapter->hw.mac.addr); 266062306a36Sopenharmony_ci eth_hw_addr_random(netdev); 266162306a36Sopenharmony_ci ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); 266262306a36Sopenharmony_ci } else { 266362306a36Sopenharmony_ci eth_hw_addr_set(netdev, adapter->hw.mac.addr); 266462306a36Sopenharmony_ci ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr); 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci adapter->tx_desc_count = IAVF_DEFAULT_TXD; 266862306a36Sopenharmony_ci adapter->rx_desc_count = IAVF_DEFAULT_RXD; 266962306a36Sopenharmony_ci err = iavf_init_interrupt_scheme(adapter); 267062306a36Sopenharmony_ci if (err) 267162306a36Sopenharmony_ci goto err_sw_init; 267262306a36Sopenharmony_ci iavf_map_rings_to_vectors(adapter); 267362306a36Sopenharmony_ci if (adapter->vf_res->vf_cap_flags & 267462306a36Sopenharmony_ci VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) 267562306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_WB_ON_ITR_CAPABLE; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci err = iavf_request_misc_irq(adapter); 267862306a36Sopenharmony_ci if (err) 267962306a36Sopenharmony_ci goto err_sw_init; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci netif_carrier_off(netdev); 268262306a36Sopenharmony_ci adapter->link_up = false; 268362306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci if (CLIENT_ALLOWED(adapter)) { 268662306a36Sopenharmony_ci err = iavf_lan_add_device(adapter); 268762306a36Sopenharmony_ci if (err) 268862306a36Sopenharmony_ci dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n", 268962306a36Sopenharmony_ci err); 269062306a36Sopenharmony_ci } 269162306a36Sopenharmony_ci dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr); 269262306a36Sopenharmony_ci if (netdev->features & NETIF_F_GRO) 269362306a36Sopenharmony_ci dev_info(&pdev->dev, "GRO is enabled\n"); 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_DOWN); 269662306a36Sopenharmony_ci set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci iavf_misc_irq_enable(adapter); 269962306a36Sopenharmony_ci wake_up(&adapter->down_waitqueue); 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci adapter->rss_key = kzalloc(adapter->rss_key_size, GFP_KERNEL); 270262306a36Sopenharmony_ci adapter->rss_lut = kzalloc(adapter->rss_lut_size, GFP_KERNEL); 270362306a36Sopenharmony_ci if (!adapter->rss_key || !adapter->rss_lut) { 270462306a36Sopenharmony_ci err = -ENOMEM; 270562306a36Sopenharmony_ci goto err_mem; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci if (RSS_AQ(adapter)) 270862306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS; 270962306a36Sopenharmony_ci else 271062306a36Sopenharmony_ci iavf_init_rss(adapter); 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci if (VLAN_V2_ALLOWED(adapter)) 271362306a36Sopenharmony_ci /* request initial VLAN offload settings */ 271462306a36Sopenharmony_ci iavf_set_vlan_offload_features(adapter, 0, netdev->features); 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci iavf_schedule_finish_config(adapter); 271762306a36Sopenharmony_ci return; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_cierr_mem: 272062306a36Sopenharmony_ci iavf_free_rss(adapter); 272162306a36Sopenharmony_ci iavf_free_misc_irq(adapter); 272262306a36Sopenharmony_cierr_sw_init: 272362306a36Sopenharmony_ci iavf_reset_interrupt_capability(adapter); 272462306a36Sopenharmony_cierr: 272562306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_FAILED); 272662306a36Sopenharmony_ci} 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci/** 272962306a36Sopenharmony_ci * iavf_watchdog_task - Periodic call-back task 273062306a36Sopenharmony_ci * @work: pointer to work_struct 273162306a36Sopenharmony_ci **/ 273262306a36Sopenharmony_cistatic void iavf_watchdog_task(struct work_struct *work) 273362306a36Sopenharmony_ci{ 273462306a36Sopenharmony_ci struct iavf_adapter *adapter = container_of(work, 273562306a36Sopenharmony_ci struct iavf_adapter, 273662306a36Sopenharmony_ci watchdog_task.work); 273762306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 273862306a36Sopenharmony_ci u32 reg_val; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci if (!mutex_trylock(&adapter->crit_lock)) { 274162306a36Sopenharmony_ci if (adapter->state == __IAVF_REMOVE) 274262306a36Sopenharmony_ci return; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci goto restart_watchdog; 274562306a36Sopenharmony_ci } 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) 274862306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_COMM_FAILED); 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci switch (adapter->state) { 275162306a36Sopenharmony_ci case __IAVF_STARTUP: 275262306a36Sopenharmony_ci iavf_startup(adapter); 275362306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 275462306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 275562306a36Sopenharmony_ci msecs_to_jiffies(30)); 275662306a36Sopenharmony_ci return; 275762306a36Sopenharmony_ci case __IAVF_INIT_VERSION_CHECK: 275862306a36Sopenharmony_ci iavf_init_version_check(adapter); 275962306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 276062306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 276162306a36Sopenharmony_ci msecs_to_jiffies(30)); 276262306a36Sopenharmony_ci return; 276362306a36Sopenharmony_ci case __IAVF_INIT_GET_RESOURCES: 276462306a36Sopenharmony_ci iavf_init_get_resources(adapter); 276562306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 276662306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 276762306a36Sopenharmony_ci msecs_to_jiffies(1)); 276862306a36Sopenharmony_ci return; 276962306a36Sopenharmony_ci case __IAVF_INIT_EXTENDED_CAPS: 277062306a36Sopenharmony_ci iavf_init_process_extended_caps(adapter); 277162306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 277262306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 277362306a36Sopenharmony_ci msecs_to_jiffies(1)); 277462306a36Sopenharmony_ci return; 277562306a36Sopenharmony_ci case __IAVF_INIT_CONFIG_ADAPTER: 277662306a36Sopenharmony_ci iavf_init_config_adapter(adapter); 277762306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 277862306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 277962306a36Sopenharmony_ci msecs_to_jiffies(1)); 278062306a36Sopenharmony_ci return; 278162306a36Sopenharmony_ci case __IAVF_INIT_FAILED: 278262306a36Sopenharmony_ci if (test_bit(__IAVF_IN_REMOVE_TASK, 278362306a36Sopenharmony_ci &adapter->crit_section)) { 278462306a36Sopenharmony_ci /* Do not update the state and do not reschedule 278562306a36Sopenharmony_ci * watchdog task, iavf_remove should handle this state 278662306a36Sopenharmony_ci * as it can loop forever 278762306a36Sopenharmony_ci */ 278862306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 278962306a36Sopenharmony_ci return; 279062306a36Sopenharmony_ci } 279162306a36Sopenharmony_ci if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) { 279262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 279362306a36Sopenharmony_ci "Failed to communicate with PF; waiting before retry\n"); 279462306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED; 279562306a36Sopenharmony_ci iavf_shutdown_adminq(hw); 279662306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 279762306a36Sopenharmony_ci queue_delayed_work(adapter->wq, 279862306a36Sopenharmony_ci &adapter->watchdog_task, (5 * HZ)); 279962306a36Sopenharmony_ci return; 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci /* Try again from failed step*/ 280262306a36Sopenharmony_ci iavf_change_state(adapter, adapter->last_state); 280362306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 280462306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, HZ); 280562306a36Sopenharmony_ci return; 280662306a36Sopenharmony_ci case __IAVF_COMM_FAILED: 280762306a36Sopenharmony_ci if (test_bit(__IAVF_IN_REMOVE_TASK, 280862306a36Sopenharmony_ci &adapter->crit_section)) { 280962306a36Sopenharmony_ci /* Set state to __IAVF_INIT_FAILED and perform remove 281062306a36Sopenharmony_ci * steps. Remove IAVF_FLAG_PF_COMMS_FAILED so the task 281162306a36Sopenharmony_ci * doesn't bring the state back to __IAVF_COMM_FAILED. 281262306a36Sopenharmony_ci */ 281362306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_INIT_FAILED); 281462306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED; 281562306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 281662306a36Sopenharmony_ci return; 281762306a36Sopenharmony_ci } 281862306a36Sopenharmony_ci reg_val = rd32(hw, IAVF_VFGEN_RSTAT) & 281962306a36Sopenharmony_ci IAVF_VFGEN_RSTAT_VFR_STATE_MASK; 282062306a36Sopenharmony_ci if (reg_val == VIRTCHNL_VFR_VFACTIVE || 282162306a36Sopenharmony_ci reg_val == VIRTCHNL_VFR_COMPLETED) { 282262306a36Sopenharmony_ci /* A chance for redemption! */ 282362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 282462306a36Sopenharmony_ci "Hardware came out of reset. Attempting reinit.\n"); 282562306a36Sopenharmony_ci /* When init task contacts the PF and 282662306a36Sopenharmony_ci * gets everything set up again, it'll restart the 282762306a36Sopenharmony_ci * watchdog for us. Down, boy. Sit. Stay. Woof. 282862306a36Sopenharmony_ci */ 282962306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_STARTUP); 283062306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED; 283162306a36Sopenharmony_ci } 283262306a36Sopenharmony_ci adapter->aq_required = 0; 283362306a36Sopenharmony_ci adapter->current_op = VIRTCHNL_OP_UNKNOWN; 283462306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 283562306a36Sopenharmony_ci queue_delayed_work(adapter->wq, 283662306a36Sopenharmony_ci &adapter->watchdog_task, 283762306a36Sopenharmony_ci msecs_to_jiffies(10)); 283862306a36Sopenharmony_ci return; 283962306a36Sopenharmony_ci case __IAVF_RESETTING: 284062306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 284162306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 284262306a36Sopenharmony_ci HZ * 2); 284362306a36Sopenharmony_ci return; 284462306a36Sopenharmony_ci case __IAVF_DOWN: 284562306a36Sopenharmony_ci case __IAVF_DOWN_PENDING: 284662306a36Sopenharmony_ci case __IAVF_TESTING: 284762306a36Sopenharmony_ci case __IAVF_RUNNING: 284862306a36Sopenharmony_ci if (adapter->current_op) { 284962306a36Sopenharmony_ci if (!iavf_asq_done(hw)) { 285062306a36Sopenharmony_ci dev_dbg(&adapter->pdev->dev, 285162306a36Sopenharmony_ci "Admin queue timeout\n"); 285262306a36Sopenharmony_ci iavf_send_api_ver(adapter); 285362306a36Sopenharmony_ci } 285462306a36Sopenharmony_ci } else { 285562306a36Sopenharmony_ci int ret = iavf_process_aq_command(adapter); 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci /* An error will be returned if no commands were 285862306a36Sopenharmony_ci * processed; use this opportunity to update stats 285962306a36Sopenharmony_ci * if the error isn't -ENOTSUPP 286062306a36Sopenharmony_ci */ 286162306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP && 286262306a36Sopenharmony_ci adapter->state == __IAVF_RUNNING) 286362306a36Sopenharmony_ci iavf_request_stats(adapter); 286462306a36Sopenharmony_ci } 286562306a36Sopenharmony_ci if (adapter->state == __IAVF_RUNNING) 286662306a36Sopenharmony_ci iavf_detect_recover_hung(&adapter->vsi); 286762306a36Sopenharmony_ci break; 286862306a36Sopenharmony_ci case __IAVF_REMOVE: 286962306a36Sopenharmony_ci default: 287062306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 287162306a36Sopenharmony_ci return; 287262306a36Sopenharmony_ci } 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci /* check for hw reset */ 287562306a36Sopenharmony_ci reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK; 287662306a36Sopenharmony_ci if (!reg_val) { 287762306a36Sopenharmony_ci adapter->aq_required = 0; 287862306a36Sopenharmony_ci adapter->current_op = VIRTCHNL_OP_UNKNOWN; 287962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); 288062306a36Sopenharmony_ci iavf_schedule_reset(adapter, IAVF_FLAG_RESET_PENDING); 288162306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 288262306a36Sopenharmony_ci queue_delayed_work(adapter->wq, 288362306a36Sopenharmony_ci &adapter->watchdog_task, HZ * 2); 288462306a36Sopenharmony_ci return; 288562306a36Sopenharmony_ci } 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5)); 288862306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 288962306a36Sopenharmony_cirestart_watchdog: 289062306a36Sopenharmony_ci if (adapter->state >= __IAVF_DOWN) 289162306a36Sopenharmony_ci queue_work(adapter->wq, &adapter->adminq_task); 289262306a36Sopenharmony_ci if (adapter->aq_required) 289362306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 289462306a36Sopenharmony_ci msecs_to_jiffies(20)); 289562306a36Sopenharmony_ci else 289662306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 289762306a36Sopenharmony_ci HZ * 2); 289862306a36Sopenharmony_ci} 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci/** 290162306a36Sopenharmony_ci * iavf_disable_vf - disable VF 290262306a36Sopenharmony_ci * @adapter: board private structure 290362306a36Sopenharmony_ci * 290462306a36Sopenharmony_ci * Set communication failed flag and free all resources. 290562306a36Sopenharmony_ci * NOTE: This function is expected to be called with crit_lock being held. 290662306a36Sopenharmony_ci **/ 290762306a36Sopenharmony_cistatic void iavf_disable_vf(struct iavf_adapter *adapter) 290862306a36Sopenharmony_ci{ 290962306a36Sopenharmony_ci struct iavf_mac_filter *f, *ftmp; 291062306a36Sopenharmony_ci struct iavf_vlan_filter *fv, *fvtmp; 291162306a36Sopenharmony_ci struct iavf_cloud_filter *cf, *cftmp; 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci /* We don't use netif_running() because it may be true prior to 291662306a36Sopenharmony_ci * ndo_open() returning, so we can't assume it means all our open 291762306a36Sopenharmony_ci * tasks have finished, since we're not holding the rtnl_lock here. 291862306a36Sopenharmony_ci */ 291962306a36Sopenharmony_ci if (adapter->state == __IAVF_RUNNING) { 292062306a36Sopenharmony_ci set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); 292162306a36Sopenharmony_ci netif_carrier_off(adapter->netdev); 292262306a36Sopenharmony_ci netif_tx_disable(adapter->netdev); 292362306a36Sopenharmony_ci adapter->link_up = false; 292462306a36Sopenharmony_ci iavf_napi_disable_all(adapter); 292562306a36Sopenharmony_ci iavf_irq_disable(adapter); 292662306a36Sopenharmony_ci iavf_free_traffic_irqs(adapter); 292762306a36Sopenharmony_ci iavf_free_all_tx_resources(adapter); 292862306a36Sopenharmony_ci iavf_free_all_rx_resources(adapter); 292962306a36Sopenharmony_ci } 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci /* Delete all of the filters */ 293462306a36Sopenharmony_ci list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { 293562306a36Sopenharmony_ci list_del(&f->list); 293662306a36Sopenharmony_ci kfree(f); 293762306a36Sopenharmony_ci } 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ci list_for_each_entry_safe(fv, fvtmp, &adapter->vlan_filter_list, list) { 294062306a36Sopenharmony_ci list_del(&fv->list); 294162306a36Sopenharmony_ci kfree(fv); 294262306a36Sopenharmony_ci } 294362306a36Sopenharmony_ci adapter->num_vlan_filters = 0; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 294862306a36Sopenharmony_ci list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) { 294962306a36Sopenharmony_ci list_del(&cf->list); 295062306a36Sopenharmony_ci kfree(cf); 295162306a36Sopenharmony_ci adapter->num_cloud_filters--; 295262306a36Sopenharmony_ci } 295362306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci iavf_free_misc_irq(adapter); 295662306a36Sopenharmony_ci iavf_reset_interrupt_capability(adapter); 295762306a36Sopenharmony_ci iavf_free_q_vectors(adapter); 295862306a36Sopenharmony_ci iavf_free_queues(adapter); 295962306a36Sopenharmony_ci memset(adapter->vf_res, 0, IAVF_VIRTCHNL_VF_RESOURCE_SIZE); 296062306a36Sopenharmony_ci iavf_shutdown_adminq(&adapter->hw); 296162306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_RESET_PENDING; 296262306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_DOWN); 296362306a36Sopenharmony_ci wake_up(&adapter->down_waitqueue); 296462306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n"); 296562306a36Sopenharmony_ci} 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci/** 296862306a36Sopenharmony_ci * iavf_reset_task - Call-back task to handle hardware reset 296962306a36Sopenharmony_ci * @work: pointer to work_struct 297062306a36Sopenharmony_ci * 297162306a36Sopenharmony_ci * During reset we need to shut down and reinitialize the admin queue 297262306a36Sopenharmony_ci * before we can use it to communicate with the PF again. We also clear 297362306a36Sopenharmony_ci * and reinit the rings because that context is lost as well. 297462306a36Sopenharmony_ci **/ 297562306a36Sopenharmony_cistatic void iavf_reset_task(struct work_struct *work) 297662306a36Sopenharmony_ci{ 297762306a36Sopenharmony_ci struct iavf_adapter *adapter = container_of(work, 297862306a36Sopenharmony_ci struct iavf_adapter, 297962306a36Sopenharmony_ci reset_task); 298062306a36Sopenharmony_ci struct virtchnl_vf_resource *vfres = adapter->vf_res; 298162306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 298262306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 298362306a36Sopenharmony_ci struct iavf_mac_filter *f, *ftmp; 298462306a36Sopenharmony_ci struct iavf_cloud_filter *cf; 298562306a36Sopenharmony_ci enum iavf_status status; 298662306a36Sopenharmony_ci u32 reg_val; 298762306a36Sopenharmony_ci int i = 0, err; 298862306a36Sopenharmony_ci bool running; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci /* When device is being removed it doesn't make sense to run the reset 299162306a36Sopenharmony_ci * task, just return in such a case. 299262306a36Sopenharmony_ci */ 299362306a36Sopenharmony_ci if (!mutex_trylock(&adapter->crit_lock)) { 299462306a36Sopenharmony_ci if (adapter->state != __IAVF_REMOVE) 299562306a36Sopenharmony_ci queue_work(adapter->wq, &adapter->reset_task); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci return; 299862306a36Sopenharmony_ci } 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci while (!mutex_trylock(&adapter->client_lock)) 300162306a36Sopenharmony_ci usleep_range(500, 1000); 300262306a36Sopenharmony_ci if (CLIENT_ENABLED(adapter)) { 300362306a36Sopenharmony_ci adapter->flags &= ~(IAVF_FLAG_CLIENT_NEEDS_OPEN | 300462306a36Sopenharmony_ci IAVF_FLAG_CLIENT_NEEDS_CLOSE | 300562306a36Sopenharmony_ci IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS | 300662306a36Sopenharmony_ci IAVF_FLAG_SERVICE_CLIENT_REQUESTED); 300762306a36Sopenharmony_ci cancel_delayed_work_sync(&adapter->client_task); 300862306a36Sopenharmony_ci iavf_notify_client_close(&adapter->vsi, true); 300962306a36Sopenharmony_ci } 301062306a36Sopenharmony_ci iavf_misc_irq_disable(adapter); 301162306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_RESET_NEEDED) { 301262306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_RESET_NEEDED; 301362306a36Sopenharmony_ci /* Restart the AQ here. If we have been reset but didn't 301462306a36Sopenharmony_ci * detect it, or if the PF had to reinit, our AQ will be hosed. 301562306a36Sopenharmony_ci */ 301662306a36Sopenharmony_ci iavf_shutdown_adminq(hw); 301762306a36Sopenharmony_ci iavf_init_adminq(hw); 301862306a36Sopenharmony_ci iavf_request_reset(adapter); 301962306a36Sopenharmony_ci } 302062306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_RESET_PENDING; 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci /* poll until we see the reset actually happen */ 302362306a36Sopenharmony_ci for (i = 0; i < IAVF_RESET_WAIT_DETECTED_COUNT; i++) { 302462306a36Sopenharmony_ci reg_val = rd32(hw, IAVF_VF_ARQLEN1) & 302562306a36Sopenharmony_ci IAVF_VF_ARQLEN1_ARQENABLE_MASK; 302662306a36Sopenharmony_ci if (!reg_val) 302762306a36Sopenharmony_ci break; 302862306a36Sopenharmony_ci usleep_range(5000, 10000); 302962306a36Sopenharmony_ci } 303062306a36Sopenharmony_ci if (i == IAVF_RESET_WAIT_DETECTED_COUNT) { 303162306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Never saw reset\n"); 303262306a36Sopenharmony_ci goto continue_reset; /* act like the reset happened */ 303362306a36Sopenharmony_ci } 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci /* wait until the reset is complete and the PF is responding to us */ 303662306a36Sopenharmony_ci for (i = 0; i < IAVF_RESET_WAIT_COMPLETE_COUNT; i++) { 303762306a36Sopenharmony_ci /* sleep first to make sure a minimum wait time is met */ 303862306a36Sopenharmony_ci msleep(IAVF_RESET_WAIT_MS); 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci reg_val = rd32(hw, IAVF_VFGEN_RSTAT) & 304162306a36Sopenharmony_ci IAVF_VFGEN_RSTAT_VFR_STATE_MASK; 304262306a36Sopenharmony_ci if (reg_val == VIRTCHNL_VFR_VFACTIVE) 304362306a36Sopenharmony_ci break; 304462306a36Sopenharmony_ci } 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci pci_set_master(adapter->pdev); 304762306a36Sopenharmony_ci pci_restore_msi_state(adapter->pdev); 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci if (i == IAVF_RESET_WAIT_COMPLETE_COUNT) { 305062306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", 305162306a36Sopenharmony_ci reg_val); 305262306a36Sopenharmony_ci iavf_disable_vf(adapter); 305362306a36Sopenharmony_ci mutex_unlock(&adapter->client_lock); 305462306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 305562306a36Sopenharmony_ci return; /* Do not attempt to reinit. It's dead, Jim. */ 305662306a36Sopenharmony_ci } 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_cicontinue_reset: 305962306a36Sopenharmony_ci /* We don't use netif_running() because it may be true prior to 306062306a36Sopenharmony_ci * ndo_open() returning, so we can't assume it means all our open 306162306a36Sopenharmony_ci * tasks have finished, since we're not holding the rtnl_lock here. 306262306a36Sopenharmony_ci */ 306362306a36Sopenharmony_ci running = adapter->state == __IAVF_RUNNING; 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci if (running) { 306662306a36Sopenharmony_ci netif_carrier_off(netdev); 306762306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 306862306a36Sopenharmony_ci adapter->link_up = false; 306962306a36Sopenharmony_ci iavf_napi_disable_all(adapter); 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci iavf_irq_disable(adapter); 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_RESETTING); 307462306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_RESET_PENDING; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci /* free the Tx/Rx rings and descriptors, might be better to just 307762306a36Sopenharmony_ci * re-use them sometime in the future 307862306a36Sopenharmony_ci */ 307962306a36Sopenharmony_ci iavf_free_all_rx_resources(adapter); 308062306a36Sopenharmony_ci iavf_free_all_tx_resources(adapter); 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_QUEUES_DISABLED; 308362306a36Sopenharmony_ci /* kill and reinit the admin queue */ 308462306a36Sopenharmony_ci iavf_shutdown_adminq(hw); 308562306a36Sopenharmony_ci adapter->current_op = VIRTCHNL_OP_UNKNOWN; 308662306a36Sopenharmony_ci status = iavf_init_adminq(hw); 308762306a36Sopenharmony_ci if (status) { 308862306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n", 308962306a36Sopenharmony_ci status); 309062306a36Sopenharmony_ci goto reset_err; 309162306a36Sopenharmony_ci } 309262306a36Sopenharmony_ci adapter->aq_required = 0; 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) || 309562306a36Sopenharmony_ci (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) { 309662306a36Sopenharmony_ci err = iavf_reinit_interrupt_scheme(adapter, running); 309762306a36Sopenharmony_ci if (err) 309862306a36Sopenharmony_ci goto reset_err; 309962306a36Sopenharmony_ci } 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci if (RSS_AQ(adapter)) { 310262306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS; 310362306a36Sopenharmony_ci } else { 310462306a36Sopenharmony_ci err = iavf_init_rss(adapter); 310562306a36Sopenharmony_ci if (err) 310662306a36Sopenharmony_ci goto reset_err; 310762306a36Sopenharmony_ci } 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_GET_CONFIG; 311062306a36Sopenharmony_ci /* always set since VIRTCHNL_OP_GET_VF_RESOURCES has not been 311162306a36Sopenharmony_ci * sent/received yet, so VLAN_V2_ALLOWED() cannot is not reliable here, 311262306a36Sopenharmony_ci * however the VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS won't be sent until 311362306a36Sopenharmony_ci * VIRTCHNL_OP_GET_VF_RESOURCES and VIRTCHNL_VF_OFFLOAD_VLAN_V2 have 311462306a36Sopenharmony_ci * been successfully sent and negotiated 311562306a36Sopenharmony_ci */ 311662306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS; 311762306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci /* Delete filter for the current MAC address, it could have 312262306a36Sopenharmony_ci * been changed by the PF via administratively set MAC. 312362306a36Sopenharmony_ci * Will be re-added via VIRTCHNL_OP_GET_VF_RESOURCES. 312462306a36Sopenharmony_ci */ 312562306a36Sopenharmony_ci list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { 312662306a36Sopenharmony_ci if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr)) { 312762306a36Sopenharmony_ci list_del(&f->list); 312862306a36Sopenharmony_ci kfree(f); 312962306a36Sopenharmony_ci } 313062306a36Sopenharmony_ci } 313162306a36Sopenharmony_ci /* re-add all MAC filters */ 313262306a36Sopenharmony_ci list_for_each_entry(f, &adapter->mac_filter_list, list) { 313362306a36Sopenharmony_ci f->add = true; 313462306a36Sopenharmony_ci } 313562306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci /* check if TCs are running and re-add all cloud filters */ 313862306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 313962306a36Sopenharmony_ci if ((vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) && 314062306a36Sopenharmony_ci adapter->num_tc) { 314162306a36Sopenharmony_ci list_for_each_entry(cf, &adapter->cloud_filter_list, list) { 314262306a36Sopenharmony_ci cf->add = true; 314362306a36Sopenharmony_ci } 314462306a36Sopenharmony_ci } 314562306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; 314862306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER; 314962306a36Sopenharmony_ci iavf_misc_irq_enable(adapter); 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci mod_delayed_work(adapter->wq, &adapter->watchdog_task, 2); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci /* We were running when the reset started, so we need to restore some 315462306a36Sopenharmony_ci * state here. 315562306a36Sopenharmony_ci */ 315662306a36Sopenharmony_ci if (running) { 315762306a36Sopenharmony_ci /* allocate transmit descriptors */ 315862306a36Sopenharmony_ci err = iavf_setup_all_tx_resources(adapter); 315962306a36Sopenharmony_ci if (err) 316062306a36Sopenharmony_ci goto reset_err; 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci /* allocate receive descriptors */ 316362306a36Sopenharmony_ci err = iavf_setup_all_rx_resources(adapter); 316462306a36Sopenharmony_ci if (err) 316562306a36Sopenharmony_ci goto reset_err; 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) || 316862306a36Sopenharmony_ci (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) { 316962306a36Sopenharmony_ci err = iavf_request_traffic_irqs(adapter, netdev->name); 317062306a36Sopenharmony_ci if (err) 317162306a36Sopenharmony_ci goto reset_err; 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_REINIT_MSIX_NEEDED; 317462306a36Sopenharmony_ci } 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci iavf_configure(adapter); 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci /* iavf_up_complete() will switch device back 317962306a36Sopenharmony_ci * to __IAVF_RUNNING 318062306a36Sopenharmony_ci */ 318162306a36Sopenharmony_ci iavf_up_complete(adapter); 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci iavf_irq_enable(adapter, true); 318462306a36Sopenharmony_ci } else { 318562306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_DOWN); 318662306a36Sopenharmony_ci wake_up(&adapter->down_waitqueue); 318762306a36Sopenharmony_ci } 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci wake_up(&adapter->reset_waitqueue); 319262306a36Sopenharmony_ci mutex_unlock(&adapter->client_lock); 319362306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci return; 319662306a36Sopenharmony_cireset_err: 319762306a36Sopenharmony_ci if (running) { 319862306a36Sopenharmony_ci set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); 319962306a36Sopenharmony_ci iavf_free_traffic_irqs(adapter); 320062306a36Sopenharmony_ci } 320162306a36Sopenharmony_ci iavf_disable_vf(adapter); 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci mutex_unlock(&adapter->client_lock); 320462306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 320562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); 320662306a36Sopenharmony_ci} 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci/** 320962306a36Sopenharmony_ci * iavf_adminq_task - worker thread to clean the admin queue 321062306a36Sopenharmony_ci * @work: pointer to work_struct containing our data 321162306a36Sopenharmony_ci **/ 321262306a36Sopenharmony_cistatic void iavf_adminq_task(struct work_struct *work) 321362306a36Sopenharmony_ci{ 321462306a36Sopenharmony_ci struct iavf_adapter *adapter = 321562306a36Sopenharmony_ci container_of(work, struct iavf_adapter, adminq_task); 321662306a36Sopenharmony_ci struct iavf_hw *hw = &adapter->hw; 321762306a36Sopenharmony_ci struct iavf_arq_event_info event; 321862306a36Sopenharmony_ci enum virtchnl_ops v_op; 321962306a36Sopenharmony_ci enum iavf_status ret, v_ret; 322062306a36Sopenharmony_ci u32 val, oldval; 322162306a36Sopenharmony_ci u16 pending; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci if (!mutex_trylock(&adapter->crit_lock)) { 322462306a36Sopenharmony_ci if (adapter->state == __IAVF_REMOVE) 322562306a36Sopenharmony_ci return; 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci queue_work(adapter->wq, &adapter->adminq_task); 322862306a36Sopenharmony_ci goto out; 322962306a36Sopenharmony_ci } 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) 323262306a36Sopenharmony_ci goto unlock; 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci event.buf_len = IAVF_MAX_AQ_BUF_SIZE; 323562306a36Sopenharmony_ci event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); 323662306a36Sopenharmony_ci if (!event.msg_buf) 323762306a36Sopenharmony_ci goto unlock; 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci do { 324062306a36Sopenharmony_ci ret = iavf_clean_arq_element(hw, &event, &pending); 324162306a36Sopenharmony_ci v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); 324262306a36Sopenharmony_ci v_ret = (enum iavf_status)le32_to_cpu(event.desc.cookie_low); 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci if (ret || !v_op) 324562306a36Sopenharmony_ci break; /* No event to process or error cleaning ARQ */ 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci iavf_virtchnl_completion(adapter, v_op, v_ret, event.msg_buf, 324862306a36Sopenharmony_ci event.msg_len); 324962306a36Sopenharmony_ci if (pending != 0) 325062306a36Sopenharmony_ci memset(event.msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE); 325162306a36Sopenharmony_ci } while (pending); 325262306a36Sopenharmony_ci 325362306a36Sopenharmony_ci if (iavf_is_reset_in_progress(adapter)) 325462306a36Sopenharmony_ci goto freedom; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci /* check for error indications */ 325762306a36Sopenharmony_ci val = rd32(hw, hw->aq.arq.len); 325862306a36Sopenharmony_ci if (val == 0xdeadbeef || val == 0xffffffff) /* device in reset */ 325962306a36Sopenharmony_ci goto freedom; 326062306a36Sopenharmony_ci oldval = val; 326162306a36Sopenharmony_ci if (val & IAVF_VF_ARQLEN1_ARQVFE_MASK) { 326262306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "ARQ VF Error detected\n"); 326362306a36Sopenharmony_ci val &= ~IAVF_VF_ARQLEN1_ARQVFE_MASK; 326462306a36Sopenharmony_ci } 326562306a36Sopenharmony_ci if (val & IAVF_VF_ARQLEN1_ARQOVFL_MASK) { 326662306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "ARQ Overflow Error detected\n"); 326762306a36Sopenharmony_ci val &= ~IAVF_VF_ARQLEN1_ARQOVFL_MASK; 326862306a36Sopenharmony_ci } 326962306a36Sopenharmony_ci if (val & IAVF_VF_ARQLEN1_ARQCRIT_MASK) { 327062306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "ARQ Critical Error detected\n"); 327162306a36Sopenharmony_ci val &= ~IAVF_VF_ARQLEN1_ARQCRIT_MASK; 327262306a36Sopenharmony_ci } 327362306a36Sopenharmony_ci if (oldval != val) 327462306a36Sopenharmony_ci wr32(hw, hw->aq.arq.len, val); 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci val = rd32(hw, hw->aq.asq.len); 327762306a36Sopenharmony_ci oldval = val; 327862306a36Sopenharmony_ci if (val & IAVF_VF_ATQLEN1_ATQVFE_MASK) { 327962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "ASQ VF Error detected\n"); 328062306a36Sopenharmony_ci val &= ~IAVF_VF_ATQLEN1_ATQVFE_MASK; 328162306a36Sopenharmony_ci } 328262306a36Sopenharmony_ci if (val & IAVF_VF_ATQLEN1_ATQOVFL_MASK) { 328362306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "ASQ Overflow Error detected\n"); 328462306a36Sopenharmony_ci val &= ~IAVF_VF_ATQLEN1_ATQOVFL_MASK; 328562306a36Sopenharmony_ci } 328662306a36Sopenharmony_ci if (val & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { 328762306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "ASQ Critical Error detected\n"); 328862306a36Sopenharmony_ci val &= ~IAVF_VF_ATQLEN1_ATQCRIT_MASK; 328962306a36Sopenharmony_ci } 329062306a36Sopenharmony_ci if (oldval != val) 329162306a36Sopenharmony_ci wr32(hw, hw->aq.asq.len, val); 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_cifreedom: 329462306a36Sopenharmony_ci kfree(event.msg_buf); 329562306a36Sopenharmony_ciunlock: 329662306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 329762306a36Sopenharmony_ciout: 329862306a36Sopenharmony_ci /* re-enable Admin queue interrupt cause */ 329962306a36Sopenharmony_ci iavf_misc_irq_enable(adapter); 330062306a36Sopenharmony_ci} 330162306a36Sopenharmony_ci 330262306a36Sopenharmony_ci/** 330362306a36Sopenharmony_ci * iavf_client_task - worker thread to perform client work 330462306a36Sopenharmony_ci * @work: pointer to work_struct containing our data 330562306a36Sopenharmony_ci * 330662306a36Sopenharmony_ci * This task handles client interactions. Because client calls can be 330762306a36Sopenharmony_ci * reentrant, we can't handle them in the watchdog. 330862306a36Sopenharmony_ci **/ 330962306a36Sopenharmony_cistatic void iavf_client_task(struct work_struct *work) 331062306a36Sopenharmony_ci{ 331162306a36Sopenharmony_ci struct iavf_adapter *adapter = 331262306a36Sopenharmony_ci container_of(work, struct iavf_adapter, client_task.work); 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci /* If we can't get the client bit, just give up. We'll be rescheduled 331562306a36Sopenharmony_ci * later. 331662306a36Sopenharmony_ci */ 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci if (!mutex_trylock(&adapter->client_lock)) 331962306a36Sopenharmony_ci return; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_SERVICE_CLIENT_REQUESTED) { 332262306a36Sopenharmony_ci iavf_client_subtask(adapter); 332362306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_SERVICE_CLIENT_REQUESTED; 332462306a36Sopenharmony_ci goto out; 332562306a36Sopenharmony_ci } 332662306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS) { 332762306a36Sopenharmony_ci iavf_notify_client_l2_params(&adapter->vsi); 332862306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS; 332962306a36Sopenharmony_ci goto out; 333062306a36Sopenharmony_ci } 333162306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_CLOSE) { 333262306a36Sopenharmony_ci iavf_notify_client_close(&adapter->vsi, false); 333362306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_CLOSE; 333462306a36Sopenharmony_ci goto out; 333562306a36Sopenharmony_ci } 333662306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_OPEN) { 333762306a36Sopenharmony_ci iavf_notify_client_open(&adapter->vsi); 333862306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_OPEN; 333962306a36Sopenharmony_ci } 334062306a36Sopenharmony_ciout: 334162306a36Sopenharmony_ci mutex_unlock(&adapter->client_lock); 334262306a36Sopenharmony_ci} 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci/** 334562306a36Sopenharmony_ci * iavf_free_all_tx_resources - Free Tx Resources for All Queues 334662306a36Sopenharmony_ci * @adapter: board private structure 334762306a36Sopenharmony_ci * 334862306a36Sopenharmony_ci * Free all transmit software resources 334962306a36Sopenharmony_ci **/ 335062306a36Sopenharmony_civoid iavf_free_all_tx_resources(struct iavf_adapter *adapter) 335162306a36Sopenharmony_ci{ 335262306a36Sopenharmony_ci int i; 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci if (!adapter->tx_rings) 335562306a36Sopenharmony_ci return; 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) 335862306a36Sopenharmony_ci if (adapter->tx_rings[i].desc) 335962306a36Sopenharmony_ci iavf_free_tx_resources(&adapter->tx_rings[i]); 336062306a36Sopenharmony_ci} 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci/** 336362306a36Sopenharmony_ci * iavf_setup_all_tx_resources - allocate all queues Tx resources 336462306a36Sopenharmony_ci * @adapter: board private structure 336562306a36Sopenharmony_ci * 336662306a36Sopenharmony_ci * If this function returns with an error, then it's possible one or 336762306a36Sopenharmony_ci * more of the rings is populated (while the rest are not). It is the 336862306a36Sopenharmony_ci * callers duty to clean those orphaned rings. 336962306a36Sopenharmony_ci * 337062306a36Sopenharmony_ci * Return 0 on success, negative on failure 337162306a36Sopenharmony_ci **/ 337262306a36Sopenharmony_cistatic int iavf_setup_all_tx_resources(struct iavf_adapter *adapter) 337362306a36Sopenharmony_ci{ 337462306a36Sopenharmony_ci int i, err = 0; 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) { 337762306a36Sopenharmony_ci adapter->tx_rings[i].count = adapter->tx_desc_count; 337862306a36Sopenharmony_ci err = iavf_setup_tx_descriptors(&adapter->tx_rings[i]); 337962306a36Sopenharmony_ci if (!err) 338062306a36Sopenharmony_ci continue; 338162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 338262306a36Sopenharmony_ci "Allocation for Tx Queue %u failed\n", i); 338362306a36Sopenharmony_ci break; 338462306a36Sopenharmony_ci } 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci return err; 338762306a36Sopenharmony_ci} 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci/** 339062306a36Sopenharmony_ci * iavf_setup_all_rx_resources - allocate all queues Rx resources 339162306a36Sopenharmony_ci * @adapter: board private structure 339262306a36Sopenharmony_ci * 339362306a36Sopenharmony_ci * If this function returns with an error, then it's possible one or 339462306a36Sopenharmony_ci * more of the rings is populated (while the rest are not). It is the 339562306a36Sopenharmony_ci * callers duty to clean those orphaned rings. 339662306a36Sopenharmony_ci * 339762306a36Sopenharmony_ci * Return 0 on success, negative on failure 339862306a36Sopenharmony_ci **/ 339962306a36Sopenharmony_cistatic int iavf_setup_all_rx_resources(struct iavf_adapter *adapter) 340062306a36Sopenharmony_ci{ 340162306a36Sopenharmony_ci int i, err = 0; 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) { 340462306a36Sopenharmony_ci adapter->rx_rings[i].count = adapter->rx_desc_count; 340562306a36Sopenharmony_ci err = iavf_setup_rx_descriptors(&adapter->rx_rings[i]); 340662306a36Sopenharmony_ci if (!err) 340762306a36Sopenharmony_ci continue; 340862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 340962306a36Sopenharmony_ci "Allocation for Rx Queue %u failed\n", i); 341062306a36Sopenharmony_ci break; 341162306a36Sopenharmony_ci } 341262306a36Sopenharmony_ci return err; 341362306a36Sopenharmony_ci} 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci/** 341662306a36Sopenharmony_ci * iavf_free_all_rx_resources - Free Rx Resources for All Queues 341762306a36Sopenharmony_ci * @adapter: board private structure 341862306a36Sopenharmony_ci * 341962306a36Sopenharmony_ci * Free all receive software resources 342062306a36Sopenharmony_ci **/ 342162306a36Sopenharmony_civoid iavf_free_all_rx_resources(struct iavf_adapter *adapter) 342262306a36Sopenharmony_ci{ 342362306a36Sopenharmony_ci int i; 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci if (!adapter->rx_rings) 342662306a36Sopenharmony_ci return; 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci for (i = 0; i < adapter->num_active_queues; i++) 342962306a36Sopenharmony_ci if (adapter->rx_rings[i].desc) 343062306a36Sopenharmony_ci iavf_free_rx_resources(&adapter->rx_rings[i]); 343162306a36Sopenharmony_ci} 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci/** 343462306a36Sopenharmony_ci * iavf_validate_tx_bandwidth - validate the max Tx bandwidth 343562306a36Sopenharmony_ci * @adapter: board private structure 343662306a36Sopenharmony_ci * @max_tx_rate: max Tx bw for a tc 343762306a36Sopenharmony_ci **/ 343862306a36Sopenharmony_cistatic int iavf_validate_tx_bandwidth(struct iavf_adapter *adapter, 343962306a36Sopenharmony_ci u64 max_tx_rate) 344062306a36Sopenharmony_ci{ 344162306a36Sopenharmony_ci int speed = 0, ret = 0; 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci if (ADV_LINK_SUPPORT(adapter)) { 344462306a36Sopenharmony_ci if (adapter->link_speed_mbps < U32_MAX) { 344562306a36Sopenharmony_ci speed = adapter->link_speed_mbps; 344662306a36Sopenharmony_ci goto validate_bw; 344762306a36Sopenharmony_ci } else { 344862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Unknown link speed\n"); 344962306a36Sopenharmony_ci return -EINVAL; 345062306a36Sopenharmony_ci } 345162306a36Sopenharmony_ci } 345262306a36Sopenharmony_ci 345362306a36Sopenharmony_ci switch (adapter->link_speed) { 345462306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_40GB: 345562306a36Sopenharmony_ci speed = SPEED_40000; 345662306a36Sopenharmony_ci break; 345762306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_25GB: 345862306a36Sopenharmony_ci speed = SPEED_25000; 345962306a36Sopenharmony_ci break; 346062306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_20GB: 346162306a36Sopenharmony_ci speed = SPEED_20000; 346262306a36Sopenharmony_ci break; 346362306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_10GB: 346462306a36Sopenharmony_ci speed = SPEED_10000; 346562306a36Sopenharmony_ci break; 346662306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_5GB: 346762306a36Sopenharmony_ci speed = SPEED_5000; 346862306a36Sopenharmony_ci break; 346962306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_2_5GB: 347062306a36Sopenharmony_ci speed = SPEED_2500; 347162306a36Sopenharmony_ci break; 347262306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_1GB: 347362306a36Sopenharmony_ci speed = SPEED_1000; 347462306a36Sopenharmony_ci break; 347562306a36Sopenharmony_ci case VIRTCHNL_LINK_SPEED_100MB: 347662306a36Sopenharmony_ci speed = SPEED_100; 347762306a36Sopenharmony_ci break; 347862306a36Sopenharmony_ci default: 347962306a36Sopenharmony_ci break; 348062306a36Sopenharmony_ci } 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_civalidate_bw: 348362306a36Sopenharmony_ci if (max_tx_rate > speed) { 348462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 348562306a36Sopenharmony_ci "Invalid tx rate specified\n"); 348662306a36Sopenharmony_ci ret = -EINVAL; 348762306a36Sopenharmony_ci } 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci return ret; 349062306a36Sopenharmony_ci} 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_ci/** 349362306a36Sopenharmony_ci * iavf_validate_ch_config - validate queue mapping info 349462306a36Sopenharmony_ci * @adapter: board private structure 349562306a36Sopenharmony_ci * @mqprio_qopt: queue parameters 349662306a36Sopenharmony_ci * 349762306a36Sopenharmony_ci * This function validates if the config provided by the user to 349862306a36Sopenharmony_ci * configure queue channels is valid or not. Returns 0 on a valid 349962306a36Sopenharmony_ci * config. 350062306a36Sopenharmony_ci **/ 350162306a36Sopenharmony_cistatic int iavf_validate_ch_config(struct iavf_adapter *adapter, 350262306a36Sopenharmony_ci struct tc_mqprio_qopt_offload *mqprio_qopt) 350362306a36Sopenharmony_ci{ 350462306a36Sopenharmony_ci u64 total_max_rate = 0; 350562306a36Sopenharmony_ci u32 tx_rate_rem = 0; 350662306a36Sopenharmony_ci int i, num_qps = 0; 350762306a36Sopenharmony_ci u64 tx_rate = 0; 350862306a36Sopenharmony_ci int ret = 0; 350962306a36Sopenharmony_ci 351062306a36Sopenharmony_ci if (mqprio_qopt->qopt.num_tc > IAVF_MAX_TRAFFIC_CLASS || 351162306a36Sopenharmony_ci mqprio_qopt->qopt.num_tc < 1) 351262306a36Sopenharmony_ci return -EINVAL; 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci for (i = 0; i <= mqprio_qopt->qopt.num_tc - 1; i++) { 351562306a36Sopenharmony_ci if (!mqprio_qopt->qopt.count[i] || 351662306a36Sopenharmony_ci mqprio_qopt->qopt.offset[i] != num_qps) 351762306a36Sopenharmony_ci return -EINVAL; 351862306a36Sopenharmony_ci if (mqprio_qopt->min_rate[i]) { 351962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 352062306a36Sopenharmony_ci "Invalid min tx rate (greater than 0) specified for TC%d\n", 352162306a36Sopenharmony_ci i); 352262306a36Sopenharmony_ci return -EINVAL; 352362306a36Sopenharmony_ci } 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_ci /* convert to Mbps */ 352662306a36Sopenharmony_ci tx_rate = div_u64(mqprio_qopt->max_rate[i], 352762306a36Sopenharmony_ci IAVF_MBPS_DIVISOR); 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci if (mqprio_qopt->max_rate[i] && 353062306a36Sopenharmony_ci tx_rate < IAVF_MBPS_QUANTA) { 353162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 353262306a36Sopenharmony_ci "Invalid max tx rate for TC%d, minimum %dMbps\n", 353362306a36Sopenharmony_ci i, IAVF_MBPS_QUANTA); 353462306a36Sopenharmony_ci return -EINVAL; 353562306a36Sopenharmony_ci } 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci (void)div_u64_rem(tx_rate, IAVF_MBPS_QUANTA, &tx_rate_rem); 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_ci if (tx_rate_rem != 0) { 354062306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 354162306a36Sopenharmony_ci "Invalid max tx rate for TC%d, not divisible by %d\n", 354262306a36Sopenharmony_ci i, IAVF_MBPS_QUANTA); 354362306a36Sopenharmony_ci return -EINVAL; 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci total_max_rate += tx_rate; 354762306a36Sopenharmony_ci num_qps += mqprio_qopt->qopt.count[i]; 354862306a36Sopenharmony_ci } 354962306a36Sopenharmony_ci if (num_qps > adapter->num_active_queues) { 355062306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 355162306a36Sopenharmony_ci "Cannot support requested number of queues\n"); 355262306a36Sopenharmony_ci return -EINVAL; 355362306a36Sopenharmony_ci } 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci ret = iavf_validate_tx_bandwidth(adapter, total_max_rate); 355662306a36Sopenharmony_ci return ret; 355762306a36Sopenharmony_ci} 355862306a36Sopenharmony_ci 355962306a36Sopenharmony_ci/** 356062306a36Sopenharmony_ci * iavf_del_all_cloud_filters - delete all cloud filters on the traffic classes 356162306a36Sopenharmony_ci * @adapter: board private structure 356262306a36Sopenharmony_ci **/ 356362306a36Sopenharmony_cistatic void iavf_del_all_cloud_filters(struct iavf_adapter *adapter) 356462306a36Sopenharmony_ci{ 356562306a36Sopenharmony_ci struct iavf_cloud_filter *cf, *cftmp; 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 356862306a36Sopenharmony_ci list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, 356962306a36Sopenharmony_ci list) { 357062306a36Sopenharmony_ci list_del(&cf->list); 357162306a36Sopenharmony_ci kfree(cf); 357262306a36Sopenharmony_ci adapter->num_cloud_filters--; 357362306a36Sopenharmony_ci } 357462306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 357562306a36Sopenharmony_ci} 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci/** 357862306a36Sopenharmony_ci * __iavf_setup_tc - configure multiple traffic classes 357962306a36Sopenharmony_ci * @netdev: network interface device structure 358062306a36Sopenharmony_ci * @type_data: tc offload data 358162306a36Sopenharmony_ci * 358262306a36Sopenharmony_ci * This function processes the config information provided by the 358362306a36Sopenharmony_ci * user to configure traffic classes/queue channels and packages the 358462306a36Sopenharmony_ci * information to request the PF to setup traffic classes. 358562306a36Sopenharmony_ci * 358662306a36Sopenharmony_ci * Returns 0 on success. 358762306a36Sopenharmony_ci **/ 358862306a36Sopenharmony_cistatic int __iavf_setup_tc(struct net_device *netdev, void *type_data) 358962306a36Sopenharmony_ci{ 359062306a36Sopenharmony_ci struct tc_mqprio_qopt_offload *mqprio_qopt = type_data; 359162306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 359262306a36Sopenharmony_ci struct virtchnl_vf_resource *vfres = adapter->vf_res; 359362306a36Sopenharmony_ci u8 num_tc = 0, total_qps = 0; 359462306a36Sopenharmony_ci int ret = 0, netdev_tc = 0; 359562306a36Sopenharmony_ci u64 max_tx_rate; 359662306a36Sopenharmony_ci u16 mode; 359762306a36Sopenharmony_ci int i; 359862306a36Sopenharmony_ci 359962306a36Sopenharmony_ci num_tc = mqprio_qopt->qopt.num_tc; 360062306a36Sopenharmony_ci mode = mqprio_qopt->mode; 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci /* delete queue_channel */ 360362306a36Sopenharmony_ci if (!mqprio_qopt->qopt.hw) { 360462306a36Sopenharmony_ci if (adapter->ch_config.state == __IAVF_TC_RUNNING) { 360562306a36Sopenharmony_ci /* reset the tc configuration */ 360662306a36Sopenharmony_ci netdev_reset_tc(netdev); 360762306a36Sopenharmony_ci adapter->num_tc = 0; 360862306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 360962306a36Sopenharmony_ci netif_tx_disable(netdev); 361062306a36Sopenharmony_ci iavf_del_all_cloud_filters(adapter); 361162306a36Sopenharmony_ci adapter->aq_required = IAVF_FLAG_AQ_DISABLE_CHANNELS; 361262306a36Sopenharmony_ci total_qps = adapter->orig_num_active_queues; 361362306a36Sopenharmony_ci goto exit; 361462306a36Sopenharmony_ci } else { 361562306a36Sopenharmony_ci return -EINVAL; 361662306a36Sopenharmony_ci } 361762306a36Sopenharmony_ci } 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci /* add queue channel */ 362062306a36Sopenharmony_ci if (mode == TC_MQPRIO_MODE_CHANNEL) { 362162306a36Sopenharmony_ci if (!(vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ)) { 362262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "ADq not supported\n"); 362362306a36Sopenharmony_ci return -EOPNOTSUPP; 362462306a36Sopenharmony_ci } 362562306a36Sopenharmony_ci if (adapter->ch_config.state != __IAVF_TC_INVALID) { 362662306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "TC configuration already exists\n"); 362762306a36Sopenharmony_ci return -EINVAL; 362862306a36Sopenharmony_ci } 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci ret = iavf_validate_ch_config(adapter, mqprio_qopt); 363162306a36Sopenharmony_ci if (ret) 363262306a36Sopenharmony_ci return ret; 363362306a36Sopenharmony_ci /* Return if same TC config is requested */ 363462306a36Sopenharmony_ci if (adapter->num_tc == num_tc) 363562306a36Sopenharmony_ci return 0; 363662306a36Sopenharmony_ci adapter->num_tc = num_tc; 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci for (i = 0; i < IAVF_MAX_TRAFFIC_CLASS; i++) { 363962306a36Sopenharmony_ci if (i < num_tc) { 364062306a36Sopenharmony_ci adapter->ch_config.ch_info[i].count = 364162306a36Sopenharmony_ci mqprio_qopt->qopt.count[i]; 364262306a36Sopenharmony_ci adapter->ch_config.ch_info[i].offset = 364362306a36Sopenharmony_ci mqprio_qopt->qopt.offset[i]; 364462306a36Sopenharmony_ci total_qps += mqprio_qopt->qopt.count[i]; 364562306a36Sopenharmony_ci max_tx_rate = mqprio_qopt->max_rate[i]; 364662306a36Sopenharmony_ci /* convert to Mbps */ 364762306a36Sopenharmony_ci max_tx_rate = div_u64(max_tx_rate, 364862306a36Sopenharmony_ci IAVF_MBPS_DIVISOR); 364962306a36Sopenharmony_ci adapter->ch_config.ch_info[i].max_tx_rate = 365062306a36Sopenharmony_ci max_tx_rate; 365162306a36Sopenharmony_ci } else { 365262306a36Sopenharmony_ci adapter->ch_config.ch_info[i].count = 1; 365362306a36Sopenharmony_ci adapter->ch_config.ch_info[i].offset = 0; 365462306a36Sopenharmony_ci } 365562306a36Sopenharmony_ci } 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci /* Take snapshot of original config such as "num_active_queues" 365862306a36Sopenharmony_ci * It is used later when delete ADQ flow is exercised, so that 365962306a36Sopenharmony_ci * once delete ADQ flow completes, VF shall go back to its 366062306a36Sopenharmony_ci * original queue configuration 366162306a36Sopenharmony_ci */ 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci adapter->orig_num_active_queues = adapter->num_active_queues; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci /* Store queue info based on TC so that VF gets configured 366662306a36Sopenharmony_ci * with correct number of queues when VF completes ADQ config 366762306a36Sopenharmony_ci * flow 366862306a36Sopenharmony_ci */ 366962306a36Sopenharmony_ci adapter->ch_config.total_qps = total_qps; 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 367262306a36Sopenharmony_ci netif_tx_disable(netdev); 367362306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_CHANNELS; 367462306a36Sopenharmony_ci netdev_reset_tc(netdev); 367562306a36Sopenharmony_ci /* Report the tc mapping up the stack */ 367662306a36Sopenharmony_ci netdev_set_num_tc(adapter->netdev, num_tc); 367762306a36Sopenharmony_ci for (i = 0; i < IAVF_MAX_TRAFFIC_CLASS; i++) { 367862306a36Sopenharmony_ci u16 qcount = mqprio_qopt->qopt.count[i]; 367962306a36Sopenharmony_ci u16 qoffset = mqprio_qopt->qopt.offset[i]; 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_ci if (i < num_tc) 368262306a36Sopenharmony_ci netdev_set_tc_queue(netdev, netdev_tc++, qcount, 368362306a36Sopenharmony_ci qoffset); 368462306a36Sopenharmony_ci } 368562306a36Sopenharmony_ci } 368662306a36Sopenharmony_ciexit: 368762306a36Sopenharmony_ci if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) 368862306a36Sopenharmony_ci return 0; 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci netif_set_real_num_rx_queues(netdev, total_qps); 369162306a36Sopenharmony_ci netif_set_real_num_tx_queues(netdev, total_qps); 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci return ret; 369462306a36Sopenharmony_ci} 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci/** 369762306a36Sopenharmony_ci * iavf_parse_cls_flower - Parse tc flower filters provided by kernel 369862306a36Sopenharmony_ci * @adapter: board private structure 369962306a36Sopenharmony_ci * @f: pointer to struct flow_cls_offload 370062306a36Sopenharmony_ci * @filter: pointer to cloud filter structure 370162306a36Sopenharmony_ci */ 370262306a36Sopenharmony_cistatic int iavf_parse_cls_flower(struct iavf_adapter *adapter, 370362306a36Sopenharmony_ci struct flow_cls_offload *f, 370462306a36Sopenharmony_ci struct iavf_cloud_filter *filter) 370562306a36Sopenharmony_ci{ 370662306a36Sopenharmony_ci struct flow_rule *rule = flow_cls_offload_flow_rule(f); 370762306a36Sopenharmony_ci struct flow_dissector *dissector = rule->match.dissector; 370862306a36Sopenharmony_ci u16 n_proto_mask = 0; 370962306a36Sopenharmony_ci u16 n_proto_key = 0; 371062306a36Sopenharmony_ci u8 field_flags = 0; 371162306a36Sopenharmony_ci u16 addr_type = 0; 371262306a36Sopenharmony_ci u16 n_proto = 0; 371362306a36Sopenharmony_ci int i = 0; 371462306a36Sopenharmony_ci struct virtchnl_filter *vf = &filter->f; 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci if (dissector->used_keys & 371762306a36Sopenharmony_ci ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) | 371862306a36Sopenharmony_ci BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) | 371962306a36Sopenharmony_ci BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 372062306a36Sopenharmony_ci BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) | 372162306a36Sopenharmony_ci BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 372262306a36Sopenharmony_ci BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 372362306a36Sopenharmony_ci BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) | 372462306a36Sopenharmony_ci BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID))) { 372562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Unsupported key used: 0x%llx\n", 372662306a36Sopenharmony_ci dissector->used_keys); 372762306a36Sopenharmony_ci return -EOPNOTSUPP; 372862306a36Sopenharmony_ci } 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) { 373162306a36Sopenharmony_ci struct flow_match_enc_keyid match; 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci flow_rule_match_enc_keyid(rule, &match); 373462306a36Sopenharmony_ci if (match.mask->keyid != 0) 373562306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_TEN_ID; 373662306a36Sopenharmony_ci } 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_ci if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { 373962306a36Sopenharmony_ci struct flow_match_basic match; 374062306a36Sopenharmony_ci 374162306a36Sopenharmony_ci flow_rule_match_basic(rule, &match); 374262306a36Sopenharmony_ci n_proto_key = ntohs(match.key->n_proto); 374362306a36Sopenharmony_ci n_proto_mask = ntohs(match.mask->n_proto); 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci if (n_proto_key == ETH_P_ALL) { 374662306a36Sopenharmony_ci n_proto_key = 0; 374762306a36Sopenharmony_ci n_proto_mask = 0; 374862306a36Sopenharmony_ci } 374962306a36Sopenharmony_ci n_proto = n_proto_key & n_proto_mask; 375062306a36Sopenharmony_ci if (n_proto != ETH_P_IP && n_proto != ETH_P_IPV6) 375162306a36Sopenharmony_ci return -EINVAL; 375262306a36Sopenharmony_ci if (n_proto == ETH_P_IPV6) { 375362306a36Sopenharmony_ci /* specify flow type as TCP IPv6 */ 375462306a36Sopenharmony_ci vf->flow_type = VIRTCHNL_TCP_V6_FLOW; 375562306a36Sopenharmony_ci } 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci if (match.key->ip_proto != IPPROTO_TCP) { 375862306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Only TCP transport is supported\n"); 375962306a36Sopenharmony_ci return -EINVAL; 376062306a36Sopenharmony_ci } 376162306a36Sopenharmony_ci } 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 376462306a36Sopenharmony_ci struct flow_match_eth_addrs match; 376562306a36Sopenharmony_ci 376662306a36Sopenharmony_ci flow_rule_match_eth_addrs(rule, &match); 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci /* use is_broadcast and is_zero to check for all 0xf or 0 */ 376962306a36Sopenharmony_ci if (!is_zero_ether_addr(match.mask->dst)) { 377062306a36Sopenharmony_ci if (is_broadcast_ether_addr(match.mask->dst)) { 377162306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_OMAC; 377262306a36Sopenharmony_ci } else { 377362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad ether dest mask %pM\n", 377462306a36Sopenharmony_ci match.mask->dst); 377562306a36Sopenharmony_ci return -EINVAL; 377662306a36Sopenharmony_ci } 377762306a36Sopenharmony_ci } 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci if (!is_zero_ether_addr(match.mask->src)) { 378062306a36Sopenharmony_ci if (is_broadcast_ether_addr(match.mask->src)) { 378162306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_IMAC; 378262306a36Sopenharmony_ci } else { 378362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad ether src mask %pM\n", 378462306a36Sopenharmony_ci match.mask->src); 378562306a36Sopenharmony_ci return -EINVAL; 378662306a36Sopenharmony_ci } 378762306a36Sopenharmony_ci } 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci if (!is_zero_ether_addr(match.key->dst)) 379062306a36Sopenharmony_ci if (is_valid_ether_addr(match.key->dst) || 379162306a36Sopenharmony_ci is_multicast_ether_addr(match.key->dst)) { 379262306a36Sopenharmony_ci /* set the mask if a valid dst_mac address */ 379362306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 379462306a36Sopenharmony_ci vf->mask.tcp_spec.dst_mac[i] |= 0xff; 379562306a36Sopenharmony_ci ether_addr_copy(vf->data.tcp_spec.dst_mac, 379662306a36Sopenharmony_ci match.key->dst); 379762306a36Sopenharmony_ci } 379862306a36Sopenharmony_ci 379962306a36Sopenharmony_ci if (!is_zero_ether_addr(match.key->src)) 380062306a36Sopenharmony_ci if (is_valid_ether_addr(match.key->src) || 380162306a36Sopenharmony_ci is_multicast_ether_addr(match.key->src)) { 380262306a36Sopenharmony_ci /* set the mask if a valid dst_mac address */ 380362306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 380462306a36Sopenharmony_ci vf->mask.tcp_spec.src_mac[i] |= 0xff; 380562306a36Sopenharmony_ci ether_addr_copy(vf->data.tcp_spec.src_mac, 380662306a36Sopenharmony_ci match.key->src); 380762306a36Sopenharmony_ci } 380862306a36Sopenharmony_ci } 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 381162306a36Sopenharmony_ci struct flow_match_vlan match; 381262306a36Sopenharmony_ci 381362306a36Sopenharmony_ci flow_rule_match_vlan(rule, &match); 381462306a36Sopenharmony_ci if (match.mask->vlan_id) { 381562306a36Sopenharmony_ci if (match.mask->vlan_id == VLAN_VID_MASK) { 381662306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_IVLAN; 381762306a36Sopenharmony_ci } else { 381862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad vlan mask %u\n", 381962306a36Sopenharmony_ci match.mask->vlan_id); 382062306a36Sopenharmony_ci return -EINVAL; 382162306a36Sopenharmony_ci } 382262306a36Sopenharmony_ci } 382362306a36Sopenharmony_ci vf->mask.tcp_spec.vlan_id |= cpu_to_be16(0xffff); 382462306a36Sopenharmony_ci vf->data.tcp_spec.vlan_id = cpu_to_be16(match.key->vlan_id); 382562306a36Sopenharmony_ci } 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { 382862306a36Sopenharmony_ci struct flow_match_control match; 382962306a36Sopenharmony_ci 383062306a36Sopenharmony_ci flow_rule_match_control(rule, &match); 383162306a36Sopenharmony_ci addr_type = match.key->addr_type; 383262306a36Sopenharmony_ci } 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 383562306a36Sopenharmony_ci struct flow_match_ipv4_addrs match; 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci flow_rule_match_ipv4_addrs(rule, &match); 383862306a36Sopenharmony_ci if (match.mask->dst) { 383962306a36Sopenharmony_ci if (match.mask->dst == cpu_to_be32(0xffffffff)) { 384062306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_IIP; 384162306a36Sopenharmony_ci } else { 384262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad ip dst mask 0x%08x\n", 384362306a36Sopenharmony_ci be32_to_cpu(match.mask->dst)); 384462306a36Sopenharmony_ci return -EINVAL; 384562306a36Sopenharmony_ci } 384662306a36Sopenharmony_ci } 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_ci if (match.mask->src) { 384962306a36Sopenharmony_ci if (match.mask->src == cpu_to_be32(0xffffffff)) { 385062306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_IIP; 385162306a36Sopenharmony_ci } else { 385262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n", 385362306a36Sopenharmony_ci be32_to_cpu(match.mask->src)); 385462306a36Sopenharmony_ci return -EINVAL; 385562306a36Sopenharmony_ci } 385662306a36Sopenharmony_ci } 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci if (field_flags & IAVF_CLOUD_FIELD_TEN_ID) { 385962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Tenant id not allowed for ip filter\n"); 386062306a36Sopenharmony_ci return -EINVAL; 386162306a36Sopenharmony_ci } 386262306a36Sopenharmony_ci if (match.key->dst) { 386362306a36Sopenharmony_ci vf->mask.tcp_spec.dst_ip[0] |= cpu_to_be32(0xffffffff); 386462306a36Sopenharmony_ci vf->data.tcp_spec.dst_ip[0] = match.key->dst; 386562306a36Sopenharmony_ci } 386662306a36Sopenharmony_ci if (match.key->src) { 386762306a36Sopenharmony_ci vf->mask.tcp_spec.src_ip[0] |= cpu_to_be32(0xffffffff); 386862306a36Sopenharmony_ci vf->data.tcp_spec.src_ip[0] = match.key->src; 386962306a36Sopenharmony_ci } 387062306a36Sopenharmony_ci } 387162306a36Sopenharmony_ci 387262306a36Sopenharmony_ci if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 387362306a36Sopenharmony_ci struct flow_match_ipv6_addrs match; 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci flow_rule_match_ipv6_addrs(rule, &match); 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci /* validate mask, make sure it is not IPV6_ADDR_ANY */ 387862306a36Sopenharmony_ci if (ipv6_addr_any(&match.mask->dst)) { 387962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad ipv6 dst mask 0x%02x\n", 388062306a36Sopenharmony_ci IPV6_ADDR_ANY); 388162306a36Sopenharmony_ci return -EINVAL; 388262306a36Sopenharmony_ci } 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci /* src and dest IPv6 address should not be LOOPBACK 388562306a36Sopenharmony_ci * (0:0:0:0:0:0:0:1) which can be represented as ::1 388662306a36Sopenharmony_ci */ 388762306a36Sopenharmony_ci if (ipv6_addr_loopback(&match.key->dst) || 388862306a36Sopenharmony_ci ipv6_addr_loopback(&match.key->src)) { 388962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 389062306a36Sopenharmony_ci "ipv6 addr should not be loopback\n"); 389162306a36Sopenharmony_ci return -EINVAL; 389262306a36Sopenharmony_ci } 389362306a36Sopenharmony_ci if (!ipv6_addr_any(&match.mask->dst) || 389462306a36Sopenharmony_ci !ipv6_addr_any(&match.mask->src)) 389562306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_IIP; 389662306a36Sopenharmony_ci 389762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 389862306a36Sopenharmony_ci vf->mask.tcp_spec.dst_ip[i] |= cpu_to_be32(0xffffffff); 389962306a36Sopenharmony_ci memcpy(&vf->data.tcp_spec.dst_ip, &match.key->dst.s6_addr32, 390062306a36Sopenharmony_ci sizeof(vf->data.tcp_spec.dst_ip)); 390162306a36Sopenharmony_ci for (i = 0; i < 4; i++) 390262306a36Sopenharmony_ci vf->mask.tcp_spec.src_ip[i] |= cpu_to_be32(0xffffffff); 390362306a36Sopenharmony_ci memcpy(&vf->data.tcp_spec.src_ip, &match.key->src.s6_addr32, 390462306a36Sopenharmony_ci sizeof(vf->data.tcp_spec.src_ip)); 390562306a36Sopenharmony_ci } 390662306a36Sopenharmony_ci if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { 390762306a36Sopenharmony_ci struct flow_match_ports match; 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci flow_rule_match_ports(rule, &match); 391062306a36Sopenharmony_ci if (match.mask->src) { 391162306a36Sopenharmony_ci if (match.mask->src == cpu_to_be16(0xffff)) { 391262306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_IIP; 391362306a36Sopenharmony_ci } else { 391462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad src port mask %u\n", 391562306a36Sopenharmony_ci be16_to_cpu(match.mask->src)); 391662306a36Sopenharmony_ci return -EINVAL; 391762306a36Sopenharmony_ci } 391862306a36Sopenharmony_ci } 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci if (match.mask->dst) { 392162306a36Sopenharmony_ci if (match.mask->dst == cpu_to_be16(0xffff)) { 392262306a36Sopenharmony_ci field_flags |= IAVF_CLOUD_FIELD_IIP; 392362306a36Sopenharmony_ci } else { 392462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Bad dst port mask %u\n", 392562306a36Sopenharmony_ci be16_to_cpu(match.mask->dst)); 392662306a36Sopenharmony_ci return -EINVAL; 392762306a36Sopenharmony_ci } 392862306a36Sopenharmony_ci } 392962306a36Sopenharmony_ci if (match.key->dst) { 393062306a36Sopenharmony_ci vf->mask.tcp_spec.dst_port |= cpu_to_be16(0xffff); 393162306a36Sopenharmony_ci vf->data.tcp_spec.dst_port = match.key->dst; 393262306a36Sopenharmony_ci } 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ci if (match.key->src) { 393562306a36Sopenharmony_ci vf->mask.tcp_spec.src_port |= cpu_to_be16(0xffff); 393662306a36Sopenharmony_ci vf->data.tcp_spec.src_port = match.key->src; 393762306a36Sopenharmony_ci } 393862306a36Sopenharmony_ci } 393962306a36Sopenharmony_ci vf->field_flags = field_flags; 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ci return 0; 394262306a36Sopenharmony_ci} 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci/** 394562306a36Sopenharmony_ci * iavf_handle_tclass - Forward to a traffic class on the device 394662306a36Sopenharmony_ci * @adapter: board private structure 394762306a36Sopenharmony_ci * @tc: traffic class index on the device 394862306a36Sopenharmony_ci * @filter: pointer to cloud filter structure 394962306a36Sopenharmony_ci */ 395062306a36Sopenharmony_cistatic int iavf_handle_tclass(struct iavf_adapter *adapter, u32 tc, 395162306a36Sopenharmony_ci struct iavf_cloud_filter *filter) 395262306a36Sopenharmony_ci{ 395362306a36Sopenharmony_ci if (tc == 0) 395462306a36Sopenharmony_ci return 0; 395562306a36Sopenharmony_ci if (tc < adapter->num_tc) { 395662306a36Sopenharmony_ci if (!filter->f.data.tcp_spec.dst_port) { 395762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 395862306a36Sopenharmony_ci "Specify destination port to redirect to traffic class other than TC0\n"); 395962306a36Sopenharmony_ci return -EINVAL; 396062306a36Sopenharmony_ci } 396162306a36Sopenharmony_ci } 396262306a36Sopenharmony_ci /* redirect to a traffic class on the same device */ 396362306a36Sopenharmony_ci filter->f.action = VIRTCHNL_ACTION_TC_REDIRECT; 396462306a36Sopenharmony_ci filter->f.action_meta = tc; 396562306a36Sopenharmony_ci return 0; 396662306a36Sopenharmony_ci} 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci/** 396962306a36Sopenharmony_ci * iavf_find_cf - Find the cloud filter in the list 397062306a36Sopenharmony_ci * @adapter: Board private structure 397162306a36Sopenharmony_ci * @cookie: filter specific cookie 397262306a36Sopenharmony_ci * 397362306a36Sopenharmony_ci * Returns ptr to the filter object or NULL. Must be called while holding the 397462306a36Sopenharmony_ci * cloud_filter_list_lock. 397562306a36Sopenharmony_ci */ 397662306a36Sopenharmony_cistatic struct iavf_cloud_filter *iavf_find_cf(struct iavf_adapter *adapter, 397762306a36Sopenharmony_ci unsigned long *cookie) 397862306a36Sopenharmony_ci{ 397962306a36Sopenharmony_ci struct iavf_cloud_filter *filter = NULL; 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci if (!cookie) 398262306a36Sopenharmony_ci return NULL; 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci list_for_each_entry(filter, &adapter->cloud_filter_list, list) { 398562306a36Sopenharmony_ci if (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie))) 398662306a36Sopenharmony_ci return filter; 398762306a36Sopenharmony_ci } 398862306a36Sopenharmony_ci return NULL; 398962306a36Sopenharmony_ci} 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci/** 399262306a36Sopenharmony_ci * iavf_configure_clsflower - Add tc flower filters 399362306a36Sopenharmony_ci * @adapter: board private structure 399462306a36Sopenharmony_ci * @cls_flower: Pointer to struct flow_cls_offload 399562306a36Sopenharmony_ci */ 399662306a36Sopenharmony_cistatic int iavf_configure_clsflower(struct iavf_adapter *adapter, 399762306a36Sopenharmony_ci struct flow_cls_offload *cls_flower) 399862306a36Sopenharmony_ci{ 399962306a36Sopenharmony_ci int tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid); 400062306a36Sopenharmony_ci struct iavf_cloud_filter *filter = NULL; 400162306a36Sopenharmony_ci int err = -EINVAL, count = 50; 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_ci if (tc < 0) { 400462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Invalid traffic class\n"); 400562306a36Sopenharmony_ci return -EINVAL; 400662306a36Sopenharmony_ci } 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci filter = kzalloc(sizeof(*filter), GFP_KERNEL); 400962306a36Sopenharmony_ci if (!filter) 401062306a36Sopenharmony_ci return -ENOMEM; 401162306a36Sopenharmony_ci 401262306a36Sopenharmony_ci while (!mutex_trylock(&adapter->crit_lock)) { 401362306a36Sopenharmony_ci if (--count == 0) { 401462306a36Sopenharmony_ci kfree(filter); 401562306a36Sopenharmony_ci return err; 401662306a36Sopenharmony_ci } 401762306a36Sopenharmony_ci udelay(1); 401862306a36Sopenharmony_ci } 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci filter->cookie = cls_flower->cookie; 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_ci /* bail out here if filter already exists */ 402362306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 402462306a36Sopenharmony_ci if (iavf_find_cf(adapter, &cls_flower->cookie)) { 402562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Failed to add TC Flower filter, it already exists\n"); 402662306a36Sopenharmony_ci err = -EEXIST; 402762306a36Sopenharmony_ci goto spin_unlock; 402862306a36Sopenharmony_ci } 402962306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 403062306a36Sopenharmony_ci 403162306a36Sopenharmony_ci /* set the mask to all zeroes to begin with */ 403262306a36Sopenharmony_ci memset(&filter->f.mask.tcp_spec, 0, sizeof(struct virtchnl_l4_spec)); 403362306a36Sopenharmony_ci /* start out with flow type and eth type IPv4 to begin with */ 403462306a36Sopenharmony_ci filter->f.flow_type = VIRTCHNL_TCP_V4_FLOW; 403562306a36Sopenharmony_ci err = iavf_parse_cls_flower(adapter, cls_flower, filter); 403662306a36Sopenharmony_ci if (err) 403762306a36Sopenharmony_ci goto err; 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci err = iavf_handle_tclass(adapter, tc, filter); 404062306a36Sopenharmony_ci if (err) 404162306a36Sopenharmony_ci goto err; 404262306a36Sopenharmony_ci 404362306a36Sopenharmony_ci /* add filter to the list */ 404462306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 404562306a36Sopenharmony_ci list_add_tail(&filter->list, &adapter->cloud_filter_list); 404662306a36Sopenharmony_ci adapter->num_cloud_filters++; 404762306a36Sopenharmony_ci filter->add = true; 404862306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER; 404962306a36Sopenharmony_cispin_unlock: 405062306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 405162306a36Sopenharmony_cierr: 405262306a36Sopenharmony_ci if (err) 405362306a36Sopenharmony_ci kfree(filter); 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 405662306a36Sopenharmony_ci return err; 405762306a36Sopenharmony_ci} 405862306a36Sopenharmony_ci 405962306a36Sopenharmony_ci/** 406062306a36Sopenharmony_ci * iavf_delete_clsflower - Remove tc flower filters 406162306a36Sopenharmony_ci * @adapter: board private structure 406262306a36Sopenharmony_ci * @cls_flower: Pointer to struct flow_cls_offload 406362306a36Sopenharmony_ci */ 406462306a36Sopenharmony_cistatic int iavf_delete_clsflower(struct iavf_adapter *adapter, 406562306a36Sopenharmony_ci struct flow_cls_offload *cls_flower) 406662306a36Sopenharmony_ci{ 406762306a36Sopenharmony_ci struct iavf_cloud_filter *filter = NULL; 406862306a36Sopenharmony_ci int err = 0; 406962306a36Sopenharmony_ci 407062306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 407162306a36Sopenharmony_ci filter = iavf_find_cf(adapter, &cls_flower->cookie); 407262306a36Sopenharmony_ci if (filter) { 407362306a36Sopenharmony_ci filter->del = true; 407462306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; 407562306a36Sopenharmony_ci } else { 407662306a36Sopenharmony_ci err = -EINVAL; 407762306a36Sopenharmony_ci } 407862306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 407962306a36Sopenharmony_ci 408062306a36Sopenharmony_ci return err; 408162306a36Sopenharmony_ci} 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ci/** 408462306a36Sopenharmony_ci * iavf_setup_tc_cls_flower - flower classifier offloads 408562306a36Sopenharmony_ci * @adapter: board private structure 408662306a36Sopenharmony_ci * @cls_flower: pointer to flow_cls_offload struct with flow info 408762306a36Sopenharmony_ci */ 408862306a36Sopenharmony_cistatic int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter, 408962306a36Sopenharmony_ci struct flow_cls_offload *cls_flower) 409062306a36Sopenharmony_ci{ 409162306a36Sopenharmony_ci switch (cls_flower->command) { 409262306a36Sopenharmony_ci case FLOW_CLS_REPLACE: 409362306a36Sopenharmony_ci return iavf_configure_clsflower(adapter, cls_flower); 409462306a36Sopenharmony_ci case FLOW_CLS_DESTROY: 409562306a36Sopenharmony_ci return iavf_delete_clsflower(adapter, cls_flower); 409662306a36Sopenharmony_ci case FLOW_CLS_STATS: 409762306a36Sopenharmony_ci return -EOPNOTSUPP; 409862306a36Sopenharmony_ci default: 409962306a36Sopenharmony_ci return -EOPNOTSUPP; 410062306a36Sopenharmony_ci } 410162306a36Sopenharmony_ci} 410262306a36Sopenharmony_ci 410362306a36Sopenharmony_ci/** 410462306a36Sopenharmony_ci * iavf_setup_tc_block_cb - block callback for tc 410562306a36Sopenharmony_ci * @type: type of offload 410662306a36Sopenharmony_ci * @type_data: offload data 410762306a36Sopenharmony_ci * @cb_priv: 410862306a36Sopenharmony_ci * 410962306a36Sopenharmony_ci * This function is the block callback for traffic classes 411062306a36Sopenharmony_ci **/ 411162306a36Sopenharmony_cistatic int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data, 411262306a36Sopenharmony_ci void *cb_priv) 411362306a36Sopenharmony_ci{ 411462306a36Sopenharmony_ci struct iavf_adapter *adapter = cb_priv; 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci if (!tc_cls_can_offload_and_chain0(adapter->netdev, type_data)) 411762306a36Sopenharmony_ci return -EOPNOTSUPP; 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_ci switch (type) { 412062306a36Sopenharmony_ci case TC_SETUP_CLSFLOWER: 412162306a36Sopenharmony_ci return iavf_setup_tc_cls_flower(cb_priv, type_data); 412262306a36Sopenharmony_ci default: 412362306a36Sopenharmony_ci return -EOPNOTSUPP; 412462306a36Sopenharmony_ci } 412562306a36Sopenharmony_ci} 412662306a36Sopenharmony_ci 412762306a36Sopenharmony_cistatic LIST_HEAD(iavf_block_cb_list); 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ci/** 413062306a36Sopenharmony_ci * iavf_setup_tc - configure multiple traffic classes 413162306a36Sopenharmony_ci * @netdev: network interface device structure 413262306a36Sopenharmony_ci * @type: type of offload 413362306a36Sopenharmony_ci * @type_data: tc offload data 413462306a36Sopenharmony_ci * 413562306a36Sopenharmony_ci * This function is the callback to ndo_setup_tc in the 413662306a36Sopenharmony_ci * netdev_ops. 413762306a36Sopenharmony_ci * 413862306a36Sopenharmony_ci * Returns 0 on success 413962306a36Sopenharmony_ci **/ 414062306a36Sopenharmony_cistatic int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type, 414162306a36Sopenharmony_ci void *type_data) 414262306a36Sopenharmony_ci{ 414362306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci switch (type) { 414662306a36Sopenharmony_ci case TC_SETUP_QDISC_MQPRIO: 414762306a36Sopenharmony_ci return __iavf_setup_tc(netdev, type_data); 414862306a36Sopenharmony_ci case TC_SETUP_BLOCK: 414962306a36Sopenharmony_ci return flow_block_cb_setup_simple(type_data, 415062306a36Sopenharmony_ci &iavf_block_cb_list, 415162306a36Sopenharmony_ci iavf_setup_tc_block_cb, 415262306a36Sopenharmony_ci adapter, adapter, true); 415362306a36Sopenharmony_ci default: 415462306a36Sopenharmony_ci return -EOPNOTSUPP; 415562306a36Sopenharmony_ci } 415662306a36Sopenharmony_ci} 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ci/** 415962306a36Sopenharmony_ci * iavf_restore_fdir_filters 416062306a36Sopenharmony_ci * @adapter: board private structure 416162306a36Sopenharmony_ci * 416262306a36Sopenharmony_ci * Restore existing FDIR filters when VF netdev comes back up. 416362306a36Sopenharmony_ci **/ 416462306a36Sopenharmony_cistatic void iavf_restore_fdir_filters(struct iavf_adapter *adapter) 416562306a36Sopenharmony_ci{ 416662306a36Sopenharmony_ci struct iavf_fdir_fltr *f; 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_ci spin_lock_bh(&adapter->fdir_fltr_lock); 416962306a36Sopenharmony_ci list_for_each_entry(f, &adapter->fdir_list_head, list) { 417062306a36Sopenharmony_ci if (f->state == IAVF_FDIR_FLTR_DIS_REQUEST) { 417162306a36Sopenharmony_ci /* Cancel a request, keep filter as active */ 417262306a36Sopenharmony_ci f->state = IAVF_FDIR_FLTR_ACTIVE; 417362306a36Sopenharmony_ci } else if (f->state == IAVF_FDIR_FLTR_DIS_PENDING || 417462306a36Sopenharmony_ci f->state == IAVF_FDIR_FLTR_INACTIVE) { 417562306a36Sopenharmony_ci /* Add filters which are inactive or have a pending 417662306a36Sopenharmony_ci * request to PF to be deleted 417762306a36Sopenharmony_ci */ 417862306a36Sopenharmony_ci f->state = IAVF_FDIR_FLTR_ADD_REQUEST; 417962306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER; 418062306a36Sopenharmony_ci } 418162306a36Sopenharmony_ci } 418262306a36Sopenharmony_ci spin_unlock_bh(&adapter->fdir_fltr_lock); 418362306a36Sopenharmony_ci} 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ci/** 418662306a36Sopenharmony_ci * iavf_open - Called when a network interface is made active 418762306a36Sopenharmony_ci * @netdev: network interface device structure 418862306a36Sopenharmony_ci * 418962306a36Sopenharmony_ci * Returns 0 on success, negative value on failure 419062306a36Sopenharmony_ci * 419162306a36Sopenharmony_ci * The open entry point is called when a network interface is made 419262306a36Sopenharmony_ci * active by the system (IFF_UP). At this point all resources needed 419362306a36Sopenharmony_ci * for transmit and receive operations are allocated, the interrupt 419462306a36Sopenharmony_ci * handler is registered with the OS, the watchdog is started, 419562306a36Sopenharmony_ci * and the stack is notified that the interface is ready. 419662306a36Sopenharmony_ci **/ 419762306a36Sopenharmony_cistatic int iavf_open(struct net_device *netdev) 419862306a36Sopenharmony_ci{ 419962306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 420062306a36Sopenharmony_ci int err; 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_ci if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) { 420362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n"); 420462306a36Sopenharmony_ci return -EIO; 420562306a36Sopenharmony_ci } 420662306a36Sopenharmony_ci 420762306a36Sopenharmony_ci while (!mutex_trylock(&adapter->crit_lock)) { 420862306a36Sopenharmony_ci /* If we are in __IAVF_INIT_CONFIG_ADAPTER state the crit_lock 420962306a36Sopenharmony_ci * is already taken and iavf_open is called from an upper 421062306a36Sopenharmony_ci * device's notifier reacting on NETDEV_REGISTER event. 421162306a36Sopenharmony_ci * We have to leave here to avoid dead lock. 421262306a36Sopenharmony_ci */ 421362306a36Sopenharmony_ci if (adapter->state == __IAVF_INIT_CONFIG_ADAPTER) 421462306a36Sopenharmony_ci return -EBUSY; 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ci usleep_range(500, 1000); 421762306a36Sopenharmony_ci } 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_ci if (adapter->state != __IAVF_DOWN) { 422062306a36Sopenharmony_ci err = -EBUSY; 422162306a36Sopenharmony_ci goto err_unlock; 422262306a36Sopenharmony_ci } 422362306a36Sopenharmony_ci 422462306a36Sopenharmony_ci if (adapter->state == __IAVF_RUNNING && 422562306a36Sopenharmony_ci !test_bit(__IAVF_VSI_DOWN, adapter->vsi.state)) { 422662306a36Sopenharmony_ci dev_dbg(&adapter->pdev->dev, "VF is already open.\n"); 422762306a36Sopenharmony_ci err = 0; 422862306a36Sopenharmony_ci goto err_unlock; 422962306a36Sopenharmony_ci } 423062306a36Sopenharmony_ci 423162306a36Sopenharmony_ci /* allocate transmit descriptors */ 423262306a36Sopenharmony_ci err = iavf_setup_all_tx_resources(adapter); 423362306a36Sopenharmony_ci if (err) 423462306a36Sopenharmony_ci goto err_setup_tx; 423562306a36Sopenharmony_ci 423662306a36Sopenharmony_ci /* allocate receive descriptors */ 423762306a36Sopenharmony_ci err = iavf_setup_all_rx_resources(adapter); 423862306a36Sopenharmony_ci if (err) 423962306a36Sopenharmony_ci goto err_setup_rx; 424062306a36Sopenharmony_ci 424162306a36Sopenharmony_ci /* clear any pending interrupts, may auto mask */ 424262306a36Sopenharmony_ci err = iavf_request_traffic_irqs(adapter, netdev->name); 424362306a36Sopenharmony_ci if (err) 424462306a36Sopenharmony_ci goto err_req_irq; 424562306a36Sopenharmony_ci 424662306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 424762306a36Sopenharmony_ci 424862306a36Sopenharmony_ci iavf_add_filter(adapter, adapter->hw.mac.addr); 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 425162306a36Sopenharmony_ci 425262306a36Sopenharmony_ci /* Restore filters that were removed with IFF_DOWN */ 425362306a36Sopenharmony_ci iavf_restore_filters(adapter); 425462306a36Sopenharmony_ci iavf_restore_fdir_filters(adapter); 425562306a36Sopenharmony_ci 425662306a36Sopenharmony_ci iavf_configure(adapter); 425762306a36Sopenharmony_ci 425862306a36Sopenharmony_ci iavf_up_complete(adapter); 425962306a36Sopenharmony_ci 426062306a36Sopenharmony_ci iavf_irq_enable(adapter, true); 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci return 0; 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_cierr_req_irq: 426762306a36Sopenharmony_ci iavf_down(adapter); 426862306a36Sopenharmony_ci iavf_free_traffic_irqs(adapter); 426962306a36Sopenharmony_cierr_setup_rx: 427062306a36Sopenharmony_ci iavf_free_all_rx_resources(adapter); 427162306a36Sopenharmony_cierr_setup_tx: 427262306a36Sopenharmony_ci iavf_free_all_tx_resources(adapter); 427362306a36Sopenharmony_cierr_unlock: 427462306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci return err; 427762306a36Sopenharmony_ci} 427862306a36Sopenharmony_ci 427962306a36Sopenharmony_ci/** 428062306a36Sopenharmony_ci * iavf_close - Disables a network interface 428162306a36Sopenharmony_ci * @netdev: network interface device structure 428262306a36Sopenharmony_ci * 428362306a36Sopenharmony_ci * Returns 0, this is not allowed to fail 428462306a36Sopenharmony_ci * 428562306a36Sopenharmony_ci * The close entry point is called when an interface is de-activated 428662306a36Sopenharmony_ci * by the OS. The hardware is still under the drivers control, but 428762306a36Sopenharmony_ci * needs to be disabled. All IRQs except vector 0 (reserved for admin queue) 428862306a36Sopenharmony_ci * are freed, along with all transmit and receive resources. 428962306a36Sopenharmony_ci **/ 429062306a36Sopenharmony_cistatic int iavf_close(struct net_device *netdev) 429162306a36Sopenharmony_ci{ 429262306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 429362306a36Sopenharmony_ci u64 aq_to_restore; 429462306a36Sopenharmony_ci int status; 429562306a36Sopenharmony_ci 429662306a36Sopenharmony_ci mutex_lock(&adapter->crit_lock); 429762306a36Sopenharmony_ci 429862306a36Sopenharmony_ci if (adapter->state <= __IAVF_DOWN_PENDING) { 429962306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 430062306a36Sopenharmony_ci return 0; 430162306a36Sopenharmony_ci } 430262306a36Sopenharmony_ci 430362306a36Sopenharmony_ci set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); 430462306a36Sopenharmony_ci if (CLIENT_ENABLED(adapter)) 430562306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_CLOSE; 430662306a36Sopenharmony_ci /* We cannot send IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS before 430762306a36Sopenharmony_ci * IAVF_FLAG_AQ_DISABLE_QUEUES because in such case there is rtnl 430862306a36Sopenharmony_ci * deadlock with adminq_task() until iavf_close timeouts. We must send 430962306a36Sopenharmony_ci * IAVF_FLAG_AQ_GET_CONFIG before IAVF_FLAG_AQ_DISABLE_QUEUES to make 431062306a36Sopenharmony_ci * disable queues possible for vf. Give only necessary flags to 431162306a36Sopenharmony_ci * iavf_down and save other to set them right before iavf_close() 431262306a36Sopenharmony_ci * returns, when IAVF_FLAG_AQ_DISABLE_QUEUES will be already sent and 431362306a36Sopenharmony_ci * iavf will be in DOWN state. 431462306a36Sopenharmony_ci */ 431562306a36Sopenharmony_ci aq_to_restore = adapter->aq_required; 431662306a36Sopenharmony_ci adapter->aq_required &= IAVF_FLAG_AQ_GET_CONFIG; 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci /* Remove flags which we do not want to send after close or we want to 431962306a36Sopenharmony_ci * send before disable queues. 432062306a36Sopenharmony_ci */ 432162306a36Sopenharmony_ci aq_to_restore &= ~(IAVF_FLAG_AQ_GET_CONFIG | 432262306a36Sopenharmony_ci IAVF_FLAG_AQ_ENABLE_QUEUES | 432362306a36Sopenharmony_ci IAVF_FLAG_AQ_CONFIGURE_QUEUES | 432462306a36Sopenharmony_ci IAVF_FLAG_AQ_ADD_VLAN_FILTER | 432562306a36Sopenharmony_ci IAVF_FLAG_AQ_ADD_MAC_FILTER | 432662306a36Sopenharmony_ci IAVF_FLAG_AQ_ADD_CLOUD_FILTER | 432762306a36Sopenharmony_ci IAVF_FLAG_AQ_ADD_FDIR_FILTER | 432862306a36Sopenharmony_ci IAVF_FLAG_AQ_ADD_ADV_RSS_CFG); 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci iavf_down(adapter); 433162306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_DOWN_PENDING); 433262306a36Sopenharmony_ci iavf_free_traffic_irqs(adapter); 433362306a36Sopenharmony_ci 433462306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 433562306a36Sopenharmony_ci 433662306a36Sopenharmony_ci /* We explicitly don't free resources here because the hardware is 433762306a36Sopenharmony_ci * still active and can DMA into memory. Resources are cleared in 433862306a36Sopenharmony_ci * iavf_virtchnl_completion() after we get confirmation from the PF 433962306a36Sopenharmony_ci * driver that the rings have been stopped. 434062306a36Sopenharmony_ci * 434162306a36Sopenharmony_ci * Also, we wait for state to transition to __IAVF_DOWN before 434262306a36Sopenharmony_ci * returning. State change occurs in iavf_virtchnl_completion() after 434362306a36Sopenharmony_ci * VF resources are released (which occurs after PF driver processes and 434462306a36Sopenharmony_ci * responds to admin queue commands). 434562306a36Sopenharmony_ci */ 434662306a36Sopenharmony_ci 434762306a36Sopenharmony_ci status = wait_event_timeout(adapter->down_waitqueue, 434862306a36Sopenharmony_ci adapter->state == __IAVF_DOWN, 434962306a36Sopenharmony_ci msecs_to_jiffies(500)); 435062306a36Sopenharmony_ci if (!status) 435162306a36Sopenharmony_ci netdev_warn(netdev, "Device resources not yet released\n"); 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ci mutex_lock(&adapter->crit_lock); 435462306a36Sopenharmony_ci adapter->aq_required |= aq_to_restore; 435562306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 435662306a36Sopenharmony_ci return 0; 435762306a36Sopenharmony_ci} 435862306a36Sopenharmony_ci 435962306a36Sopenharmony_ci/** 436062306a36Sopenharmony_ci * iavf_change_mtu - Change the Maximum Transfer Unit 436162306a36Sopenharmony_ci * @netdev: network interface device structure 436262306a36Sopenharmony_ci * @new_mtu: new value for maximum frame size 436362306a36Sopenharmony_ci * 436462306a36Sopenharmony_ci * Returns 0 on success, negative on failure 436562306a36Sopenharmony_ci **/ 436662306a36Sopenharmony_cistatic int iavf_change_mtu(struct net_device *netdev, int new_mtu) 436762306a36Sopenharmony_ci{ 436862306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 436962306a36Sopenharmony_ci int ret = 0; 437062306a36Sopenharmony_ci 437162306a36Sopenharmony_ci netdev_dbg(netdev, "changing MTU from %d to %d\n", 437262306a36Sopenharmony_ci netdev->mtu, new_mtu); 437362306a36Sopenharmony_ci netdev->mtu = new_mtu; 437462306a36Sopenharmony_ci if (CLIENT_ENABLED(adapter)) { 437562306a36Sopenharmony_ci iavf_notify_client_l2_params(&adapter->vsi); 437662306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED; 437762306a36Sopenharmony_ci } 437862306a36Sopenharmony_ci 437962306a36Sopenharmony_ci if (netif_running(netdev)) { 438062306a36Sopenharmony_ci iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED); 438162306a36Sopenharmony_ci ret = iavf_wait_for_reset(adapter); 438262306a36Sopenharmony_ci if (ret < 0) 438362306a36Sopenharmony_ci netdev_warn(netdev, "MTU change interrupted waiting for reset"); 438462306a36Sopenharmony_ci else if (ret) 438562306a36Sopenharmony_ci netdev_warn(netdev, "MTU change timed out waiting for reset"); 438662306a36Sopenharmony_ci } 438762306a36Sopenharmony_ci 438862306a36Sopenharmony_ci return ret; 438962306a36Sopenharmony_ci} 439062306a36Sopenharmony_ci 439162306a36Sopenharmony_ci/** 439262306a36Sopenharmony_ci * iavf_disable_fdir - disable Flow Director and clear existing filters 439362306a36Sopenharmony_ci * @adapter: board private structure 439462306a36Sopenharmony_ci **/ 439562306a36Sopenharmony_cistatic void iavf_disable_fdir(struct iavf_adapter *adapter) 439662306a36Sopenharmony_ci{ 439762306a36Sopenharmony_ci struct iavf_fdir_fltr *fdir, *fdirtmp; 439862306a36Sopenharmony_ci bool del_filters = false; 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_FDIR_ENABLED; 440162306a36Sopenharmony_ci 440262306a36Sopenharmony_ci /* remove all Flow Director filters */ 440362306a36Sopenharmony_ci spin_lock_bh(&adapter->fdir_fltr_lock); 440462306a36Sopenharmony_ci list_for_each_entry_safe(fdir, fdirtmp, &adapter->fdir_list_head, 440562306a36Sopenharmony_ci list) { 440662306a36Sopenharmony_ci if (fdir->state == IAVF_FDIR_FLTR_ADD_REQUEST || 440762306a36Sopenharmony_ci fdir->state == IAVF_FDIR_FLTR_INACTIVE) { 440862306a36Sopenharmony_ci /* Delete filters not registered in PF */ 440962306a36Sopenharmony_ci list_del(&fdir->list); 441062306a36Sopenharmony_ci kfree(fdir); 441162306a36Sopenharmony_ci adapter->fdir_active_fltr--; 441262306a36Sopenharmony_ci } else if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING || 441362306a36Sopenharmony_ci fdir->state == IAVF_FDIR_FLTR_DIS_REQUEST || 441462306a36Sopenharmony_ci fdir->state == IAVF_FDIR_FLTR_ACTIVE) { 441562306a36Sopenharmony_ci /* Filters registered in PF, schedule their deletion */ 441662306a36Sopenharmony_ci fdir->state = IAVF_FDIR_FLTR_DEL_REQUEST; 441762306a36Sopenharmony_ci del_filters = true; 441862306a36Sopenharmony_ci } else if (fdir->state == IAVF_FDIR_FLTR_DIS_PENDING) { 441962306a36Sopenharmony_ci /* Request to delete filter already sent to PF, change 442062306a36Sopenharmony_ci * state to DEL_PENDING to delete filter after PF's 442162306a36Sopenharmony_ci * response, not set as INACTIVE 442262306a36Sopenharmony_ci */ 442362306a36Sopenharmony_ci fdir->state = IAVF_FDIR_FLTR_DEL_PENDING; 442462306a36Sopenharmony_ci } 442562306a36Sopenharmony_ci } 442662306a36Sopenharmony_ci spin_unlock_bh(&adapter->fdir_fltr_lock); 442762306a36Sopenharmony_ci 442862306a36Sopenharmony_ci if (del_filters) { 442962306a36Sopenharmony_ci adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER; 443062306a36Sopenharmony_ci mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); 443162306a36Sopenharmony_ci } 443262306a36Sopenharmony_ci} 443362306a36Sopenharmony_ci 443462306a36Sopenharmony_ci#define NETIF_VLAN_OFFLOAD_FEATURES (NETIF_F_HW_VLAN_CTAG_RX | \ 443562306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | \ 443662306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_RX | \ 443762306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX) 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci/** 444062306a36Sopenharmony_ci * iavf_set_features - set the netdev feature flags 444162306a36Sopenharmony_ci * @netdev: ptr to the netdev being adjusted 444262306a36Sopenharmony_ci * @features: the feature set that the stack is suggesting 444362306a36Sopenharmony_ci * Note: expects to be called while under rtnl_lock() 444462306a36Sopenharmony_ci **/ 444562306a36Sopenharmony_cistatic int iavf_set_features(struct net_device *netdev, 444662306a36Sopenharmony_ci netdev_features_t features) 444762306a36Sopenharmony_ci{ 444862306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 444962306a36Sopenharmony_ci 445062306a36Sopenharmony_ci /* trigger update on any VLAN feature change */ 445162306a36Sopenharmony_ci if ((netdev->features & NETIF_VLAN_OFFLOAD_FEATURES) ^ 445262306a36Sopenharmony_ci (features & NETIF_VLAN_OFFLOAD_FEATURES)) 445362306a36Sopenharmony_ci iavf_set_vlan_offload_features(adapter, netdev->features, 445462306a36Sopenharmony_ci features); 445562306a36Sopenharmony_ci 445662306a36Sopenharmony_ci if ((netdev->features & NETIF_F_NTUPLE) ^ (features & NETIF_F_NTUPLE)) { 445762306a36Sopenharmony_ci if (features & NETIF_F_NTUPLE) 445862306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_FDIR_ENABLED; 445962306a36Sopenharmony_ci else 446062306a36Sopenharmony_ci iavf_disable_fdir(adapter); 446162306a36Sopenharmony_ci } 446262306a36Sopenharmony_ci 446362306a36Sopenharmony_ci return 0; 446462306a36Sopenharmony_ci} 446562306a36Sopenharmony_ci 446662306a36Sopenharmony_ci/** 446762306a36Sopenharmony_ci * iavf_features_check - Validate encapsulated packet conforms to limits 446862306a36Sopenharmony_ci * @skb: skb buff 446962306a36Sopenharmony_ci * @dev: This physical port's netdev 447062306a36Sopenharmony_ci * @features: Offload features that the stack believes apply 447162306a36Sopenharmony_ci **/ 447262306a36Sopenharmony_cistatic netdev_features_t iavf_features_check(struct sk_buff *skb, 447362306a36Sopenharmony_ci struct net_device *dev, 447462306a36Sopenharmony_ci netdev_features_t features) 447562306a36Sopenharmony_ci{ 447662306a36Sopenharmony_ci size_t len; 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_ci /* No point in doing any of this if neither checksum nor GSO are 447962306a36Sopenharmony_ci * being requested for this frame. We can rule out both by just 448062306a36Sopenharmony_ci * checking for CHECKSUM_PARTIAL 448162306a36Sopenharmony_ci */ 448262306a36Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 448362306a36Sopenharmony_ci return features; 448462306a36Sopenharmony_ci 448562306a36Sopenharmony_ci /* We cannot support GSO if the MSS is going to be less than 448662306a36Sopenharmony_ci * 64 bytes. If it is then we need to drop support for GSO. 448762306a36Sopenharmony_ci */ 448862306a36Sopenharmony_ci if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64)) 448962306a36Sopenharmony_ci features &= ~NETIF_F_GSO_MASK; 449062306a36Sopenharmony_ci 449162306a36Sopenharmony_ci /* MACLEN can support at most 63 words */ 449262306a36Sopenharmony_ci len = skb_network_header(skb) - skb->data; 449362306a36Sopenharmony_ci if (len & ~(63 * 2)) 449462306a36Sopenharmony_ci goto out_err; 449562306a36Sopenharmony_ci 449662306a36Sopenharmony_ci /* IPLEN and EIPLEN can support at most 127 dwords */ 449762306a36Sopenharmony_ci len = skb_transport_header(skb) - skb_network_header(skb); 449862306a36Sopenharmony_ci if (len & ~(127 * 4)) 449962306a36Sopenharmony_ci goto out_err; 450062306a36Sopenharmony_ci 450162306a36Sopenharmony_ci if (skb->encapsulation) { 450262306a36Sopenharmony_ci /* L4TUNLEN can support 127 words */ 450362306a36Sopenharmony_ci len = skb_inner_network_header(skb) - skb_transport_header(skb); 450462306a36Sopenharmony_ci if (len & ~(127 * 2)) 450562306a36Sopenharmony_ci goto out_err; 450662306a36Sopenharmony_ci 450762306a36Sopenharmony_ci /* IPLEN can support at most 127 dwords */ 450862306a36Sopenharmony_ci len = skb_inner_transport_header(skb) - 450962306a36Sopenharmony_ci skb_inner_network_header(skb); 451062306a36Sopenharmony_ci if (len & ~(127 * 4)) 451162306a36Sopenharmony_ci goto out_err; 451262306a36Sopenharmony_ci } 451362306a36Sopenharmony_ci 451462306a36Sopenharmony_ci /* No need to validate L4LEN as TCP is the only protocol with a 451562306a36Sopenharmony_ci * flexible value and we support all possible values supported 451662306a36Sopenharmony_ci * by TCP, which is at most 15 dwords 451762306a36Sopenharmony_ci */ 451862306a36Sopenharmony_ci 451962306a36Sopenharmony_ci return features; 452062306a36Sopenharmony_ciout_err: 452162306a36Sopenharmony_ci return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 452262306a36Sopenharmony_ci} 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_ci/** 452562306a36Sopenharmony_ci * iavf_get_netdev_vlan_hw_features - get NETDEV VLAN features that can toggle on/off 452662306a36Sopenharmony_ci * @adapter: board private structure 452762306a36Sopenharmony_ci * 452862306a36Sopenharmony_ci * Depending on whether VIRTHCNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2 452962306a36Sopenharmony_ci * were negotiated determine the VLAN features that can be toggled on and off. 453062306a36Sopenharmony_ci **/ 453162306a36Sopenharmony_cistatic netdev_features_t 453262306a36Sopenharmony_ciiavf_get_netdev_vlan_hw_features(struct iavf_adapter *adapter) 453362306a36Sopenharmony_ci{ 453462306a36Sopenharmony_ci netdev_features_t hw_features = 0; 453562306a36Sopenharmony_ci 453662306a36Sopenharmony_ci if (!adapter->vf_res || !adapter->vf_res->vf_cap_flags) 453762306a36Sopenharmony_ci return hw_features; 453862306a36Sopenharmony_ci 453962306a36Sopenharmony_ci /* Enable VLAN features if supported */ 454062306a36Sopenharmony_ci if (VLAN_ALLOWED(adapter)) { 454162306a36Sopenharmony_ci hw_features |= (NETIF_F_HW_VLAN_CTAG_TX | 454262306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX); 454362306a36Sopenharmony_ci } else if (VLAN_V2_ALLOWED(adapter)) { 454462306a36Sopenharmony_ci struct virtchnl_vlan_caps *vlan_v2_caps = 454562306a36Sopenharmony_ci &adapter->vlan_v2_caps; 454662306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *stripping_support = 454762306a36Sopenharmony_ci &vlan_v2_caps->offloads.stripping_support; 454862306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *insertion_support = 454962306a36Sopenharmony_ci &vlan_v2_caps->offloads.insertion_support; 455062306a36Sopenharmony_ci 455162306a36Sopenharmony_ci if (stripping_support->outer != VIRTCHNL_VLAN_UNSUPPORTED && 455262306a36Sopenharmony_ci stripping_support->outer & VIRTCHNL_VLAN_TOGGLE) { 455362306a36Sopenharmony_ci if (stripping_support->outer & 455462306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100) 455562306a36Sopenharmony_ci hw_features |= NETIF_F_HW_VLAN_CTAG_RX; 455662306a36Sopenharmony_ci if (stripping_support->outer & 455762306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8) 455862306a36Sopenharmony_ci hw_features |= NETIF_F_HW_VLAN_STAG_RX; 455962306a36Sopenharmony_ci } else if (stripping_support->inner != 456062306a36Sopenharmony_ci VIRTCHNL_VLAN_UNSUPPORTED && 456162306a36Sopenharmony_ci stripping_support->inner & VIRTCHNL_VLAN_TOGGLE) { 456262306a36Sopenharmony_ci if (stripping_support->inner & 456362306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100) 456462306a36Sopenharmony_ci hw_features |= NETIF_F_HW_VLAN_CTAG_RX; 456562306a36Sopenharmony_ci } 456662306a36Sopenharmony_ci 456762306a36Sopenharmony_ci if (insertion_support->outer != VIRTCHNL_VLAN_UNSUPPORTED && 456862306a36Sopenharmony_ci insertion_support->outer & VIRTCHNL_VLAN_TOGGLE) { 456962306a36Sopenharmony_ci if (insertion_support->outer & 457062306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100) 457162306a36Sopenharmony_ci hw_features |= NETIF_F_HW_VLAN_CTAG_TX; 457262306a36Sopenharmony_ci if (insertion_support->outer & 457362306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8) 457462306a36Sopenharmony_ci hw_features |= NETIF_F_HW_VLAN_STAG_TX; 457562306a36Sopenharmony_ci } else if (insertion_support->inner && 457662306a36Sopenharmony_ci insertion_support->inner & VIRTCHNL_VLAN_TOGGLE) { 457762306a36Sopenharmony_ci if (insertion_support->inner & 457862306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100) 457962306a36Sopenharmony_ci hw_features |= NETIF_F_HW_VLAN_CTAG_TX; 458062306a36Sopenharmony_ci } 458162306a36Sopenharmony_ci } 458262306a36Sopenharmony_ci 458362306a36Sopenharmony_ci return hw_features; 458462306a36Sopenharmony_ci} 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci/** 458762306a36Sopenharmony_ci * iavf_get_netdev_vlan_features - get the enabled NETDEV VLAN fetures 458862306a36Sopenharmony_ci * @adapter: board private structure 458962306a36Sopenharmony_ci * 459062306a36Sopenharmony_ci * Depending on whether VIRTHCNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2 459162306a36Sopenharmony_ci * were negotiated determine the VLAN features that are enabled by default. 459262306a36Sopenharmony_ci **/ 459362306a36Sopenharmony_cistatic netdev_features_t 459462306a36Sopenharmony_ciiavf_get_netdev_vlan_features(struct iavf_adapter *adapter) 459562306a36Sopenharmony_ci{ 459662306a36Sopenharmony_ci netdev_features_t features = 0; 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ci if (!adapter->vf_res || !adapter->vf_res->vf_cap_flags) 459962306a36Sopenharmony_ci return features; 460062306a36Sopenharmony_ci 460162306a36Sopenharmony_ci if (VLAN_ALLOWED(adapter)) { 460262306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_FILTER | 460362306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; 460462306a36Sopenharmony_ci } else if (VLAN_V2_ALLOWED(adapter)) { 460562306a36Sopenharmony_ci struct virtchnl_vlan_caps *vlan_v2_caps = 460662306a36Sopenharmony_ci &adapter->vlan_v2_caps; 460762306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *filtering_support = 460862306a36Sopenharmony_ci &vlan_v2_caps->filtering.filtering_support; 460962306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *stripping_support = 461062306a36Sopenharmony_ci &vlan_v2_caps->offloads.stripping_support; 461162306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *insertion_support = 461262306a36Sopenharmony_ci &vlan_v2_caps->offloads.insertion_support; 461362306a36Sopenharmony_ci u32 ethertype_init; 461462306a36Sopenharmony_ci 461562306a36Sopenharmony_ci /* give priority to outer stripping and don't support both outer 461662306a36Sopenharmony_ci * and inner stripping 461762306a36Sopenharmony_ci */ 461862306a36Sopenharmony_ci ethertype_init = vlan_v2_caps->offloads.ethertype_init; 461962306a36Sopenharmony_ci if (stripping_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) { 462062306a36Sopenharmony_ci if (stripping_support->outer & 462162306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 && 462262306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100) 462362306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_RX; 462462306a36Sopenharmony_ci else if (stripping_support->outer & 462562306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 && 462662306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8) 462762306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_STAG_RX; 462862306a36Sopenharmony_ci } else if (stripping_support->inner != 462962306a36Sopenharmony_ci VIRTCHNL_VLAN_UNSUPPORTED) { 463062306a36Sopenharmony_ci if (stripping_support->inner & 463162306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 && 463262306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100) 463362306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_RX; 463462306a36Sopenharmony_ci } 463562306a36Sopenharmony_ci 463662306a36Sopenharmony_ci /* give priority to outer insertion and don't support both outer 463762306a36Sopenharmony_ci * and inner insertion 463862306a36Sopenharmony_ci */ 463962306a36Sopenharmony_ci if (insertion_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) { 464062306a36Sopenharmony_ci if (insertion_support->outer & 464162306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 && 464262306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100) 464362306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_TX; 464462306a36Sopenharmony_ci else if (insertion_support->outer & 464562306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 && 464662306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8) 464762306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_STAG_TX; 464862306a36Sopenharmony_ci } else if (insertion_support->inner != 464962306a36Sopenharmony_ci VIRTCHNL_VLAN_UNSUPPORTED) { 465062306a36Sopenharmony_ci if (insertion_support->inner & 465162306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 && 465262306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100) 465362306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_TX; 465462306a36Sopenharmony_ci } 465562306a36Sopenharmony_ci 465662306a36Sopenharmony_ci /* give priority to outer filtering and don't bother if both 465762306a36Sopenharmony_ci * outer and inner filtering are enabled 465862306a36Sopenharmony_ci */ 465962306a36Sopenharmony_ci ethertype_init = vlan_v2_caps->filtering.ethertype_init; 466062306a36Sopenharmony_ci if (filtering_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) { 466162306a36Sopenharmony_ci if (filtering_support->outer & 466262306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 && 466362306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100) 466462306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_FILTER; 466562306a36Sopenharmony_ci if (filtering_support->outer & 466662306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 && 466762306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8) 466862306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_STAG_FILTER; 466962306a36Sopenharmony_ci } else if (filtering_support->inner != 467062306a36Sopenharmony_ci VIRTCHNL_VLAN_UNSUPPORTED) { 467162306a36Sopenharmony_ci if (filtering_support->inner & 467262306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 && 467362306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100) 467462306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_CTAG_FILTER; 467562306a36Sopenharmony_ci if (filtering_support->inner & 467662306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 && 467762306a36Sopenharmony_ci ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8) 467862306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_STAG_FILTER; 467962306a36Sopenharmony_ci } 468062306a36Sopenharmony_ci } 468162306a36Sopenharmony_ci 468262306a36Sopenharmony_ci return features; 468362306a36Sopenharmony_ci} 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci#define IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested, allowed, feature_bit) \ 468662306a36Sopenharmony_ci (!(((requested) & (feature_bit)) && \ 468762306a36Sopenharmony_ci !((allowed) & (feature_bit)))) 468862306a36Sopenharmony_ci 468962306a36Sopenharmony_ci/** 469062306a36Sopenharmony_ci * iavf_fix_netdev_vlan_features - fix NETDEV VLAN features based on support 469162306a36Sopenharmony_ci * @adapter: board private structure 469262306a36Sopenharmony_ci * @requested_features: stack requested NETDEV features 469362306a36Sopenharmony_ci **/ 469462306a36Sopenharmony_cistatic netdev_features_t 469562306a36Sopenharmony_ciiavf_fix_netdev_vlan_features(struct iavf_adapter *adapter, 469662306a36Sopenharmony_ci netdev_features_t requested_features) 469762306a36Sopenharmony_ci{ 469862306a36Sopenharmony_ci netdev_features_t allowed_features; 469962306a36Sopenharmony_ci 470062306a36Sopenharmony_ci allowed_features = iavf_get_netdev_vlan_hw_features(adapter) | 470162306a36Sopenharmony_ci iavf_get_netdev_vlan_features(adapter); 470262306a36Sopenharmony_ci 470362306a36Sopenharmony_ci if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features, 470462306a36Sopenharmony_ci allowed_features, 470562306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX)) 470662306a36Sopenharmony_ci requested_features &= ~NETIF_F_HW_VLAN_CTAG_TX; 470762306a36Sopenharmony_ci 470862306a36Sopenharmony_ci if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features, 470962306a36Sopenharmony_ci allowed_features, 471062306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX)) 471162306a36Sopenharmony_ci requested_features &= ~NETIF_F_HW_VLAN_CTAG_RX; 471262306a36Sopenharmony_ci 471362306a36Sopenharmony_ci if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features, 471462306a36Sopenharmony_ci allowed_features, 471562306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX)) 471662306a36Sopenharmony_ci requested_features &= ~NETIF_F_HW_VLAN_STAG_TX; 471762306a36Sopenharmony_ci if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features, 471862306a36Sopenharmony_ci allowed_features, 471962306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_RX)) 472062306a36Sopenharmony_ci requested_features &= ~NETIF_F_HW_VLAN_STAG_RX; 472162306a36Sopenharmony_ci 472262306a36Sopenharmony_ci if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features, 472362306a36Sopenharmony_ci allowed_features, 472462306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER)) 472562306a36Sopenharmony_ci requested_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 472662306a36Sopenharmony_ci 472762306a36Sopenharmony_ci if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features, 472862306a36Sopenharmony_ci allowed_features, 472962306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_FILTER)) 473062306a36Sopenharmony_ci requested_features &= ~NETIF_F_HW_VLAN_STAG_FILTER; 473162306a36Sopenharmony_ci 473262306a36Sopenharmony_ci if ((requested_features & 473362306a36Sopenharmony_ci (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX)) && 473462306a36Sopenharmony_ci (requested_features & 473562306a36Sopenharmony_ci (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX)) && 473662306a36Sopenharmony_ci adapter->vlan_v2_caps.offloads.ethertype_match == 473762306a36Sopenharmony_ci VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION) { 473862306a36Sopenharmony_ci netdev_warn(adapter->netdev, "cannot support CTAG and STAG VLAN stripping and/or insertion simultaneously since CTAG and STAG offloads are mutually exclusive, clearing STAG offload settings\n"); 473962306a36Sopenharmony_ci requested_features &= ~(NETIF_F_HW_VLAN_STAG_RX | 474062306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX); 474162306a36Sopenharmony_ci } 474262306a36Sopenharmony_ci 474362306a36Sopenharmony_ci return requested_features; 474462306a36Sopenharmony_ci} 474562306a36Sopenharmony_ci 474662306a36Sopenharmony_ci/** 474762306a36Sopenharmony_ci * iavf_fix_features - fix up the netdev feature bits 474862306a36Sopenharmony_ci * @netdev: our net device 474962306a36Sopenharmony_ci * @features: desired feature bits 475062306a36Sopenharmony_ci * 475162306a36Sopenharmony_ci * Returns fixed-up features bits 475262306a36Sopenharmony_ci **/ 475362306a36Sopenharmony_cistatic netdev_features_t iavf_fix_features(struct net_device *netdev, 475462306a36Sopenharmony_ci netdev_features_t features) 475562306a36Sopenharmony_ci{ 475662306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_ci if (!FDIR_FLTR_SUPPORT(adapter)) 475962306a36Sopenharmony_ci features &= ~NETIF_F_NTUPLE; 476062306a36Sopenharmony_ci 476162306a36Sopenharmony_ci return iavf_fix_netdev_vlan_features(adapter, features); 476262306a36Sopenharmony_ci} 476362306a36Sopenharmony_ci 476462306a36Sopenharmony_cistatic const struct net_device_ops iavf_netdev_ops = { 476562306a36Sopenharmony_ci .ndo_open = iavf_open, 476662306a36Sopenharmony_ci .ndo_stop = iavf_close, 476762306a36Sopenharmony_ci .ndo_start_xmit = iavf_xmit_frame, 476862306a36Sopenharmony_ci .ndo_set_rx_mode = iavf_set_rx_mode, 476962306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 477062306a36Sopenharmony_ci .ndo_set_mac_address = iavf_set_mac, 477162306a36Sopenharmony_ci .ndo_change_mtu = iavf_change_mtu, 477262306a36Sopenharmony_ci .ndo_tx_timeout = iavf_tx_timeout, 477362306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = iavf_vlan_rx_add_vid, 477462306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = iavf_vlan_rx_kill_vid, 477562306a36Sopenharmony_ci .ndo_features_check = iavf_features_check, 477662306a36Sopenharmony_ci .ndo_fix_features = iavf_fix_features, 477762306a36Sopenharmony_ci .ndo_set_features = iavf_set_features, 477862306a36Sopenharmony_ci .ndo_setup_tc = iavf_setup_tc, 477962306a36Sopenharmony_ci}; 478062306a36Sopenharmony_ci 478162306a36Sopenharmony_ci/** 478262306a36Sopenharmony_ci * iavf_check_reset_complete - check that VF reset is complete 478362306a36Sopenharmony_ci * @hw: pointer to hw struct 478462306a36Sopenharmony_ci * 478562306a36Sopenharmony_ci * Returns 0 if device is ready to use, or -EBUSY if it's in reset. 478662306a36Sopenharmony_ci **/ 478762306a36Sopenharmony_cistatic int iavf_check_reset_complete(struct iavf_hw *hw) 478862306a36Sopenharmony_ci{ 478962306a36Sopenharmony_ci u32 rstat; 479062306a36Sopenharmony_ci int i; 479162306a36Sopenharmony_ci 479262306a36Sopenharmony_ci for (i = 0; i < IAVF_RESET_WAIT_COMPLETE_COUNT; i++) { 479362306a36Sopenharmony_ci rstat = rd32(hw, IAVF_VFGEN_RSTAT) & 479462306a36Sopenharmony_ci IAVF_VFGEN_RSTAT_VFR_STATE_MASK; 479562306a36Sopenharmony_ci if ((rstat == VIRTCHNL_VFR_VFACTIVE) || 479662306a36Sopenharmony_ci (rstat == VIRTCHNL_VFR_COMPLETED)) 479762306a36Sopenharmony_ci return 0; 479862306a36Sopenharmony_ci usleep_range(10, 20); 479962306a36Sopenharmony_ci } 480062306a36Sopenharmony_ci return -EBUSY; 480162306a36Sopenharmony_ci} 480262306a36Sopenharmony_ci 480362306a36Sopenharmony_ci/** 480462306a36Sopenharmony_ci * iavf_process_config - Process the config information we got from the PF 480562306a36Sopenharmony_ci * @adapter: board private structure 480662306a36Sopenharmony_ci * 480762306a36Sopenharmony_ci * Verify that we have a valid config struct, and set up our netdev features 480862306a36Sopenharmony_ci * and our VSI struct. 480962306a36Sopenharmony_ci **/ 481062306a36Sopenharmony_ciint iavf_process_config(struct iavf_adapter *adapter) 481162306a36Sopenharmony_ci{ 481262306a36Sopenharmony_ci struct virtchnl_vf_resource *vfres = adapter->vf_res; 481362306a36Sopenharmony_ci netdev_features_t hw_vlan_features, vlan_features; 481462306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 481562306a36Sopenharmony_ci netdev_features_t hw_enc_features; 481662306a36Sopenharmony_ci netdev_features_t hw_features; 481762306a36Sopenharmony_ci 481862306a36Sopenharmony_ci hw_enc_features = NETIF_F_SG | 481962306a36Sopenharmony_ci NETIF_F_IP_CSUM | 482062306a36Sopenharmony_ci NETIF_F_IPV6_CSUM | 482162306a36Sopenharmony_ci NETIF_F_HIGHDMA | 482262306a36Sopenharmony_ci NETIF_F_SOFT_FEATURES | 482362306a36Sopenharmony_ci NETIF_F_TSO | 482462306a36Sopenharmony_ci NETIF_F_TSO_ECN | 482562306a36Sopenharmony_ci NETIF_F_TSO6 | 482662306a36Sopenharmony_ci NETIF_F_SCTP_CRC | 482762306a36Sopenharmony_ci NETIF_F_RXHASH | 482862306a36Sopenharmony_ci NETIF_F_RXCSUM | 482962306a36Sopenharmony_ci 0; 483062306a36Sopenharmony_ci 483162306a36Sopenharmony_ci /* advertise to stack only if offloads for encapsulated packets is 483262306a36Sopenharmony_ci * supported 483362306a36Sopenharmony_ci */ 483462306a36Sopenharmony_ci if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ENCAP) { 483562306a36Sopenharmony_ci hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL | 483662306a36Sopenharmony_ci NETIF_F_GSO_GRE | 483762306a36Sopenharmony_ci NETIF_F_GSO_GRE_CSUM | 483862306a36Sopenharmony_ci NETIF_F_GSO_IPXIP4 | 483962306a36Sopenharmony_ci NETIF_F_GSO_IPXIP6 | 484062306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 484162306a36Sopenharmony_ci NETIF_F_GSO_PARTIAL | 484262306a36Sopenharmony_ci 0; 484362306a36Sopenharmony_ci 484462306a36Sopenharmony_ci if (!(vfres->vf_cap_flags & 484562306a36Sopenharmony_ci VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) 484662306a36Sopenharmony_ci netdev->gso_partial_features |= 484762306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM; 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_ci netdev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM; 485062306a36Sopenharmony_ci netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID; 485162306a36Sopenharmony_ci netdev->hw_enc_features |= hw_enc_features; 485262306a36Sopenharmony_ci } 485362306a36Sopenharmony_ci /* record features VLANs can make use of */ 485462306a36Sopenharmony_ci netdev->vlan_features |= hw_enc_features | NETIF_F_TSO_MANGLEID; 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ci /* Write features and hw_features separately to avoid polluting 485762306a36Sopenharmony_ci * with, or dropping, features that are set when we registered. 485862306a36Sopenharmony_ci */ 485962306a36Sopenharmony_ci hw_features = hw_enc_features; 486062306a36Sopenharmony_ci 486162306a36Sopenharmony_ci /* get HW VLAN features that can be toggled */ 486262306a36Sopenharmony_ci hw_vlan_features = iavf_get_netdev_vlan_hw_features(adapter); 486362306a36Sopenharmony_ci 486462306a36Sopenharmony_ci /* Enable cloud filter if ADQ is supported */ 486562306a36Sopenharmony_ci if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) 486662306a36Sopenharmony_ci hw_features |= NETIF_F_HW_TC; 486762306a36Sopenharmony_ci if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_USO) 486862306a36Sopenharmony_ci hw_features |= NETIF_F_GSO_UDP_L4; 486962306a36Sopenharmony_ci 487062306a36Sopenharmony_ci netdev->hw_features |= hw_features | hw_vlan_features; 487162306a36Sopenharmony_ci vlan_features = iavf_get_netdev_vlan_features(adapter); 487262306a36Sopenharmony_ci 487362306a36Sopenharmony_ci netdev->features |= hw_features | vlan_features; 487462306a36Sopenharmony_ci 487562306a36Sopenharmony_ci if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN) 487662306a36Sopenharmony_ci netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 487762306a36Sopenharmony_ci 487862306a36Sopenharmony_ci if (FDIR_FLTR_SUPPORT(adapter)) { 487962306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_NTUPLE; 488062306a36Sopenharmony_ci netdev->features |= NETIF_F_NTUPLE; 488162306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_FDIR_ENABLED; 488262306a36Sopenharmony_ci } 488362306a36Sopenharmony_ci 488462306a36Sopenharmony_ci netdev->priv_flags |= IFF_UNICAST_FLT; 488562306a36Sopenharmony_ci 488662306a36Sopenharmony_ci /* Do not turn on offloads when they are requested to be turned off. 488762306a36Sopenharmony_ci * TSO needs minimum 576 bytes to work correctly. 488862306a36Sopenharmony_ci */ 488962306a36Sopenharmony_ci if (netdev->wanted_features) { 489062306a36Sopenharmony_ci if (!(netdev->wanted_features & NETIF_F_TSO) || 489162306a36Sopenharmony_ci netdev->mtu < 576) 489262306a36Sopenharmony_ci netdev->features &= ~NETIF_F_TSO; 489362306a36Sopenharmony_ci if (!(netdev->wanted_features & NETIF_F_TSO6) || 489462306a36Sopenharmony_ci netdev->mtu < 576) 489562306a36Sopenharmony_ci netdev->features &= ~NETIF_F_TSO6; 489662306a36Sopenharmony_ci if (!(netdev->wanted_features & NETIF_F_TSO_ECN)) 489762306a36Sopenharmony_ci netdev->features &= ~NETIF_F_TSO_ECN; 489862306a36Sopenharmony_ci if (!(netdev->wanted_features & NETIF_F_GRO)) 489962306a36Sopenharmony_ci netdev->features &= ~NETIF_F_GRO; 490062306a36Sopenharmony_ci if (!(netdev->wanted_features & NETIF_F_GSO)) 490162306a36Sopenharmony_ci netdev->features &= ~NETIF_F_GSO; 490262306a36Sopenharmony_ci } 490362306a36Sopenharmony_ci 490462306a36Sopenharmony_ci return 0; 490562306a36Sopenharmony_ci} 490662306a36Sopenharmony_ci 490762306a36Sopenharmony_ci/** 490862306a36Sopenharmony_ci * iavf_probe - Device Initialization Routine 490962306a36Sopenharmony_ci * @pdev: PCI device information struct 491062306a36Sopenharmony_ci * @ent: entry in iavf_pci_tbl 491162306a36Sopenharmony_ci * 491262306a36Sopenharmony_ci * Returns 0 on success, negative on failure 491362306a36Sopenharmony_ci * 491462306a36Sopenharmony_ci * iavf_probe initializes an adapter identified by a pci_dev structure. 491562306a36Sopenharmony_ci * The OS initialization, configuring of the adapter private structure, 491662306a36Sopenharmony_ci * and a hardware reset occur. 491762306a36Sopenharmony_ci **/ 491862306a36Sopenharmony_cistatic int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 491962306a36Sopenharmony_ci{ 492062306a36Sopenharmony_ci struct net_device *netdev; 492162306a36Sopenharmony_ci struct iavf_adapter *adapter = NULL; 492262306a36Sopenharmony_ci struct iavf_hw *hw = NULL; 492362306a36Sopenharmony_ci int err; 492462306a36Sopenharmony_ci 492562306a36Sopenharmony_ci err = pci_enable_device(pdev); 492662306a36Sopenharmony_ci if (err) 492762306a36Sopenharmony_ci return err; 492862306a36Sopenharmony_ci 492962306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 493062306a36Sopenharmony_ci if (err) { 493162306a36Sopenharmony_ci dev_err(&pdev->dev, 493262306a36Sopenharmony_ci "DMA configuration failed: 0x%x\n", err); 493362306a36Sopenharmony_ci goto err_dma; 493462306a36Sopenharmony_ci } 493562306a36Sopenharmony_ci 493662306a36Sopenharmony_ci err = pci_request_regions(pdev, iavf_driver_name); 493762306a36Sopenharmony_ci if (err) { 493862306a36Sopenharmony_ci dev_err(&pdev->dev, 493962306a36Sopenharmony_ci "pci_request_regions failed 0x%x\n", err); 494062306a36Sopenharmony_ci goto err_pci_reg; 494162306a36Sopenharmony_ci } 494262306a36Sopenharmony_ci 494362306a36Sopenharmony_ci pci_set_master(pdev); 494462306a36Sopenharmony_ci 494562306a36Sopenharmony_ci netdev = alloc_etherdev_mq(sizeof(struct iavf_adapter), 494662306a36Sopenharmony_ci IAVF_MAX_REQ_QUEUES); 494762306a36Sopenharmony_ci if (!netdev) { 494862306a36Sopenharmony_ci err = -ENOMEM; 494962306a36Sopenharmony_ci goto err_alloc_etherdev; 495062306a36Sopenharmony_ci } 495162306a36Sopenharmony_ci 495262306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 495362306a36Sopenharmony_ci 495462306a36Sopenharmony_ci pci_set_drvdata(pdev, netdev); 495562306a36Sopenharmony_ci adapter = netdev_priv(netdev); 495662306a36Sopenharmony_ci 495762306a36Sopenharmony_ci adapter->netdev = netdev; 495862306a36Sopenharmony_ci adapter->pdev = pdev; 495962306a36Sopenharmony_ci 496062306a36Sopenharmony_ci hw = &adapter->hw; 496162306a36Sopenharmony_ci hw->back = adapter; 496262306a36Sopenharmony_ci 496362306a36Sopenharmony_ci adapter->wq = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, 496462306a36Sopenharmony_ci iavf_driver_name); 496562306a36Sopenharmony_ci if (!adapter->wq) { 496662306a36Sopenharmony_ci err = -ENOMEM; 496762306a36Sopenharmony_ci goto err_alloc_wq; 496862306a36Sopenharmony_ci } 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1; 497162306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_STARTUP); 497262306a36Sopenharmony_ci 497362306a36Sopenharmony_ci /* Call save state here because it relies on the adapter struct. */ 497462306a36Sopenharmony_ci pci_save_state(pdev); 497562306a36Sopenharmony_ci 497662306a36Sopenharmony_ci hw->hw_addr = ioremap(pci_resource_start(pdev, 0), 497762306a36Sopenharmony_ci pci_resource_len(pdev, 0)); 497862306a36Sopenharmony_ci if (!hw->hw_addr) { 497962306a36Sopenharmony_ci err = -EIO; 498062306a36Sopenharmony_ci goto err_ioremap; 498162306a36Sopenharmony_ci } 498262306a36Sopenharmony_ci hw->vendor_id = pdev->vendor; 498362306a36Sopenharmony_ci hw->device_id = pdev->device; 498462306a36Sopenharmony_ci pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); 498562306a36Sopenharmony_ci hw->subsystem_vendor_id = pdev->subsystem_vendor; 498662306a36Sopenharmony_ci hw->subsystem_device_id = pdev->subsystem_device; 498762306a36Sopenharmony_ci hw->bus.device = PCI_SLOT(pdev->devfn); 498862306a36Sopenharmony_ci hw->bus.func = PCI_FUNC(pdev->devfn); 498962306a36Sopenharmony_ci hw->bus.bus_id = pdev->bus->number; 499062306a36Sopenharmony_ci 499162306a36Sopenharmony_ci /* set up the locks for the AQ, do this only once in probe 499262306a36Sopenharmony_ci * and destroy them only once in remove 499362306a36Sopenharmony_ci */ 499462306a36Sopenharmony_ci mutex_init(&adapter->crit_lock); 499562306a36Sopenharmony_ci mutex_init(&adapter->client_lock); 499662306a36Sopenharmony_ci mutex_init(&hw->aq.asq_mutex); 499762306a36Sopenharmony_ci mutex_init(&hw->aq.arq_mutex); 499862306a36Sopenharmony_ci 499962306a36Sopenharmony_ci spin_lock_init(&adapter->mac_vlan_list_lock); 500062306a36Sopenharmony_ci spin_lock_init(&adapter->cloud_filter_list_lock); 500162306a36Sopenharmony_ci spin_lock_init(&adapter->fdir_fltr_lock); 500262306a36Sopenharmony_ci spin_lock_init(&adapter->adv_rss_lock); 500362306a36Sopenharmony_ci spin_lock_init(&adapter->current_netdev_promisc_flags_lock); 500462306a36Sopenharmony_ci 500562306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->mac_filter_list); 500662306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->vlan_filter_list); 500762306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->cloud_filter_list); 500862306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->fdir_list_head); 500962306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->adv_rss_list_head); 501062306a36Sopenharmony_ci 501162306a36Sopenharmony_ci INIT_WORK(&adapter->reset_task, iavf_reset_task); 501262306a36Sopenharmony_ci INIT_WORK(&adapter->adminq_task, iavf_adminq_task); 501362306a36Sopenharmony_ci INIT_WORK(&adapter->finish_config, iavf_finish_config); 501462306a36Sopenharmony_ci INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task); 501562306a36Sopenharmony_ci INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task); 501662306a36Sopenharmony_ci 501762306a36Sopenharmony_ci /* Setup the wait queue for indicating transition to down status */ 501862306a36Sopenharmony_ci init_waitqueue_head(&adapter->down_waitqueue); 501962306a36Sopenharmony_ci 502062306a36Sopenharmony_ci /* Setup the wait queue for indicating transition to running state */ 502162306a36Sopenharmony_ci init_waitqueue_head(&adapter->reset_waitqueue); 502262306a36Sopenharmony_ci 502362306a36Sopenharmony_ci /* Setup the wait queue for indicating virtchannel events */ 502462306a36Sopenharmony_ci init_waitqueue_head(&adapter->vc_waitqueue); 502562306a36Sopenharmony_ci 502662306a36Sopenharmony_ci queue_delayed_work(adapter->wq, &adapter->watchdog_task, 502762306a36Sopenharmony_ci msecs_to_jiffies(5 * (pdev->devfn & 0x07))); 502862306a36Sopenharmony_ci /* Initialization goes on in the work. Do not add more of it below. */ 502962306a36Sopenharmony_ci return 0; 503062306a36Sopenharmony_ci 503162306a36Sopenharmony_cierr_ioremap: 503262306a36Sopenharmony_ci destroy_workqueue(adapter->wq); 503362306a36Sopenharmony_cierr_alloc_wq: 503462306a36Sopenharmony_ci free_netdev(netdev); 503562306a36Sopenharmony_cierr_alloc_etherdev: 503662306a36Sopenharmony_ci pci_release_regions(pdev); 503762306a36Sopenharmony_cierr_pci_reg: 503862306a36Sopenharmony_cierr_dma: 503962306a36Sopenharmony_ci pci_disable_device(pdev); 504062306a36Sopenharmony_ci return err; 504162306a36Sopenharmony_ci} 504262306a36Sopenharmony_ci 504362306a36Sopenharmony_ci/** 504462306a36Sopenharmony_ci * iavf_suspend - Power management suspend routine 504562306a36Sopenharmony_ci * @dev_d: device info pointer 504662306a36Sopenharmony_ci * 504762306a36Sopenharmony_ci * Called when the system (VM) is entering sleep/suspend. 504862306a36Sopenharmony_ci **/ 504962306a36Sopenharmony_cistatic int __maybe_unused iavf_suspend(struct device *dev_d) 505062306a36Sopenharmony_ci{ 505162306a36Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev_d); 505262306a36Sopenharmony_ci struct iavf_adapter *adapter = netdev_priv(netdev); 505362306a36Sopenharmony_ci 505462306a36Sopenharmony_ci netif_device_detach(netdev); 505562306a36Sopenharmony_ci 505662306a36Sopenharmony_ci while (!mutex_trylock(&adapter->crit_lock)) 505762306a36Sopenharmony_ci usleep_range(500, 1000); 505862306a36Sopenharmony_ci 505962306a36Sopenharmony_ci if (netif_running(netdev)) { 506062306a36Sopenharmony_ci rtnl_lock(); 506162306a36Sopenharmony_ci iavf_down(adapter); 506262306a36Sopenharmony_ci rtnl_unlock(); 506362306a36Sopenharmony_ci } 506462306a36Sopenharmony_ci iavf_free_misc_irq(adapter); 506562306a36Sopenharmony_ci iavf_reset_interrupt_capability(adapter); 506662306a36Sopenharmony_ci 506762306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 506862306a36Sopenharmony_ci 506962306a36Sopenharmony_ci return 0; 507062306a36Sopenharmony_ci} 507162306a36Sopenharmony_ci 507262306a36Sopenharmony_ci/** 507362306a36Sopenharmony_ci * iavf_resume - Power management resume routine 507462306a36Sopenharmony_ci * @dev_d: device info pointer 507562306a36Sopenharmony_ci * 507662306a36Sopenharmony_ci * Called when the system (VM) is resumed from sleep/suspend. 507762306a36Sopenharmony_ci **/ 507862306a36Sopenharmony_cistatic int __maybe_unused iavf_resume(struct device *dev_d) 507962306a36Sopenharmony_ci{ 508062306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_d); 508162306a36Sopenharmony_ci struct iavf_adapter *adapter; 508262306a36Sopenharmony_ci u32 err; 508362306a36Sopenharmony_ci 508462306a36Sopenharmony_ci adapter = iavf_pdev_to_adapter(pdev); 508562306a36Sopenharmony_ci 508662306a36Sopenharmony_ci pci_set_master(pdev); 508762306a36Sopenharmony_ci 508862306a36Sopenharmony_ci rtnl_lock(); 508962306a36Sopenharmony_ci err = iavf_set_interrupt_capability(adapter); 509062306a36Sopenharmony_ci if (err) { 509162306a36Sopenharmony_ci rtnl_unlock(); 509262306a36Sopenharmony_ci dev_err(&pdev->dev, "Cannot enable MSI-X interrupts.\n"); 509362306a36Sopenharmony_ci return err; 509462306a36Sopenharmony_ci } 509562306a36Sopenharmony_ci err = iavf_request_misc_irq(adapter); 509662306a36Sopenharmony_ci rtnl_unlock(); 509762306a36Sopenharmony_ci if (err) { 509862306a36Sopenharmony_ci dev_err(&pdev->dev, "Cannot get interrupt vector.\n"); 509962306a36Sopenharmony_ci return err; 510062306a36Sopenharmony_ci } 510162306a36Sopenharmony_ci 510262306a36Sopenharmony_ci queue_work(adapter->wq, &adapter->reset_task); 510362306a36Sopenharmony_ci 510462306a36Sopenharmony_ci netif_device_attach(adapter->netdev); 510562306a36Sopenharmony_ci 510662306a36Sopenharmony_ci return err; 510762306a36Sopenharmony_ci} 510862306a36Sopenharmony_ci 510962306a36Sopenharmony_ci/** 511062306a36Sopenharmony_ci * iavf_remove - Device Removal Routine 511162306a36Sopenharmony_ci * @pdev: PCI device information struct 511262306a36Sopenharmony_ci * 511362306a36Sopenharmony_ci * iavf_remove is called by the PCI subsystem to alert the driver 511462306a36Sopenharmony_ci * that it should release a PCI device. The could be caused by a 511562306a36Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from 511662306a36Sopenharmony_ci * memory. 511762306a36Sopenharmony_ci **/ 511862306a36Sopenharmony_cistatic void iavf_remove(struct pci_dev *pdev) 511962306a36Sopenharmony_ci{ 512062306a36Sopenharmony_ci struct iavf_fdir_fltr *fdir, *fdirtmp; 512162306a36Sopenharmony_ci struct iavf_vlan_filter *vlf, *vlftmp; 512262306a36Sopenharmony_ci struct iavf_cloud_filter *cf, *cftmp; 512362306a36Sopenharmony_ci struct iavf_adv_rss *rss, *rsstmp; 512462306a36Sopenharmony_ci struct iavf_mac_filter *f, *ftmp; 512562306a36Sopenharmony_ci struct iavf_adapter *adapter; 512662306a36Sopenharmony_ci struct net_device *netdev; 512762306a36Sopenharmony_ci struct iavf_hw *hw; 512862306a36Sopenharmony_ci int err; 512962306a36Sopenharmony_ci 513062306a36Sopenharmony_ci /* Don't proceed with remove if netdev is already freed */ 513162306a36Sopenharmony_ci netdev = pci_get_drvdata(pdev); 513262306a36Sopenharmony_ci if (!netdev) 513362306a36Sopenharmony_ci return; 513462306a36Sopenharmony_ci 513562306a36Sopenharmony_ci adapter = iavf_pdev_to_adapter(pdev); 513662306a36Sopenharmony_ci hw = &adapter->hw; 513762306a36Sopenharmony_ci 513862306a36Sopenharmony_ci if (test_and_set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) 513962306a36Sopenharmony_ci return; 514062306a36Sopenharmony_ci 514162306a36Sopenharmony_ci /* Wait until port initialization is complete. 514262306a36Sopenharmony_ci * There are flows where register/unregister netdev may race. 514362306a36Sopenharmony_ci */ 514462306a36Sopenharmony_ci while (1) { 514562306a36Sopenharmony_ci mutex_lock(&adapter->crit_lock); 514662306a36Sopenharmony_ci if (adapter->state == __IAVF_RUNNING || 514762306a36Sopenharmony_ci adapter->state == __IAVF_DOWN || 514862306a36Sopenharmony_ci adapter->state == __IAVF_INIT_FAILED) { 514962306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 515062306a36Sopenharmony_ci break; 515162306a36Sopenharmony_ci } 515262306a36Sopenharmony_ci /* Simply return if we already went through iavf_shutdown */ 515362306a36Sopenharmony_ci if (adapter->state == __IAVF_REMOVE) { 515462306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 515562306a36Sopenharmony_ci return; 515662306a36Sopenharmony_ci } 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 515962306a36Sopenharmony_ci usleep_range(500, 1000); 516062306a36Sopenharmony_ci } 516162306a36Sopenharmony_ci cancel_delayed_work_sync(&adapter->watchdog_task); 516262306a36Sopenharmony_ci cancel_work_sync(&adapter->finish_config); 516362306a36Sopenharmony_ci 516462306a36Sopenharmony_ci rtnl_lock(); 516562306a36Sopenharmony_ci if (adapter->netdev_registered) { 516662306a36Sopenharmony_ci unregister_netdevice(netdev); 516762306a36Sopenharmony_ci adapter->netdev_registered = false; 516862306a36Sopenharmony_ci } 516962306a36Sopenharmony_ci rtnl_unlock(); 517062306a36Sopenharmony_ci 517162306a36Sopenharmony_ci if (CLIENT_ALLOWED(adapter)) { 517262306a36Sopenharmony_ci err = iavf_lan_del_device(adapter); 517362306a36Sopenharmony_ci if (err) 517462306a36Sopenharmony_ci dev_warn(&pdev->dev, "Failed to delete client device: %d\n", 517562306a36Sopenharmony_ci err); 517662306a36Sopenharmony_ci } 517762306a36Sopenharmony_ci 517862306a36Sopenharmony_ci mutex_lock(&adapter->crit_lock); 517962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Removing device\n"); 518062306a36Sopenharmony_ci iavf_change_state(adapter, __IAVF_REMOVE); 518162306a36Sopenharmony_ci 518262306a36Sopenharmony_ci iavf_request_reset(adapter); 518362306a36Sopenharmony_ci msleep(50); 518462306a36Sopenharmony_ci /* If the FW isn't responding, kick it once, but only once. */ 518562306a36Sopenharmony_ci if (!iavf_asq_done(hw)) { 518662306a36Sopenharmony_ci iavf_request_reset(adapter); 518762306a36Sopenharmony_ci msleep(50); 518862306a36Sopenharmony_ci } 518962306a36Sopenharmony_ci 519062306a36Sopenharmony_ci iavf_misc_irq_disable(adapter); 519162306a36Sopenharmony_ci /* Shut down all the garbage mashers on the detention level */ 519262306a36Sopenharmony_ci cancel_work_sync(&adapter->reset_task); 519362306a36Sopenharmony_ci cancel_delayed_work_sync(&adapter->watchdog_task); 519462306a36Sopenharmony_ci cancel_work_sync(&adapter->adminq_task); 519562306a36Sopenharmony_ci cancel_delayed_work_sync(&adapter->client_task); 519662306a36Sopenharmony_ci 519762306a36Sopenharmony_ci adapter->aq_required = 0; 519862306a36Sopenharmony_ci adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; 519962306a36Sopenharmony_ci 520062306a36Sopenharmony_ci iavf_free_all_tx_resources(adapter); 520162306a36Sopenharmony_ci iavf_free_all_rx_resources(adapter); 520262306a36Sopenharmony_ci iavf_free_misc_irq(adapter); 520362306a36Sopenharmony_ci 520462306a36Sopenharmony_ci iavf_reset_interrupt_capability(adapter); 520562306a36Sopenharmony_ci iavf_free_q_vectors(adapter); 520662306a36Sopenharmony_ci 520762306a36Sopenharmony_ci iavf_free_rss(adapter); 520862306a36Sopenharmony_ci 520962306a36Sopenharmony_ci if (hw->aq.asq.count) 521062306a36Sopenharmony_ci iavf_shutdown_adminq(hw); 521162306a36Sopenharmony_ci 521262306a36Sopenharmony_ci /* destroy the locks only once, here */ 521362306a36Sopenharmony_ci mutex_destroy(&hw->aq.arq_mutex); 521462306a36Sopenharmony_ci mutex_destroy(&hw->aq.asq_mutex); 521562306a36Sopenharmony_ci mutex_destroy(&adapter->client_lock); 521662306a36Sopenharmony_ci mutex_unlock(&adapter->crit_lock); 521762306a36Sopenharmony_ci mutex_destroy(&adapter->crit_lock); 521862306a36Sopenharmony_ci 521962306a36Sopenharmony_ci iounmap(hw->hw_addr); 522062306a36Sopenharmony_ci pci_release_regions(pdev); 522162306a36Sopenharmony_ci iavf_free_queues(adapter); 522262306a36Sopenharmony_ci kfree(adapter->vf_res); 522362306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_vlan_list_lock); 522462306a36Sopenharmony_ci /* If we got removed before an up/down sequence, we've got a filter 522562306a36Sopenharmony_ci * hanging out there that we need to get rid of. 522662306a36Sopenharmony_ci */ 522762306a36Sopenharmony_ci list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { 522862306a36Sopenharmony_ci list_del(&f->list); 522962306a36Sopenharmony_ci kfree(f); 523062306a36Sopenharmony_ci } 523162306a36Sopenharmony_ci list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, 523262306a36Sopenharmony_ci list) { 523362306a36Sopenharmony_ci list_del(&vlf->list); 523462306a36Sopenharmony_ci kfree(vlf); 523562306a36Sopenharmony_ci } 523662306a36Sopenharmony_ci 523762306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_vlan_list_lock); 523862306a36Sopenharmony_ci 523962306a36Sopenharmony_ci spin_lock_bh(&adapter->cloud_filter_list_lock); 524062306a36Sopenharmony_ci list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) { 524162306a36Sopenharmony_ci list_del(&cf->list); 524262306a36Sopenharmony_ci kfree(cf); 524362306a36Sopenharmony_ci } 524462306a36Sopenharmony_ci spin_unlock_bh(&adapter->cloud_filter_list_lock); 524562306a36Sopenharmony_ci 524662306a36Sopenharmony_ci spin_lock_bh(&adapter->fdir_fltr_lock); 524762306a36Sopenharmony_ci list_for_each_entry_safe(fdir, fdirtmp, &adapter->fdir_list_head, list) { 524862306a36Sopenharmony_ci list_del(&fdir->list); 524962306a36Sopenharmony_ci kfree(fdir); 525062306a36Sopenharmony_ci } 525162306a36Sopenharmony_ci spin_unlock_bh(&adapter->fdir_fltr_lock); 525262306a36Sopenharmony_ci 525362306a36Sopenharmony_ci spin_lock_bh(&adapter->adv_rss_lock); 525462306a36Sopenharmony_ci list_for_each_entry_safe(rss, rsstmp, &adapter->adv_rss_list_head, 525562306a36Sopenharmony_ci list) { 525662306a36Sopenharmony_ci list_del(&rss->list); 525762306a36Sopenharmony_ci kfree(rss); 525862306a36Sopenharmony_ci } 525962306a36Sopenharmony_ci spin_unlock_bh(&adapter->adv_rss_lock); 526062306a36Sopenharmony_ci 526162306a36Sopenharmony_ci destroy_workqueue(adapter->wq); 526262306a36Sopenharmony_ci 526362306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 526462306a36Sopenharmony_ci 526562306a36Sopenharmony_ci free_netdev(netdev); 526662306a36Sopenharmony_ci 526762306a36Sopenharmony_ci pci_disable_device(pdev); 526862306a36Sopenharmony_ci} 526962306a36Sopenharmony_ci 527062306a36Sopenharmony_ci/** 527162306a36Sopenharmony_ci * iavf_shutdown - Shutdown the device in preparation for a reboot 527262306a36Sopenharmony_ci * @pdev: pci device structure 527362306a36Sopenharmony_ci **/ 527462306a36Sopenharmony_cistatic void iavf_shutdown(struct pci_dev *pdev) 527562306a36Sopenharmony_ci{ 527662306a36Sopenharmony_ci iavf_remove(pdev); 527762306a36Sopenharmony_ci 527862306a36Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) 527962306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 528062306a36Sopenharmony_ci} 528162306a36Sopenharmony_ci 528262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(iavf_pm_ops, iavf_suspend, iavf_resume); 528362306a36Sopenharmony_ci 528462306a36Sopenharmony_cistatic struct pci_driver iavf_driver = { 528562306a36Sopenharmony_ci .name = iavf_driver_name, 528662306a36Sopenharmony_ci .id_table = iavf_pci_tbl, 528762306a36Sopenharmony_ci .probe = iavf_probe, 528862306a36Sopenharmony_ci .remove = iavf_remove, 528962306a36Sopenharmony_ci .driver.pm = &iavf_pm_ops, 529062306a36Sopenharmony_ci .shutdown = iavf_shutdown, 529162306a36Sopenharmony_ci}; 529262306a36Sopenharmony_ci 529362306a36Sopenharmony_ci/** 529462306a36Sopenharmony_ci * iavf_init_module - Driver Registration Routine 529562306a36Sopenharmony_ci * 529662306a36Sopenharmony_ci * iavf_init_module is the first routine called when the driver is 529762306a36Sopenharmony_ci * loaded. All it does is register with the PCI subsystem. 529862306a36Sopenharmony_ci **/ 529962306a36Sopenharmony_cistatic int __init iavf_init_module(void) 530062306a36Sopenharmony_ci{ 530162306a36Sopenharmony_ci pr_info("iavf: %s\n", iavf_driver_string); 530262306a36Sopenharmony_ci 530362306a36Sopenharmony_ci pr_info("%s\n", iavf_copyright); 530462306a36Sopenharmony_ci 530562306a36Sopenharmony_ci return pci_register_driver(&iavf_driver); 530662306a36Sopenharmony_ci} 530762306a36Sopenharmony_ci 530862306a36Sopenharmony_cimodule_init(iavf_init_module); 530962306a36Sopenharmony_ci 531062306a36Sopenharmony_ci/** 531162306a36Sopenharmony_ci * iavf_exit_module - Driver Exit Cleanup Routine 531262306a36Sopenharmony_ci * 531362306a36Sopenharmony_ci * iavf_exit_module is called just before the driver is removed 531462306a36Sopenharmony_ci * from memory. 531562306a36Sopenharmony_ci **/ 531662306a36Sopenharmony_cistatic void __exit iavf_exit_module(void) 531762306a36Sopenharmony_ci{ 531862306a36Sopenharmony_ci pci_unregister_driver(&iavf_driver); 531962306a36Sopenharmony_ci} 532062306a36Sopenharmony_ci 532162306a36Sopenharmony_cimodule_exit(iavf_exit_module); 532262306a36Sopenharmony_ci 532362306a36Sopenharmony_ci/* iavf_main.c */ 5324