162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2019 - 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 <net/ip.h> 1162306a36Sopenharmony_ci#include <linux/phy.h> 1262306a36Sopenharmony_ci#include <linux/if_vlan.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "../libwx/wx_type.h" 1562306a36Sopenharmony_ci#include "../libwx/wx_hw.h" 1662306a36Sopenharmony_ci#include "../libwx/wx_lib.h" 1762306a36Sopenharmony_ci#include "ngbe_type.h" 1862306a36Sopenharmony_ci#include "ngbe_mdio.h" 1962306a36Sopenharmony_ci#include "ngbe_hw.h" 2062306a36Sopenharmony_ci#include "ngbe_ethtool.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cichar ngbe_driver_name[] = "ngbe"; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* ngbe_pci_tbl - PCI Device ID Table 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, 2762306a36Sopenharmony_ci * Class, Class Mask, private data (not used) } 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic const struct pci_device_id ngbe_pci_tbl[] = { 3062306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL_W), 0}, 3162306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A2), 0}, 3262306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A2S), 0}, 3362306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A4), 0}, 3462306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A4S), 0}, 3562306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL2), 0}, 3662306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL2S), 0}, 3762306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL4), 0}, 3862306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL4S), 0}, 3962306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860LC), 0}, 4062306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A1), 0}, 4162306a36Sopenharmony_ci { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A1L), 0}, 4262306a36Sopenharmony_ci /* required last entry */ 4362306a36Sopenharmony_ci { .device = 0 } 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/** 4762306a36Sopenharmony_ci * ngbe_init_type_code - Initialize the shared code 4862306a36Sopenharmony_ci * @wx: pointer to hardware structure 4962306a36Sopenharmony_ci **/ 5062306a36Sopenharmony_cistatic void ngbe_init_type_code(struct wx *wx) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci int wol_mask = 0, ncsi_mask = 0; 5362306a36Sopenharmony_ci u16 type_mask = 0, val; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci wx->mac.type = wx_mac_em; 5662306a36Sopenharmony_ci type_mask = (u16)(wx->subsystem_device_id & NGBE_OEM_MASK); 5762306a36Sopenharmony_ci ncsi_mask = wx->subsystem_device_id & NGBE_NCSI_MASK; 5862306a36Sopenharmony_ci wol_mask = wx->subsystem_device_id & NGBE_WOL_MASK; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci val = rd32(wx, WX_CFG_PORT_ST); 6162306a36Sopenharmony_ci wx->mac_type = (val & BIT(7)) >> 7 ? 6262306a36Sopenharmony_ci em_mac_type_rgmii : 6362306a36Sopenharmony_ci em_mac_type_mdi; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci wx->wol_hw_supported = (wol_mask == NGBE_WOL_SUP) ? 1 : 0; 6662306a36Sopenharmony_ci wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK || 6762306a36Sopenharmony_ci type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci switch (type_mask) { 7062306a36Sopenharmony_ci case NGBE_SUBID_LY_YT8521S_SFP: 7162306a36Sopenharmony_ci case NGBE_SUBID_LY_M88E1512_SFP: 7262306a36Sopenharmony_ci case NGBE_SUBID_YT8521S_SFP_GPIO: 7362306a36Sopenharmony_ci case NGBE_SUBID_INTERNAL_YT8521S_SFP_GPIO: 7462306a36Sopenharmony_ci wx->gpio_ctrl = 1; 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci default: 7762306a36Sopenharmony_ci wx->gpio_ctrl = 0; 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * ngbe_init_rss_key - Initialize wx RSS key 8462306a36Sopenharmony_ci * @wx: device handle 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Allocates and initializes the RSS key if it is not allocated. 8762306a36Sopenharmony_ci **/ 8862306a36Sopenharmony_cistatic inline int ngbe_init_rss_key(struct wx *wx) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci u32 *rss_key; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (!wx->rss_key) { 9362306a36Sopenharmony_ci rss_key = kzalloc(WX_RSS_KEY_SIZE, GFP_KERNEL); 9462306a36Sopenharmony_ci if (unlikely(!rss_key)) 9562306a36Sopenharmony_ci return -ENOMEM; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci netdev_rss_key_fill(rss_key, WX_RSS_KEY_SIZE); 9862306a36Sopenharmony_ci wx->rss_key = rss_key; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * ngbe_sw_init - Initialize general software structures 10662306a36Sopenharmony_ci * @wx: board private structure to initialize 10762306a36Sopenharmony_ci **/ 10862306a36Sopenharmony_cistatic int ngbe_sw_init(struct wx *wx) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct pci_dev *pdev = wx->pdev; 11162306a36Sopenharmony_ci u16 msix_count = 0; 11262306a36Sopenharmony_ci int err = 0; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci wx->mac.num_rar_entries = NGBE_RAR_ENTRIES; 11562306a36Sopenharmony_ci wx->mac.max_rx_queues = NGBE_MAX_RX_QUEUES; 11662306a36Sopenharmony_ci wx->mac.max_tx_queues = NGBE_MAX_TX_QUEUES; 11762306a36Sopenharmony_ci wx->mac.mcft_size = NGBE_MC_TBL_SIZE; 11862306a36Sopenharmony_ci wx->mac.vft_size = NGBE_SP_VFT_TBL_SIZE; 11962306a36Sopenharmony_ci wx->mac.rx_pb_size = NGBE_RX_PB_SIZE; 12062306a36Sopenharmony_ci wx->mac.tx_pb_size = NGBE_TDB_PB_SZ; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* PCI config space info */ 12362306a36Sopenharmony_ci err = wx_sw_init(wx); 12462306a36Sopenharmony_ci if (err < 0) 12562306a36Sopenharmony_ci return err; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* mac type, phy type , oem type */ 12862306a36Sopenharmony_ci ngbe_init_type_code(wx); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Set common capability flags and settings */ 13162306a36Sopenharmony_ci wx->max_q_vectors = NGBE_MAX_MSIX_VECTORS; 13262306a36Sopenharmony_ci err = wx_get_pcie_msix_counts(wx, &msix_count, NGBE_MAX_MSIX_VECTORS); 13362306a36Sopenharmony_ci if (err) 13462306a36Sopenharmony_ci dev_err(&pdev->dev, "Do not support MSI-X\n"); 13562306a36Sopenharmony_ci wx->mac.max_msix_vectors = msix_count; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (ngbe_init_rss_key(wx)) 13862306a36Sopenharmony_ci return -ENOMEM; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* enable itr by default in dynamic mode */ 14162306a36Sopenharmony_ci wx->rx_itr_setting = 1; 14262306a36Sopenharmony_ci wx->tx_itr_setting = 1; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* set default ring sizes */ 14562306a36Sopenharmony_ci wx->tx_ring_count = NGBE_DEFAULT_TXD; 14662306a36Sopenharmony_ci wx->rx_ring_count = NGBE_DEFAULT_RXD; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* set default work limits */ 14962306a36Sopenharmony_ci wx->tx_work_limit = NGBE_DEFAULT_TX_WORK; 15062306a36Sopenharmony_ci wx->rx_work_limit = NGBE_DEFAULT_RX_WORK; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/** 15662306a36Sopenharmony_ci * ngbe_irq_enable - Enable default interrupt generation settings 15762306a36Sopenharmony_ci * @wx: board private structure 15862306a36Sopenharmony_ci * @queues: enable all queues interrupts 15962306a36Sopenharmony_ci **/ 16062306a36Sopenharmony_cistatic void ngbe_irq_enable(struct wx *wx, bool queues) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci u32 mask; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* enable misc interrupt */ 16562306a36Sopenharmony_ci mask = NGBE_PX_MISC_IEN_MASK; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci wr32(wx, WX_GPIO_DDR, WX_GPIO_DDR_0); 16862306a36Sopenharmony_ci wr32(wx, WX_GPIO_INTEN, WX_GPIO_INTEN_0 | WX_GPIO_INTEN_1); 16962306a36Sopenharmony_ci wr32(wx, WX_GPIO_INTTYPE_LEVEL, 0x0); 17062306a36Sopenharmony_ci wr32(wx, WX_GPIO_POLARITY, wx->gpio_ctrl ? 0 : 0x3); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci wr32(wx, WX_PX_MISC_IEN, mask); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* mask interrupt */ 17562306a36Sopenharmony_ci if (queues) 17662306a36Sopenharmony_ci wx_intr_enable(wx, NGBE_INTR_ALL); 17762306a36Sopenharmony_ci else 17862306a36Sopenharmony_ci wx_intr_enable(wx, NGBE_INTR_MISC(wx)); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/** 18262306a36Sopenharmony_ci * ngbe_intr - msi/legacy mode Interrupt Handler 18362306a36Sopenharmony_ci * @irq: interrupt number 18462306a36Sopenharmony_ci * @data: pointer to a network interface device structure 18562306a36Sopenharmony_ci **/ 18662306a36Sopenharmony_cistatic irqreturn_t ngbe_intr(int __always_unused irq, void *data) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct wx_q_vector *q_vector; 18962306a36Sopenharmony_ci struct wx *wx = data; 19062306a36Sopenharmony_ci struct pci_dev *pdev; 19162306a36Sopenharmony_ci u32 eicr; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci q_vector = wx->q_vector[0]; 19462306a36Sopenharmony_ci pdev = wx->pdev; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci eicr = wx_misc_isb(wx, WX_ISB_VEC0); 19762306a36Sopenharmony_ci if (!eicr) { 19862306a36Sopenharmony_ci /* shared interrupt alert! 19962306a36Sopenharmony_ci * the interrupt that we masked before the EICR read. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci if (netif_running(wx->netdev)) 20262306a36Sopenharmony_ci ngbe_irq_enable(wx, true); 20362306a36Sopenharmony_ci return IRQ_NONE; /* Not our interrupt */ 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci wx->isb_mem[WX_ISB_VEC0] = 0; 20662306a36Sopenharmony_ci if (!(pdev->msi_enabled)) 20762306a36Sopenharmony_ci wr32(wx, WX_PX_INTA, 1); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci wx->isb_mem[WX_ISB_MISC] = 0; 21062306a36Sopenharmony_ci /* would disable interrupts here but it is auto disabled */ 21162306a36Sopenharmony_ci napi_schedule_irqoff(&q_vector->napi); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (netif_running(wx->netdev)) 21462306a36Sopenharmony_ci ngbe_irq_enable(wx, false); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return IRQ_HANDLED; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic irqreturn_t ngbe_msix_other(int __always_unused irq, void *data) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct wx *wx = data; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* re-enable the original interrupt state, no lsc, no queues */ 22462306a36Sopenharmony_ci if (netif_running(wx->netdev)) 22562306a36Sopenharmony_ci ngbe_irq_enable(wx, false); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return IRQ_HANDLED; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/** 23162306a36Sopenharmony_ci * ngbe_request_msix_irqs - Initialize MSI-X interrupts 23262306a36Sopenharmony_ci * @wx: board private structure 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * ngbe_request_msix_irqs allocates MSI-X vectors and requests 23562306a36Sopenharmony_ci * interrupts from the kernel. 23662306a36Sopenharmony_ci **/ 23762306a36Sopenharmony_cistatic int ngbe_request_msix_irqs(struct wx *wx) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 24062306a36Sopenharmony_ci int vector, err; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci for (vector = 0; vector < wx->num_q_vectors; vector++) { 24362306a36Sopenharmony_ci struct wx_q_vector *q_vector = wx->q_vector[vector]; 24462306a36Sopenharmony_ci struct msix_entry *entry = &wx->msix_entries[vector]; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (q_vector->tx.ring && q_vector->rx.ring) 24762306a36Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name) - 1, 24862306a36Sopenharmony_ci "%s-TxRx-%d", netdev->name, entry->entry); 24962306a36Sopenharmony_ci else 25062306a36Sopenharmony_ci /* skip this unused q_vector */ 25162306a36Sopenharmony_ci continue; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci err = request_irq(entry->vector, wx_msix_clean_rings, 0, 25462306a36Sopenharmony_ci q_vector->name, q_vector); 25562306a36Sopenharmony_ci if (err) { 25662306a36Sopenharmony_ci wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", 25762306a36Sopenharmony_ci q_vector->name, err); 25862306a36Sopenharmony_ci goto free_queue_irqs; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci err = request_irq(wx->msix_entries[vector].vector, 26362306a36Sopenharmony_ci ngbe_msix_other, 0, netdev->name, wx); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (err) { 26662306a36Sopenharmony_ci wx_err(wx, "request_irq for msix_other failed: %d\n", err); 26762306a36Sopenharmony_ci goto free_queue_irqs; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return 0; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cifree_queue_irqs: 27362306a36Sopenharmony_ci while (vector) { 27462306a36Sopenharmony_ci vector--; 27562306a36Sopenharmony_ci free_irq(wx->msix_entries[vector].vector, 27662306a36Sopenharmony_ci wx->q_vector[vector]); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci wx_reset_interrupt_capability(wx); 27962306a36Sopenharmony_ci return err; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/** 28362306a36Sopenharmony_ci * ngbe_request_irq - initialize interrupts 28462306a36Sopenharmony_ci * @wx: board private structure 28562306a36Sopenharmony_ci * 28662306a36Sopenharmony_ci * Attempts to configure interrupts using the best available 28762306a36Sopenharmony_ci * capabilities of the hardware and kernel. 28862306a36Sopenharmony_ci **/ 28962306a36Sopenharmony_cistatic int ngbe_request_irq(struct wx *wx) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 29262306a36Sopenharmony_ci struct pci_dev *pdev = wx->pdev; 29362306a36Sopenharmony_ci int err; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (pdev->msix_enabled) 29662306a36Sopenharmony_ci err = ngbe_request_msix_irqs(wx); 29762306a36Sopenharmony_ci else if (pdev->msi_enabled) 29862306a36Sopenharmony_ci err = request_irq(pdev->irq, ngbe_intr, 0, 29962306a36Sopenharmony_ci netdev->name, wx); 30062306a36Sopenharmony_ci else 30162306a36Sopenharmony_ci err = request_irq(pdev->irq, ngbe_intr, IRQF_SHARED, 30262306a36Sopenharmony_ci netdev->name, wx); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (err) 30562306a36Sopenharmony_ci wx_err(wx, "request_irq failed, Error %d\n", err); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return err; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic void ngbe_disable_device(struct wx *wx) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct net_device *netdev = wx->netdev; 31362306a36Sopenharmony_ci u32 i; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* disable all enabled rx queues */ 31662306a36Sopenharmony_ci for (i = 0; i < wx->num_rx_queues; i++) 31762306a36Sopenharmony_ci /* this call also flushes the previous write */ 31862306a36Sopenharmony_ci wx_disable_rx_queue(wx, wx->rx_ring[i]); 31962306a36Sopenharmony_ci /* disable receives */ 32062306a36Sopenharmony_ci wx_disable_rx(wx); 32162306a36Sopenharmony_ci wx_napi_disable_all(wx); 32262306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 32362306a36Sopenharmony_ci netif_tx_disable(netdev); 32462306a36Sopenharmony_ci if (wx->gpio_ctrl) 32562306a36Sopenharmony_ci ngbe_sfp_modules_txrx_powerctl(wx, false); 32662306a36Sopenharmony_ci wx_irq_disable(wx); 32762306a36Sopenharmony_ci /* disable transmits in the hardware now that interrupts are off */ 32862306a36Sopenharmony_ci for (i = 0; i < wx->num_tx_queues; i++) { 32962306a36Sopenharmony_ci u8 reg_idx = wx->tx_ring[i]->reg_idx; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void ngbe_down(struct wx *wx) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci phy_stop(wx->phydev); 33862306a36Sopenharmony_ci ngbe_disable_device(wx); 33962306a36Sopenharmony_ci wx_clean_all_tx_rings(wx); 34062306a36Sopenharmony_ci wx_clean_all_rx_rings(wx); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void ngbe_up(struct wx *wx) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci wx_configure_vectors(wx); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* make sure to complete pre-operations */ 34862306a36Sopenharmony_ci smp_mb__before_atomic(); 34962306a36Sopenharmony_ci wx_napi_enable_all(wx); 35062306a36Sopenharmony_ci /* enable transmits */ 35162306a36Sopenharmony_ci netif_tx_start_all_queues(wx->netdev); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* clear any pending interrupts, may auto mask */ 35462306a36Sopenharmony_ci rd32(wx, WX_PX_IC(0)); 35562306a36Sopenharmony_ci rd32(wx, WX_PX_MISC_IC); 35662306a36Sopenharmony_ci ngbe_irq_enable(wx, true); 35762306a36Sopenharmony_ci if (wx->gpio_ctrl) 35862306a36Sopenharmony_ci ngbe_sfp_modules_txrx_powerctl(wx, true); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci phy_start(wx->phydev); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/** 36462306a36Sopenharmony_ci * ngbe_open - Called when a network interface is made active 36562306a36Sopenharmony_ci * @netdev: network interface device structure 36662306a36Sopenharmony_ci * 36762306a36Sopenharmony_ci * Returns 0 on success, negative value on failure 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * The open entry point is called when a network interface is made 37062306a36Sopenharmony_ci * active by the system (IFF_UP). 37162306a36Sopenharmony_ci **/ 37262306a36Sopenharmony_cistatic int ngbe_open(struct net_device *netdev) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct wx *wx = netdev_priv(netdev); 37562306a36Sopenharmony_ci int err; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci wx_control_hw(wx, true); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = wx_setup_resources(wx); 38062306a36Sopenharmony_ci if (err) 38162306a36Sopenharmony_ci return err; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci wx_configure(wx); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci err = ngbe_request_irq(wx); 38662306a36Sopenharmony_ci if (err) 38762306a36Sopenharmony_ci goto err_free_resources; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci err = ngbe_phy_connect(wx); 39062306a36Sopenharmony_ci if (err) 39162306a36Sopenharmony_ci goto err_free_irq; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci err = netif_set_real_num_tx_queues(netdev, wx->num_tx_queues); 39462306a36Sopenharmony_ci if (err) 39562306a36Sopenharmony_ci goto err_dis_phy; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci err = netif_set_real_num_rx_queues(netdev, wx->num_rx_queues); 39862306a36Sopenharmony_ci if (err) 39962306a36Sopenharmony_ci goto err_dis_phy; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ngbe_up(wx); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_cierr_dis_phy: 40562306a36Sopenharmony_ci phy_disconnect(wx->phydev); 40662306a36Sopenharmony_cierr_free_irq: 40762306a36Sopenharmony_ci wx_free_irq(wx); 40862306a36Sopenharmony_cierr_free_resources: 40962306a36Sopenharmony_ci wx_free_resources(wx); 41062306a36Sopenharmony_ci return err; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/** 41462306a36Sopenharmony_ci * ngbe_close - Disables a network interface 41562306a36Sopenharmony_ci * @netdev: network interface device structure 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci * Returns 0, this is not allowed to fail 41862306a36Sopenharmony_ci * 41962306a36Sopenharmony_ci * The close entry point is called when an interface is de-activated 42062306a36Sopenharmony_ci * by the OS. The hardware is still under the drivers control, but 42162306a36Sopenharmony_ci * needs to be disabled. A global MAC reset is issued to stop the 42262306a36Sopenharmony_ci * hardware, and all transmit and receive resources are freed. 42362306a36Sopenharmony_ci **/ 42462306a36Sopenharmony_cistatic int ngbe_close(struct net_device *netdev) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct wx *wx = netdev_priv(netdev); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ngbe_down(wx); 42962306a36Sopenharmony_ci wx_free_irq(wx); 43062306a36Sopenharmony_ci wx_free_resources(wx); 43162306a36Sopenharmony_ci phy_disconnect(wx->phydev); 43262306a36Sopenharmony_ci wx_control_hw(wx, false); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct wx *wx = pci_get_drvdata(pdev); 44062306a36Sopenharmony_ci struct net_device *netdev; 44162306a36Sopenharmony_ci u32 wufc = wx->wol; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci netdev = wx->netdev; 44462306a36Sopenharmony_ci rtnl_lock(); 44562306a36Sopenharmony_ci netif_device_detach(netdev); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (netif_running(netdev)) 44862306a36Sopenharmony_ci ngbe_close(netdev); 44962306a36Sopenharmony_ci wx_clear_interrupt_scheme(wx); 45062306a36Sopenharmony_ci rtnl_unlock(); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (wufc) { 45362306a36Sopenharmony_ci wx_set_rx_mode(netdev); 45462306a36Sopenharmony_ci wx_configure_rx(wx); 45562306a36Sopenharmony_ci wr32(wx, NGBE_PSR_WKUP_CTL, wufc); 45662306a36Sopenharmony_ci } else { 45762306a36Sopenharmony_ci wr32(wx, NGBE_PSR_WKUP_CTL, 0); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci pci_wake_from_d3(pdev, !!wufc); 46062306a36Sopenharmony_ci *enable_wake = !!wufc; 46162306a36Sopenharmony_ci wx_control_hw(wx, false); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci pci_disable_device(pdev); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic void ngbe_shutdown(struct pci_dev *pdev) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct wx *wx = pci_get_drvdata(pdev); 46962306a36Sopenharmony_ci bool wake; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci wake = !!wx->wol; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ngbe_dev_shutdown(pdev, &wake); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) { 47662306a36Sopenharmony_ci pci_wake_from_d3(pdev, wake); 47762306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic const struct net_device_ops ngbe_netdev_ops = { 48262306a36Sopenharmony_ci .ndo_open = ngbe_open, 48362306a36Sopenharmony_ci .ndo_stop = ngbe_close, 48462306a36Sopenharmony_ci .ndo_change_mtu = wx_change_mtu, 48562306a36Sopenharmony_ci .ndo_start_xmit = wx_xmit_frame, 48662306a36Sopenharmony_ci .ndo_set_rx_mode = wx_set_rx_mode, 48762306a36Sopenharmony_ci .ndo_set_features = wx_set_features, 48862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 48962306a36Sopenharmony_ci .ndo_set_mac_address = wx_set_mac, 49062306a36Sopenharmony_ci .ndo_get_stats64 = wx_get_stats64, 49162306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = wx_vlan_rx_add_vid, 49262306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = wx_vlan_rx_kill_vid, 49362306a36Sopenharmony_ci}; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci/** 49662306a36Sopenharmony_ci * ngbe_probe - Device Initialization Routine 49762306a36Sopenharmony_ci * @pdev: PCI device information struct 49862306a36Sopenharmony_ci * @ent: entry in ngbe_pci_tbl 49962306a36Sopenharmony_ci * 50062306a36Sopenharmony_ci * Returns 0 on success, negative on failure 50162306a36Sopenharmony_ci * 50262306a36Sopenharmony_ci * ngbe_probe initializes an wx identified by a pci_dev structure. 50362306a36Sopenharmony_ci * The OS initialization, configuring of the wx private structure, 50462306a36Sopenharmony_ci * and a hardware reset occur. 50562306a36Sopenharmony_ci **/ 50662306a36Sopenharmony_cistatic int ngbe_probe(struct pci_dev *pdev, 50762306a36Sopenharmony_ci const struct pci_device_id __always_unused *ent) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct net_device *netdev; 51062306a36Sopenharmony_ci u32 e2rom_cksum_cap = 0; 51162306a36Sopenharmony_ci struct wx *wx = NULL; 51262306a36Sopenharmony_ci static int func_nums; 51362306a36Sopenharmony_ci u16 e2rom_ver = 0; 51462306a36Sopenharmony_ci u32 etrack_id = 0; 51562306a36Sopenharmony_ci u32 saved_ver = 0; 51662306a36Sopenharmony_ci int err; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci err = pci_enable_device_mem(pdev); 51962306a36Sopenharmony_ci if (err) 52062306a36Sopenharmony_ci return err; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 52362306a36Sopenharmony_ci if (err) { 52462306a36Sopenharmony_ci dev_err(&pdev->dev, 52562306a36Sopenharmony_ci "No usable DMA configuration, aborting\n"); 52662306a36Sopenharmony_ci goto err_pci_disable_dev; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci err = pci_request_selected_regions(pdev, 53062306a36Sopenharmony_ci pci_select_bars(pdev, IORESOURCE_MEM), 53162306a36Sopenharmony_ci ngbe_driver_name); 53262306a36Sopenharmony_ci if (err) { 53362306a36Sopenharmony_ci dev_err(&pdev->dev, 53462306a36Sopenharmony_ci "pci_request_selected_regions failed %d\n", err); 53562306a36Sopenharmony_ci goto err_pci_disable_dev; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci pci_set_master(pdev); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci netdev = devm_alloc_etherdev_mqs(&pdev->dev, 54162306a36Sopenharmony_ci sizeof(struct wx), 54262306a36Sopenharmony_ci NGBE_MAX_TX_QUEUES, 54362306a36Sopenharmony_ci NGBE_MAX_RX_QUEUES); 54462306a36Sopenharmony_ci if (!netdev) { 54562306a36Sopenharmony_ci err = -ENOMEM; 54662306a36Sopenharmony_ci goto err_pci_release_regions; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci wx = netdev_priv(netdev); 55262306a36Sopenharmony_ci wx->netdev = netdev; 55362306a36Sopenharmony_ci wx->pdev = pdev; 55462306a36Sopenharmony_ci wx->msg_enable = BIT(3) - 1; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci wx->hw_addr = devm_ioremap(&pdev->dev, 55762306a36Sopenharmony_ci pci_resource_start(pdev, 0), 55862306a36Sopenharmony_ci pci_resource_len(pdev, 0)); 55962306a36Sopenharmony_ci if (!wx->hw_addr) { 56062306a36Sopenharmony_ci err = -EIO; 56162306a36Sopenharmony_ci goto err_pci_release_regions; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci wx->driver_name = ngbe_driver_name; 56562306a36Sopenharmony_ci ngbe_set_ethtool_ops(netdev); 56662306a36Sopenharmony_ci netdev->netdev_ops = &ngbe_netdev_ops; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | 56962306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | 57062306a36Sopenharmony_ci NETIF_F_RXHASH | NETIF_F_RXCSUM; 57162306a36Sopenharmony_ci netdev->features |= NETIF_F_SCTP_CRC | NETIF_F_TSO_MANGLEID; 57262306a36Sopenharmony_ci netdev->vlan_features |= netdev->features; 57362306a36Sopenharmony_ci netdev->features |= NETIF_F_IPV6_CSUM | NETIF_F_VLAN_FEATURES; 57462306a36Sopenharmony_ci /* copy netdev features into list of user selectable features */ 57562306a36Sopenharmony_ci netdev->hw_features |= netdev->features | NETIF_F_RXALL; 57662306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC; 57762306a36Sopenharmony_ci netdev->features |= NETIF_F_HIGHDMA; 57862306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_GRO; 57962306a36Sopenharmony_ci netdev->features |= NETIF_F_GRO; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci netdev->priv_flags |= IFF_UNICAST_FLT; 58262306a36Sopenharmony_ci netdev->priv_flags |= IFF_SUPP_NOFCS; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci netdev->min_mtu = ETH_MIN_MTU; 58562306a36Sopenharmony_ci netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE - 58662306a36Sopenharmony_ci (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci wx->bd_number = func_nums; 58962306a36Sopenharmony_ci /* setup the private structure */ 59062306a36Sopenharmony_ci err = ngbe_sw_init(wx); 59162306a36Sopenharmony_ci if (err) 59262306a36Sopenharmony_ci goto err_free_mac_table; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* check if flash load is done after hw power up */ 59562306a36Sopenharmony_ci err = wx_check_flash_load(wx, NGBE_SPI_ILDR_STATUS_PERST); 59662306a36Sopenharmony_ci if (err) 59762306a36Sopenharmony_ci goto err_free_mac_table; 59862306a36Sopenharmony_ci err = wx_check_flash_load(wx, NGBE_SPI_ILDR_STATUS_PWRRST); 59962306a36Sopenharmony_ci if (err) 60062306a36Sopenharmony_ci goto err_free_mac_table; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci err = wx_mng_present(wx); 60362306a36Sopenharmony_ci if (err) { 60462306a36Sopenharmony_ci dev_err(&pdev->dev, "Management capability is not present\n"); 60562306a36Sopenharmony_ci goto err_free_mac_table; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci err = ngbe_reset_hw(wx); 60962306a36Sopenharmony_ci if (err) { 61062306a36Sopenharmony_ci dev_err(&pdev->dev, "HW Init failed: %d\n", err); 61162306a36Sopenharmony_ci goto err_free_mac_table; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (wx->bus.func == 0) { 61562306a36Sopenharmony_ci wr32(wx, NGBE_CALSUM_CAP_STATUS, 0x0); 61662306a36Sopenharmony_ci wr32(wx, NGBE_EEPROM_VERSION_STORE_REG, 0x0); 61762306a36Sopenharmony_ci } else { 61862306a36Sopenharmony_ci e2rom_cksum_cap = rd32(wx, NGBE_CALSUM_CAP_STATUS); 61962306a36Sopenharmony_ci saved_ver = rd32(wx, NGBE_EEPROM_VERSION_STORE_REG); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci wx_init_eeprom_params(wx); 62362306a36Sopenharmony_ci if (wx->bus.func == 0 || e2rom_cksum_cap == 0) { 62462306a36Sopenharmony_ci /* make sure the EEPROM is ready */ 62562306a36Sopenharmony_ci err = ngbe_eeprom_chksum_hostif(wx); 62662306a36Sopenharmony_ci if (err) { 62762306a36Sopenharmony_ci dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); 62862306a36Sopenharmony_ci err = -EIO; 62962306a36Sopenharmony_ci goto err_free_mac_table; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci wx->wol = 0; 63462306a36Sopenharmony_ci if (wx->wol_hw_supported) 63562306a36Sopenharmony_ci wx->wol = NGBE_PSR_WKUP_CTL_MAG; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci netdev->wol_enabled = !!(wx->wol); 63862306a36Sopenharmony_ci wr32(wx, NGBE_PSR_WKUP_CTL, wx->wol); 63962306a36Sopenharmony_ci device_set_wakeup_enable(&pdev->dev, wx->wol); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* Save off EEPROM version number and Option Rom version which 64262306a36Sopenharmony_ci * together make a unique identify for the eeprom 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci if (saved_ver) { 64562306a36Sopenharmony_ci etrack_id = saved_ver; 64662306a36Sopenharmony_ci } else { 64762306a36Sopenharmony_ci wx_read_ee_hostif(wx, 64862306a36Sopenharmony_ci wx->eeprom.sw_region_offset + NGBE_EEPROM_VERSION_H, 64962306a36Sopenharmony_ci &e2rom_ver); 65062306a36Sopenharmony_ci etrack_id = e2rom_ver << 16; 65162306a36Sopenharmony_ci wx_read_ee_hostif(wx, 65262306a36Sopenharmony_ci wx->eeprom.sw_region_offset + NGBE_EEPROM_VERSION_L, 65362306a36Sopenharmony_ci &e2rom_ver); 65462306a36Sopenharmony_ci etrack_id |= e2rom_ver; 65562306a36Sopenharmony_ci wr32(wx, NGBE_EEPROM_VERSION_STORE_REG, etrack_id); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci snprintf(wx->eeprom_id, sizeof(wx->eeprom_id), 65862306a36Sopenharmony_ci "0x%08x", etrack_id); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci eth_hw_addr_set(netdev, wx->mac.perm_addr); 66162306a36Sopenharmony_ci wx_mac_set_default_filter(wx, wx->mac.perm_addr); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci err = wx_init_interrupt_scheme(wx); 66462306a36Sopenharmony_ci if (err) 66562306a36Sopenharmony_ci goto err_free_mac_table; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* phy Interface Configuration */ 66862306a36Sopenharmony_ci err = ngbe_mdio_init(wx); 66962306a36Sopenharmony_ci if (err) 67062306a36Sopenharmony_ci goto err_clear_interrupt_scheme; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci err = register_netdev(netdev); 67362306a36Sopenharmony_ci if (err) 67462306a36Sopenharmony_ci goto err_register; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci pci_set_drvdata(pdev, wx); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci netif_info(wx, probe, netdev, 67962306a36Sopenharmony_ci "PHY: %s, PBA No: Wang Xun GbE Family Controller\n", 68062306a36Sopenharmony_ci wx->mac_type == em_mac_type_mdi ? "Internal" : "External"); 68162306a36Sopenharmony_ci netif_info(wx, probe, netdev, "%pM\n", netdev->dev_addr); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cierr_register: 68662306a36Sopenharmony_ci wx_control_hw(wx, false); 68762306a36Sopenharmony_cierr_clear_interrupt_scheme: 68862306a36Sopenharmony_ci wx_clear_interrupt_scheme(wx); 68962306a36Sopenharmony_cierr_free_mac_table: 69062306a36Sopenharmony_ci kfree(wx->mac_table); 69162306a36Sopenharmony_cierr_pci_release_regions: 69262306a36Sopenharmony_ci pci_release_selected_regions(pdev, 69362306a36Sopenharmony_ci pci_select_bars(pdev, IORESOURCE_MEM)); 69462306a36Sopenharmony_cierr_pci_disable_dev: 69562306a36Sopenharmony_ci pci_disable_device(pdev); 69662306a36Sopenharmony_ci return err; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci/** 70062306a36Sopenharmony_ci * ngbe_remove - Device Removal Routine 70162306a36Sopenharmony_ci * @pdev: PCI device information struct 70262306a36Sopenharmony_ci * 70362306a36Sopenharmony_ci * ngbe_remove is called by the PCI subsystem to alert the driver 70462306a36Sopenharmony_ci * that it should release a PCI device. The could be caused by a 70562306a36Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from 70662306a36Sopenharmony_ci * memory. 70762306a36Sopenharmony_ci **/ 70862306a36Sopenharmony_cistatic void ngbe_remove(struct pci_dev *pdev) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct wx *wx = pci_get_drvdata(pdev); 71162306a36Sopenharmony_ci struct net_device *netdev; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci netdev = wx->netdev; 71462306a36Sopenharmony_ci unregister_netdev(netdev); 71562306a36Sopenharmony_ci pci_release_selected_regions(pdev, 71662306a36Sopenharmony_ci pci_select_bars(pdev, IORESOURCE_MEM)); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci kfree(wx->mac_table); 71962306a36Sopenharmony_ci wx_clear_interrupt_scheme(wx); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci pci_disable_device(pdev); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int ngbe_suspend(struct pci_dev *pdev, pm_message_t state) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci bool wake; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci ngbe_dev_shutdown(pdev, &wake); 72962306a36Sopenharmony_ci device_set_wakeup_enable(&pdev->dev, wake); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic int ngbe_resume(struct pci_dev *pdev) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci struct net_device *netdev; 73762306a36Sopenharmony_ci struct wx *wx; 73862306a36Sopenharmony_ci u32 err; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci wx = pci_get_drvdata(pdev); 74162306a36Sopenharmony_ci netdev = wx->netdev; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci err = pci_enable_device_mem(pdev); 74462306a36Sopenharmony_ci if (err) { 74562306a36Sopenharmony_ci wx_err(wx, "Cannot enable PCI device from suspend\n"); 74662306a36Sopenharmony_ci return err; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci pci_set_master(pdev); 74962306a36Sopenharmony_ci device_wakeup_disable(&pdev->dev); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci ngbe_reset_hw(wx); 75262306a36Sopenharmony_ci rtnl_lock(); 75362306a36Sopenharmony_ci err = wx_init_interrupt_scheme(wx); 75462306a36Sopenharmony_ci if (!err && netif_running(netdev)) 75562306a36Sopenharmony_ci err = ngbe_open(netdev); 75662306a36Sopenharmony_ci if (!err) 75762306a36Sopenharmony_ci netif_device_attach(netdev); 75862306a36Sopenharmony_ci rtnl_unlock(); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic struct pci_driver ngbe_driver = { 76462306a36Sopenharmony_ci .name = ngbe_driver_name, 76562306a36Sopenharmony_ci .id_table = ngbe_pci_tbl, 76662306a36Sopenharmony_ci .probe = ngbe_probe, 76762306a36Sopenharmony_ci .remove = ngbe_remove, 76862306a36Sopenharmony_ci .suspend = ngbe_suspend, 76962306a36Sopenharmony_ci .resume = ngbe_resume, 77062306a36Sopenharmony_ci .shutdown = ngbe_shutdown, 77162306a36Sopenharmony_ci}; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cimodule_pci_driver(ngbe_driver); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ngbe_pci_tbl); 77662306a36Sopenharmony_ciMODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@net-swift.com>"); 77762306a36Sopenharmony_ciMODULE_DESCRIPTION("WangXun(R) Gigabit PCI Express Network Driver"); 77862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 779