162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/types.h> 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include <linux/pci.h> 762306a36Sopenharmony_ci#include <linux/netdevice.h> 862306a36Sopenharmony_ci#include <linux/string.h> 962306a36Sopenharmony_ci#include <linux/etherdevice.h> 1062306a36Sopenharmony_ci#include <linux/phylink.h> 1162306a36Sopenharmony_ci#include <net/ip.h> 1262306a36Sopenharmony_ci#include <linux/if_vlan.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "../libwx/wx_type.h" 1562306a36Sopenharmony_ci#include "../libwx/wx_lib.h" 1662306a36Sopenharmony_ci#include "../libwx/wx_hw.h" 1762306a36Sopenharmony_ci#include "txgbe_type.h" 1862306a36Sopenharmony_ci#include "txgbe_hw.h" 1962306a36Sopenharmony_ci#include "txgbe_phy.h" 2062306a36Sopenharmony_ci#include "txgbe_ethtool.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cichar txgbe_driver_name[] = "txgbe"; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* txgbe_pci_tbl - PCI Device ID Table 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last 2762306a36Sopenharmony_ci * Last entry must be all 0s 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, 3062306a36Sopenharmony_ci * Class, Class Mask, private data (not used) } 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic const struct pci_device_id txgbe_pci_tbl[] = { 3362306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_SP1000), 0}, 3462306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_WX1820), 0}, 3562306a36Sopenharmony_ci /* required last entry */ 3662306a36Sopenharmony_ci { .device = 0 } 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define DEFAULT_DEBUG_LEVEL_SHIFT 3 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic void txgbe_check_minimum_link(struct wx *wx) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct pci_dev *pdev; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci pdev = wx->pdev; 4662306a36Sopenharmony_ci pcie_print_link_status(pdev); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/** 5062306a36Sopenharmony_ci * txgbe_enumerate_functions - Get the number of ports this device has 5162306a36Sopenharmony_ci * @wx: wx structure 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * This function enumerates the phsyical functions co-located on a single slot, 5462306a36Sopenharmony_ci * in order to determine how many ports a device has. This is most useful in 5562306a36Sopenharmony_ci * determining the required GT/s of PCIe bandwidth necessary for optimal 5662306a36Sopenharmony_ci * performance. 5762306a36Sopenharmony_ci **/ 5862306a36Sopenharmony_cistatic int txgbe_enumerate_functions(struct wx *wx) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct pci_dev *entry, *pdev = wx->pdev; 6162306a36Sopenharmony_ci int physfns = 0; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci list_for_each_entry(entry, &pdev->bus->devices, bus_list) { 6462306a36Sopenharmony_ci /* When the devices on the bus don't all match our device ID, 6562306a36Sopenharmony_ci * we can't reliably determine the correct number of 6662306a36Sopenharmony_ci * functions. This can occur if a function has been direct 6762306a36Sopenharmony_ci * attached to a virtual machine using VT-d. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci if (entry->vendor != pdev->vendor || 7062306a36Sopenharmony_ci entry->device != pdev->device) 7162306a36Sopenharmony_ci return -EINVAL; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci physfns++; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return physfns; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/** 8062306a36Sopenharmony_ci * txgbe_irq_enable - Enable default interrupt generation settings 8162306a36Sopenharmony_ci * @wx: pointer to private structure 8262306a36Sopenharmony_ci * @queues: enable irqs for queues 8362306a36Sopenharmony_ci **/ 8462306a36Sopenharmony_cistatic void txgbe_irq_enable(struct wx *wx, bool queues) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* unmask interrupt */ 8962306a36Sopenharmony_ci wx_intr_enable(wx, TXGBE_INTR_MISC(wx)); 9062306a36Sopenharmony_ci if (queues) 9162306a36Sopenharmony_ci wx_intr_enable(wx, TXGBE_INTR_QALL(wx)); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * txgbe_intr - msi/legacy mode Interrupt Handler 9662306a36Sopenharmony_ci * @irq: interrupt number 9762306a36Sopenharmony_ci * @data: pointer to a network interface device structure 9862306a36Sopenharmony_ci **/ 9962306a36Sopenharmony_cistatic irqreturn_t txgbe_intr(int __always_unused irq, void *data) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct wx_q_vector *q_vector; 10262306a36Sopenharmony_ci struct wx *wx = data; 10362306a36Sopenharmony_ci struct pci_dev *pdev; 10462306a36Sopenharmony_ci u32 eicr; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci q_vector = wx->q_vector[0]; 10762306a36Sopenharmony_ci pdev = wx->pdev; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci eicr = wx_misc_isb(wx, WX_ISB_VEC0); 11062306a36Sopenharmony_ci if (!eicr) { 11162306a36Sopenharmony_ci /* shared interrupt alert! 11262306a36Sopenharmony_ci * the interrupt that we masked before the ICR read. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci if (netif_running(wx->netdev)) 11562306a36Sopenharmony_ci txgbe_irq_enable(wx, true); 11662306a36Sopenharmony_ci return IRQ_NONE; /* Not our interrupt */ 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci wx->isb_mem[WX_ISB_VEC0] = 0; 11962306a36Sopenharmony_ci if (!(pdev->msi_enabled)) 12062306a36Sopenharmony_ci wr32(wx, WX_PX_INTA, 1); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci wx->isb_mem[WX_ISB_MISC] = 0; 12362306a36Sopenharmony_ci /* would disable interrupts here but it is auto disabled */ 12462306a36Sopenharmony_ci napi_schedule_irqoff(&q_vector->napi); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* re-enable link(maybe) and non-queue interrupts, no flush. 12762306a36Sopenharmony_ci * txgbe_poll will re-enable the queue interrupts 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci if (netif_running(wx->netdev)) 13062306a36Sopenharmony_ci txgbe_irq_enable(wx, false); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return IRQ_HANDLED; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/** 13662306a36Sopenharmony_ci * txgbe_request_msix_irqs - Initialize MSI-X interrupts 13762306a36Sopenharmony_ci * @wx: board private structure 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * Allocate MSI-X vectors and request interrupts from the kernel. 14062306a36Sopenharmony_ci **/ 14162306a36Sopenharmony_cistatic int txgbe_request_msix_irqs(struct wx *wx) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 14462306a36Sopenharmony_ci int vector, err; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci for (vector = 0; vector < wx->num_q_vectors; vector++) { 14762306a36Sopenharmony_ci struct wx_q_vector *q_vector = wx->q_vector[vector]; 14862306a36Sopenharmony_ci struct msix_entry *entry = &wx->msix_entries[vector]; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (q_vector->tx.ring && q_vector->rx.ring) 15162306a36Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name) - 1, 15262306a36Sopenharmony_ci "%s-TxRx-%d", netdev->name, entry->entry); 15362306a36Sopenharmony_ci else 15462306a36Sopenharmony_ci /* skip this unused q_vector */ 15562306a36Sopenharmony_ci continue; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci err = request_irq(entry->vector, wx_msix_clean_rings, 0, 15862306a36Sopenharmony_ci q_vector->name, q_vector); 15962306a36Sopenharmony_ci if (err) { 16062306a36Sopenharmony_ci wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", 16162306a36Sopenharmony_ci q_vector->name, err); 16262306a36Sopenharmony_ci goto free_queue_irqs; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cifree_queue_irqs: 16962306a36Sopenharmony_ci while (vector) { 17062306a36Sopenharmony_ci vector--; 17162306a36Sopenharmony_ci free_irq(wx->msix_entries[vector].vector, 17262306a36Sopenharmony_ci wx->q_vector[vector]); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci wx_reset_interrupt_capability(wx); 17562306a36Sopenharmony_ci return err; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/** 17962306a36Sopenharmony_ci * txgbe_request_irq - initialize interrupts 18062306a36Sopenharmony_ci * @wx: board private structure 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * Attempt to configure interrupts using the best available 18362306a36Sopenharmony_ci * capabilities of the hardware and kernel. 18462306a36Sopenharmony_ci **/ 18562306a36Sopenharmony_cistatic int txgbe_request_irq(struct wx *wx) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 18862306a36Sopenharmony_ci struct pci_dev *pdev = wx->pdev; 18962306a36Sopenharmony_ci int err; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (pdev->msix_enabled) 19262306a36Sopenharmony_ci err = txgbe_request_msix_irqs(wx); 19362306a36Sopenharmony_ci else if (pdev->msi_enabled) 19462306a36Sopenharmony_ci err = request_irq(wx->pdev->irq, &txgbe_intr, 0, 19562306a36Sopenharmony_ci netdev->name, wx); 19662306a36Sopenharmony_ci else 19762306a36Sopenharmony_ci err = request_irq(wx->pdev->irq, &txgbe_intr, IRQF_SHARED, 19862306a36Sopenharmony_ci netdev->name, wx); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (err) 20162306a36Sopenharmony_ci wx_err(wx, "request_irq failed, Error %d\n", err); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return err; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void txgbe_up_complete(struct wx *wx) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 20962306a36Sopenharmony_ci struct txgbe *txgbe; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci wx_control_hw(wx, true); 21262306a36Sopenharmony_ci wx_configure_vectors(wx); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* make sure to complete pre-operations */ 21562306a36Sopenharmony_ci smp_mb__before_atomic(); 21662306a36Sopenharmony_ci wx_napi_enable_all(wx); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci txgbe = netdev_to_txgbe(netdev); 21962306a36Sopenharmony_ci phylink_start(txgbe->phylink); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* clear any pending interrupts, may auto mask */ 22262306a36Sopenharmony_ci rd32(wx, WX_PX_IC(0)); 22362306a36Sopenharmony_ci rd32(wx, WX_PX_IC(1)); 22462306a36Sopenharmony_ci rd32(wx, WX_PX_MISC_IC); 22562306a36Sopenharmony_ci txgbe_irq_enable(wx, true); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* enable transmits */ 22862306a36Sopenharmony_ci netif_tx_start_all_queues(netdev); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void txgbe_reset(struct wx *wx) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 23462306a36Sopenharmony_ci u8 old_addr[ETH_ALEN]; 23562306a36Sopenharmony_ci int err; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci err = txgbe_reset_hw(wx); 23862306a36Sopenharmony_ci if (err != 0) 23962306a36Sopenharmony_ci wx_err(wx, "Hardware Error: %d\n", err); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci wx_start_hw(wx); 24262306a36Sopenharmony_ci /* do not flush user set addresses */ 24362306a36Sopenharmony_ci memcpy(old_addr, &wx->mac_table[0].addr, netdev->addr_len); 24462306a36Sopenharmony_ci wx_flush_sw_mac_table(wx); 24562306a36Sopenharmony_ci wx_mac_set_default_filter(wx, old_addr); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic void txgbe_disable_device(struct wx *wx) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 25162306a36Sopenharmony_ci u32 i; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci wx_disable_pcie_master(wx); 25462306a36Sopenharmony_ci /* disable receives */ 25562306a36Sopenharmony_ci wx_disable_rx(wx); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* disable all enabled rx queues */ 25862306a36Sopenharmony_ci for (i = 0; i < wx->num_rx_queues; i++) 25962306a36Sopenharmony_ci /* this call also flushes the previous write */ 26062306a36Sopenharmony_ci wx_disable_rx_queue(wx, wx->rx_ring[i]); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 26362306a36Sopenharmony_ci netif_tx_disable(netdev); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci wx_irq_disable(wx); 26662306a36Sopenharmony_ci wx_napi_disable_all(wx); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (wx->bus.func < 2) 26962306a36Sopenharmony_ci wr32m(wx, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wx->bus.func), 0); 27062306a36Sopenharmony_ci else 27162306a36Sopenharmony_ci wx_err(wx, "%s: invalid bus lan id %d\n", 27262306a36Sopenharmony_ci __func__, wx->bus.func); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) || 27562306a36Sopenharmony_ci ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) { 27662306a36Sopenharmony_ci /* disable mac transmiter */ 27762306a36Sopenharmony_ci wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* disable transmits in the hardware now that interrupts are off */ 28162306a36Sopenharmony_ci for (i = 0; i < wx->num_tx_queues; i++) { 28262306a36Sopenharmony_ci u8 reg_idx = wx->tx_ring[i]->reg_idx; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* Disable the Tx DMA engine */ 28862306a36Sopenharmony_ci wr32m(wx, WX_TDM_CTL, WX_TDM_CTL_TE, 0); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic void txgbe_down(struct wx *wx) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct txgbe *txgbe = netdev_to_txgbe(wx->netdev); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci txgbe_disable_device(wx); 29662306a36Sopenharmony_ci txgbe_reset(wx); 29762306a36Sopenharmony_ci phylink_stop(txgbe->phylink); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci wx_clean_all_tx_rings(wx); 30062306a36Sopenharmony_ci wx_clean_all_rx_rings(wx); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/** 30462306a36Sopenharmony_ci * txgbe_init_type_code - Initialize the shared code 30562306a36Sopenharmony_ci * @wx: pointer to hardware structure 30662306a36Sopenharmony_ci **/ 30762306a36Sopenharmony_cistatic void txgbe_init_type_code(struct wx *wx) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci u8 device_type = wx->subsystem_device_id & 0xF0; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci switch (wx->device_id) { 31262306a36Sopenharmony_ci case TXGBE_DEV_ID_SP1000: 31362306a36Sopenharmony_ci case TXGBE_DEV_ID_WX1820: 31462306a36Sopenharmony_ci wx->mac.type = wx_mac_sp; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci default: 31762306a36Sopenharmony_ci wx->mac.type = wx_mac_unknown; 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci switch (device_type) { 32262306a36Sopenharmony_ci case TXGBE_ID_SFP: 32362306a36Sopenharmony_ci wx->media_type = sp_media_fiber; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case TXGBE_ID_XAUI: 32662306a36Sopenharmony_ci case TXGBE_ID_SGMII: 32762306a36Sopenharmony_ci wx->media_type = sp_media_copper; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case TXGBE_ID_KR_KX_KX4: 33062306a36Sopenharmony_ci case TXGBE_ID_MAC_XAUI: 33162306a36Sopenharmony_ci case TXGBE_ID_MAC_SGMII: 33262306a36Sopenharmony_ci wx->media_type = sp_media_backplane; 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci case TXGBE_ID_SFI_XAUI: 33562306a36Sopenharmony_ci if (wx->bus.func == 0) 33662306a36Sopenharmony_ci wx->media_type = sp_media_fiber; 33762306a36Sopenharmony_ci else 33862306a36Sopenharmony_ci wx->media_type = sp_media_copper; 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci default: 34162306a36Sopenharmony_ci wx->media_type = sp_media_unknown; 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/** 34762306a36Sopenharmony_ci * txgbe_sw_init - Initialize general software structures (struct wx) 34862306a36Sopenharmony_ci * @wx: board private structure to initialize 34962306a36Sopenharmony_ci **/ 35062306a36Sopenharmony_cistatic int txgbe_sw_init(struct wx *wx) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci u16 msix_count = 0; 35362306a36Sopenharmony_ci int err; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci wx->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES; 35662306a36Sopenharmony_ci wx->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES; 35762306a36Sopenharmony_ci wx->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES; 35862306a36Sopenharmony_ci wx->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE; 35962306a36Sopenharmony_ci wx->mac.vft_size = TXGBE_SP_VFT_TBL_SIZE; 36062306a36Sopenharmony_ci wx->mac.rx_pb_size = TXGBE_SP_RX_PB_SIZE; 36162306a36Sopenharmony_ci wx->mac.tx_pb_size = TXGBE_SP_TDB_PB_SZ; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* PCI config space info */ 36462306a36Sopenharmony_ci err = wx_sw_init(wx); 36562306a36Sopenharmony_ci if (err < 0) 36662306a36Sopenharmony_ci return err; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci txgbe_init_type_code(wx); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Set common capability flags and settings */ 37162306a36Sopenharmony_ci wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS; 37262306a36Sopenharmony_ci err = wx_get_pcie_msix_counts(wx, &msix_count, TXGBE_MAX_MSIX_VECTORS); 37362306a36Sopenharmony_ci if (err) 37462306a36Sopenharmony_ci wx_err(wx, "Do not support MSI-X\n"); 37562306a36Sopenharmony_ci wx->mac.max_msix_vectors = msix_count; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* enable itr by default in dynamic mode */ 37862306a36Sopenharmony_ci wx->rx_itr_setting = 1; 37962306a36Sopenharmony_ci wx->tx_itr_setting = 1; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* set default ring sizes */ 38262306a36Sopenharmony_ci wx->tx_ring_count = TXGBE_DEFAULT_TXD; 38362306a36Sopenharmony_ci wx->rx_ring_count = TXGBE_DEFAULT_RXD; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* set default work limits */ 38662306a36Sopenharmony_ci wx->tx_work_limit = TXGBE_DEFAULT_TX_WORK; 38762306a36Sopenharmony_ci wx->rx_work_limit = TXGBE_DEFAULT_RX_WORK; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/** 39362306a36Sopenharmony_ci * txgbe_open - Called when a network interface is made active 39462306a36Sopenharmony_ci * @netdev: network interface device structure 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * Returns 0 on success, negative value on failure 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * The open entry point is called when a network interface is made 39962306a36Sopenharmony_ci * active by the system (IFF_UP). 40062306a36Sopenharmony_ci **/ 40162306a36Sopenharmony_cistatic int txgbe_open(struct net_device *netdev) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct wx *wx = netdev_priv(netdev); 40462306a36Sopenharmony_ci int err; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci err = wx_setup_resources(wx); 40762306a36Sopenharmony_ci if (err) 40862306a36Sopenharmony_ci goto err_reset; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci wx_configure(wx); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci err = txgbe_request_irq(wx); 41362306a36Sopenharmony_ci if (err) 41462306a36Sopenharmony_ci goto err_free_isb; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* Notify the stack of the actual queue counts. */ 41762306a36Sopenharmony_ci err = netif_set_real_num_tx_queues(netdev, wx->num_tx_queues); 41862306a36Sopenharmony_ci if (err) 41962306a36Sopenharmony_ci goto err_free_irq; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci err = netif_set_real_num_rx_queues(netdev, wx->num_rx_queues); 42262306a36Sopenharmony_ci if (err) 42362306a36Sopenharmony_ci goto err_free_irq; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci txgbe_up_complete(wx); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cierr_free_irq: 43062306a36Sopenharmony_ci wx_free_irq(wx); 43162306a36Sopenharmony_cierr_free_isb: 43262306a36Sopenharmony_ci wx_free_isb_resources(wx); 43362306a36Sopenharmony_cierr_reset: 43462306a36Sopenharmony_ci txgbe_reset(wx); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return err; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/** 44062306a36Sopenharmony_ci * txgbe_close_suspend - actions necessary to both suspend and close flows 44162306a36Sopenharmony_ci * @wx: the private wx struct 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * This function should contain the necessary work common to both suspending 44462306a36Sopenharmony_ci * and closing of the device. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_cistatic void txgbe_close_suspend(struct wx *wx) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci txgbe_disable_device(wx); 44962306a36Sopenharmony_ci wx_free_resources(wx); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/** 45362306a36Sopenharmony_ci * txgbe_close - Disables a network interface 45462306a36Sopenharmony_ci * @netdev: network interface device structure 45562306a36Sopenharmony_ci * 45662306a36Sopenharmony_ci * Returns 0, this is not allowed to fail 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * The close entry point is called when an interface is de-activated 45962306a36Sopenharmony_ci * by the OS. The hardware is still under the drivers control, but 46062306a36Sopenharmony_ci * needs to be disabled. A global MAC reset is issued to stop the 46162306a36Sopenharmony_ci * hardware, and all transmit and receive resources are freed. 46262306a36Sopenharmony_ci **/ 46362306a36Sopenharmony_cistatic int txgbe_close(struct net_device *netdev) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct wx *wx = netdev_priv(netdev); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci txgbe_down(wx); 46862306a36Sopenharmony_ci wx_free_irq(wx); 46962306a36Sopenharmony_ci wx_free_resources(wx); 47062306a36Sopenharmony_ci wx_control_hw(wx, false); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void txgbe_dev_shutdown(struct pci_dev *pdev) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct wx *wx = pci_get_drvdata(pdev); 47862306a36Sopenharmony_ci struct net_device *netdev; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci netdev = wx->netdev; 48162306a36Sopenharmony_ci netif_device_detach(netdev); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci rtnl_lock(); 48462306a36Sopenharmony_ci if (netif_running(netdev)) 48562306a36Sopenharmony_ci txgbe_close_suspend(wx); 48662306a36Sopenharmony_ci rtnl_unlock(); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci wx_control_hw(wx, false); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci pci_disable_device(pdev); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic void txgbe_shutdown(struct pci_dev *pdev) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci txgbe_dev_shutdown(pdev); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) { 49862306a36Sopenharmony_ci pci_wake_from_d3(pdev, false); 49962306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic const struct net_device_ops txgbe_netdev_ops = { 50462306a36Sopenharmony_ci .ndo_open = txgbe_open, 50562306a36Sopenharmony_ci .ndo_stop = txgbe_close, 50662306a36Sopenharmony_ci .ndo_change_mtu = wx_change_mtu, 50762306a36Sopenharmony_ci .ndo_start_xmit = wx_xmit_frame, 50862306a36Sopenharmony_ci .ndo_set_rx_mode = wx_set_rx_mode, 50962306a36Sopenharmony_ci .ndo_set_features = wx_set_features, 51062306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 51162306a36Sopenharmony_ci .ndo_set_mac_address = wx_set_mac, 51262306a36Sopenharmony_ci .ndo_get_stats64 = wx_get_stats64, 51362306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = wx_vlan_rx_add_vid, 51462306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = wx_vlan_rx_kill_vid, 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/** 51862306a36Sopenharmony_ci * txgbe_probe - Device Initialization Routine 51962306a36Sopenharmony_ci * @pdev: PCI device information struct 52062306a36Sopenharmony_ci * @ent: entry in txgbe_pci_tbl 52162306a36Sopenharmony_ci * 52262306a36Sopenharmony_ci * Returns 0 on success, negative on failure 52362306a36Sopenharmony_ci * 52462306a36Sopenharmony_ci * txgbe_probe initializes an adapter identified by a pci_dev structure. 52562306a36Sopenharmony_ci * The OS initialization, configuring of the wx private structure, 52662306a36Sopenharmony_ci * and a hardware reset occur. 52762306a36Sopenharmony_ci **/ 52862306a36Sopenharmony_cistatic int txgbe_probe(struct pci_dev *pdev, 52962306a36Sopenharmony_ci const struct pci_device_id __always_unused *ent) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct net_device *netdev; 53262306a36Sopenharmony_ci int err, expected_gts; 53362306a36Sopenharmony_ci struct wx *wx = NULL; 53462306a36Sopenharmony_ci struct txgbe *txgbe; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci u16 eeprom_verh = 0, eeprom_verl = 0, offset = 0; 53762306a36Sopenharmony_ci u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0; 53862306a36Sopenharmony_ci u16 build = 0, major = 0, patch = 0; 53962306a36Sopenharmony_ci u8 part_str[TXGBE_PBANUM_LENGTH]; 54062306a36Sopenharmony_ci u32 etrack_id = 0; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci err = pci_enable_device_mem(pdev); 54362306a36Sopenharmony_ci if (err) 54462306a36Sopenharmony_ci return err; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 54762306a36Sopenharmony_ci if (err) { 54862306a36Sopenharmony_ci dev_err(&pdev->dev, 54962306a36Sopenharmony_ci "No usable DMA configuration, aborting\n"); 55062306a36Sopenharmony_ci goto err_pci_disable_dev; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci err = pci_request_selected_regions(pdev, 55462306a36Sopenharmony_ci pci_select_bars(pdev, IORESOURCE_MEM), 55562306a36Sopenharmony_ci txgbe_driver_name); 55662306a36Sopenharmony_ci if (err) { 55762306a36Sopenharmony_ci dev_err(&pdev->dev, 55862306a36Sopenharmony_ci "pci_request_selected_regions failed 0x%x\n", err); 55962306a36Sopenharmony_ci goto err_pci_disable_dev; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci pci_set_master(pdev); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci netdev = devm_alloc_etherdev_mqs(&pdev->dev, 56562306a36Sopenharmony_ci sizeof(struct wx), 56662306a36Sopenharmony_ci TXGBE_MAX_TX_QUEUES, 56762306a36Sopenharmony_ci TXGBE_MAX_RX_QUEUES); 56862306a36Sopenharmony_ci if (!netdev) { 56962306a36Sopenharmony_ci err = -ENOMEM; 57062306a36Sopenharmony_ci goto err_pci_release_regions; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci wx = netdev_priv(netdev); 57662306a36Sopenharmony_ci wx->netdev = netdev; 57762306a36Sopenharmony_ci wx->pdev = pdev; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci wx->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci wx->hw_addr = devm_ioremap(&pdev->dev, 58262306a36Sopenharmony_ci pci_resource_start(pdev, 0), 58362306a36Sopenharmony_ci pci_resource_len(pdev, 0)); 58462306a36Sopenharmony_ci if (!wx->hw_addr) { 58562306a36Sopenharmony_ci err = -EIO; 58662306a36Sopenharmony_ci goto err_pci_release_regions; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci wx->driver_name = txgbe_driver_name; 59062306a36Sopenharmony_ci txgbe_set_ethtool_ops(netdev); 59162306a36Sopenharmony_ci netdev->netdev_ops = &txgbe_netdev_ops; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* setup the private structure */ 59462306a36Sopenharmony_ci err = txgbe_sw_init(wx); 59562306a36Sopenharmony_ci if (err) 59662306a36Sopenharmony_ci goto err_free_mac_table; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* check if flash load is done after hw power up */ 59962306a36Sopenharmony_ci err = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_PERST); 60062306a36Sopenharmony_ci if (err) 60162306a36Sopenharmony_ci goto err_free_mac_table; 60262306a36Sopenharmony_ci err = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_PWRRST); 60362306a36Sopenharmony_ci if (err) 60462306a36Sopenharmony_ci goto err_free_mac_table; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci err = wx_mng_present(wx); 60762306a36Sopenharmony_ci if (err) { 60862306a36Sopenharmony_ci dev_err(&pdev->dev, "Management capability is not present\n"); 60962306a36Sopenharmony_ci goto err_free_mac_table; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci err = txgbe_reset_hw(wx); 61362306a36Sopenharmony_ci if (err) { 61462306a36Sopenharmony_ci dev_err(&pdev->dev, "HW Init failed: %d\n", err); 61562306a36Sopenharmony_ci goto err_free_mac_table; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci netdev->features = NETIF_F_SG | 61962306a36Sopenharmony_ci NETIF_F_TSO | 62062306a36Sopenharmony_ci NETIF_F_TSO6 | 62162306a36Sopenharmony_ci NETIF_F_RXHASH | 62262306a36Sopenharmony_ci NETIF_F_RXCSUM | 62362306a36Sopenharmony_ci NETIF_F_HW_CSUM; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci netdev->gso_partial_features = NETIF_F_GSO_ENCAP_ALL; 62662306a36Sopenharmony_ci netdev->features |= netdev->gso_partial_features; 62762306a36Sopenharmony_ci netdev->features |= NETIF_F_SCTP_CRC; 62862306a36Sopenharmony_ci netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID; 62962306a36Sopenharmony_ci netdev->hw_enc_features |= netdev->vlan_features; 63062306a36Sopenharmony_ci netdev->features |= NETIF_F_VLAN_FEATURES; 63162306a36Sopenharmony_ci /* copy netdev features into list of user selectable features */ 63262306a36Sopenharmony_ci netdev->hw_features |= netdev->features | NETIF_F_RXALL; 63362306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC; 63462306a36Sopenharmony_ci netdev->features |= NETIF_F_HIGHDMA; 63562306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_GRO; 63662306a36Sopenharmony_ci netdev->features |= NETIF_F_GRO; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci netdev->priv_flags |= IFF_UNICAST_FLT; 63962306a36Sopenharmony_ci netdev->priv_flags |= IFF_SUPP_NOFCS; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci netdev->min_mtu = ETH_MIN_MTU; 64262306a36Sopenharmony_ci netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE - 64362306a36Sopenharmony_ci (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* make sure the EEPROM is good */ 64662306a36Sopenharmony_ci err = txgbe_validate_eeprom_checksum(wx, NULL); 64762306a36Sopenharmony_ci if (err != 0) { 64862306a36Sopenharmony_ci dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); 64962306a36Sopenharmony_ci wr32(wx, WX_MIS_RST, WX_MIS_RST_SW_RST); 65062306a36Sopenharmony_ci err = -EIO; 65162306a36Sopenharmony_ci goto err_free_mac_table; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci eth_hw_addr_set(netdev, wx->mac.perm_addr); 65562306a36Sopenharmony_ci wx_mac_set_default_filter(wx, wx->mac.perm_addr); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci err = wx_init_interrupt_scheme(wx); 65862306a36Sopenharmony_ci if (err) 65962306a36Sopenharmony_ci goto err_free_mac_table; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* Save off EEPROM version number and Option Rom version which 66262306a36Sopenharmony_ci * together make a unique identify for the eeprom 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci wx_read_ee_hostif(wx, 66562306a36Sopenharmony_ci wx->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_H, 66662306a36Sopenharmony_ci &eeprom_verh); 66762306a36Sopenharmony_ci wx_read_ee_hostif(wx, 66862306a36Sopenharmony_ci wx->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_L, 66962306a36Sopenharmony_ci &eeprom_verl); 67062306a36Sopenharmony_ci etrack_id = (eeprom_verh << 16) | eeprom_verl; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci wx_read_ee_hostif(wx, 67362306a36Sopenharmony_ci wx->eeprom.sw_region_offset + TXGBE_ISCSI_BOOT_CONFIG, 67462306a36Sopenharmony_ci &offset); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Make sure offset to SCSI block is valid */ 67762306a36Sopenharmony_ci if (!(offset == 0x0) && !(offset == 0xffff)) { 67862306a36Sopenharmony_ci wx_read_ee_hostif(wx, offset + 0x84, &eeprom_cfg_blkh); 67962306a36Sopenharmony_ci wx_read_ee_hostif(wx, offset + 0x83, &eeprom_cfg_blkl); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* Only display Option Rom if exist */ 68262306a36Sopenharmony_ci if (eeprom_cfg_blkl && eeprom_cfg_blkh) { 68362306a36Sopenharmony_ci major = eeprom_cfg_blkl >> 8; 68462306a36Sopenharmony_ci build = (eeprom_cfg_blkl << 8) | (eeprom_cfg_blkh >> 8); 68562306a36Sopenharmony_ci patch = eeprom_cfg_blkh & 0x00ff; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci snprintf(wx->eeprom_id, sizeof(wx->eeprom_id), 68862306a36Sopenharmony_ci "0x%08x, %d.%d.%d", etrack_id, major, build, 68962306a36Sopenharmony_ci patch); 69062306a36Sopenharmony_ci } else { 69162306a36Sopenharmony_ci snprintf(wx->eeprom_id, sizeof(wx->eeprom_id), 69262306a36Sopenharmony_ci "0x%08x", etrack_id); 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci } else { 69562306a36Sopenharmony_ci snprintf(wx->eeprom_id, sizeof(wx->eeprom_id), 69662306a36Sopenharmony_ci "0x%08x", etrack_id); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (etrack_id < 0x20010) 70062306a36Sopenharmony_ci dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n"); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL); 70362306a36Sopenharmony_ci if (!txgbe) { 70462306a36Sopenharmony_ci err = -ENOMEM; 70562306a36Sopenharmony_ci goto err_release_hw; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci txgbe->wx = wx; 70962306a36Sopenharmony_ci wx->priv = txgbe; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci err = txgbe_init_phy(txgbe); 71262306a36Sopenharmony_ci if (err) 71362306a36Sopenharmony_ci goto err_release_hw; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci err = register_netdev(netdev); 71662306a36Sopenharmony_ci if (err) 71762306a36Sopenharmony_ci goto err_remove_phy; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci pci_set_drvdata(pdev, wx); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* calculate the expected PCIe bandwidth required for optimal 72462306a36Sopenharmony_ci * performance. Note that some older parts will never have enough 72562306a36Sopenharmony_ci * bandwidth due to being older generation PCIe parts. We clamp these 72662306a36Sopenharmony_ci * parts to ensure that no warning is displayed, as this could confuse 72762306a36Sopenharmony_ci * users otherwise. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci expected_gts = txgbe_enumerate_functions(wx) * 10; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* don't check link if we failed to enumerate functions */ 73262306a36Sopenharmony_ci if (expected_gts > 0) 73362306a36Sopenharmony_ci txgbe_check_minimum_link(wx); 73462306a36Sopenharmony_ci else 73562306a36Sopenharmony_ci dev_warn(&pdev->dev, "Failed to enumerate PF devices.\n"); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* First try to read PBA as a string */ 73862306a36Sopenharmony_ci err = txgbe_read_pba_string(wx, part_str, TXGBE_PBANUM_LENGTH); 73962306a36Sopenharmony_ci if (err) 74062306a36Sopenharmony_ci strncpy(part_str, "Unknown", TXGBE_PBANUM_LENGTH); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci netif_info(wx, probe, netdev, "%pM\n", netdev->dev_addr); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cierr_remove_phy: 74762306a36Sopenharmony_ci txgbe_remove_phy(txgbe); 74862306a36Sopenharmony_cierr_release_hw: 74962306a36Sopenharmony_ci wx_clear_interrupt_scheme(wx); 75062306a36Sopenharmony_ci wx_control_hw(wx, false); 75162306a36Sopenharmony_cierr_free_mac_table: 75262306a36Sopenharmony_ci kfree(wx->mac_table); 75362306a36Sopenharmony_cierr_pci_release_regions: 75462306a36Sopenharmony_ci pci_release_selected_regions(pdev, 75562306a36Sopenharmony_ci pci_select_bars(pdev, IORESOURCE_MEM)); 75662306a36Sopenharmony_cierr_pci_disable_dev: 75762306a36Sopenharmony_ci pci_disable_device(pdev); 75862306a36Sopenharmony_ci return err; 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci/** 76262306a36Sopenharmony_ci * txgbe_remove - Device Removal Routine 76362306a36Sopenharmony_ci * @pdev: PCI device information struct 76462306a36Sopenharmony_ci * 76562306a36Sopenharmony_ci * txgbe_remove is called by the PCI subsystem to alert the driver 76662306a36Sopenharmony_ci * that it should release a PCI device. The could be caused by a 76762306a36Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from 76862306a36Sopenharmony_ci * memory. 76962306a36Sopenharmony_ci **/ 77062306a36Sopenharmony_cistatic void txgbe_remove(struct pci_dev *pdev) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct wx *wx = pci_get_drvdata(pdev); 77362306a36Sopenharmony_ci struct txgbe *txgbe = wx->priv; 77462306a36Sopenharmony_ci struct net_device *netdev; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci netdev = wx->netdev; 77762306a36Sopenharmony_ci unregister_netdev(netdev); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci txgbe_remove_phy(txgbe); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci pci_release_selected_regions(pdev, 78262306a36Sopenharmony_ci pci_select_bars(pdev, IORESOURCE_MEM)); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci kfree(wx->mac_table); 78562306a36Sopenharmony_ci wx_clear_interrupt_scheme(wx); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci pci_disable_device(pdev); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic struct pci_driver txgbe_driver = { 79162306a36Sopenharmony_ci .name = txgbe_driver_name, 79262306a36Sopenharmony_ci .id_table = txgbe_pci_tbl, 79362306a36Sopenharmony_ci .probe = txgbe_probe, 79462306a36Sopenharmony_ci .remove = txgbe_remove, 79562306a36Sopenharmony_ci .shutdown = txgbe_shutdown, 79662306a36Sopenharmony_ci}; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cimodule_pci_driver(txgbe_driver); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, txgbe_pci_tbl); 80162306a36Sopenharmony_ciMODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>"); 80262306a36Sopenharmony_ciMODULE_DESCRIPTION("WangXun(R) 10 Gigabit PCI Express Network Driver"); 80362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 804