162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */ 262306a36Sopenharmony_ci/* Copyright (C) 2018 Microchip Technology Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/pci.h> 662306a36Sopenharmony_ci#include <linux/netdevice.h> 762306a36Sopenharmony_ci#include <linux/etherdevice.h> 862306a36Sopenharmony_ci#include <linux/crc32.h> 962306a36Sopenharmony_ci#include <linux/microchipphy.h> 1062306a36Sopenharmony_ci#include <linux/net_tstamp.h> 1162306a36Sopenharmony_ci#include <linux/of_mdio.h> 1262306a36Sopenharmony_ci#include <linux/of_net.h> 1362306a36Sopenharmony_ci#include <linux/phy.h> 1462306a36Sopenharmony_ci#include <linux/phy_fixed.h> 1562306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1662306a36Sopenharmony_ci#include <linux/iopoll.h> 1762306a36Sopenharmony_ci#include <linux/crc16.h> 1862306a36Sopenharmony_ci#include "lan743x_main.h" 1962306a36Sopenharmony_ci#include "lan743x_ethtool.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define MMD_ACCESS_ADDRESS 0 2262306a36Sopenharmony_ci#define MMD_ACCESS_WRITE 1 2362306a36Sopenharmony_ci#define MMD_ACCESS_READ 2 2462306a36Sopenharmony_ci#define MMD_ACCESS_READ_INC 3 2562306a36Sopenharmony_ci#define PCS_POWER_STATE_DOWN 0x6 2662306a36Sopenharmony_ci#define PCS_POWER_STATE_UP 0x4 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci u32 chip_rev; 3162306a36Sopenharmony_ci u32 cfg_load; 3262306a36Sopenharmony_ci u32 hw_cfg; 3362306a36Sopenharmony_ci u32 strap; 3462306a36Sopenharmony_ci int ret; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* Timeout = 100 (i.e. 1 sec (10 msce * 100)) */ 3762306a36Sopenharmony_ci ret = lan743x_hs_syslock_acquire(adapter, 100); 3862306a36Sopenharmony_ci if (ret < 0) { 3962306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 4062306a36Sopenharmony_ci "Sys Lock acquire failed ret:%d\n", ret); 4162306a36Sopenharmony_ci return; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG); 4562306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 4662306a36Sopenharmony_ci hw_cfg = lan743x_csr_read(adapter, HW_CFG); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || 4962306a36Sopenharmony_ci hw_cfg & HW_CFG_RST_PROTECT_) { 5062306a36Sopenharmony_ci strap = lan743x_csr_read(adapter, STRAP_READ); 5162306a36Sopenharmony_ci if (strap & STRAP_READ_SGMII_EN_) 5262306a36Sopenharmony_ci adapter->is_sgmii_en = true; 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci adapter->is_sgmii_en = false; 5562306a36Sopenharmony_ci } else { 5662306a36Sopenharmony_ci chip_rev = lan743x_csr_read(adapter, FPGA_REV); 5762306a36Sopenharmony_ci if (chip_rev) { 5862306a36Sopenharmony_ci if (chip_rev & FPGA_SGMII_OP) 5962306a36Sopenharmony_ci adapter->is_sgmii_en = true; 6062306a36Sopenharmony_ci else 6162306a36Sopenharmony_ci adapter->is_sgmii_en = false; 6262306a36Sopenharmony_ci } else { 6362306a36Sopenharmony_ci adapter->is_sgmii_en = false; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, 6762306a36Sopenharmony_ci "SGMII I/F %sable\n", adapter->is_sgmii_en ? "En" : "Dis"); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic bool is_pci11x1x_chip(struct lan743x_adapter *adapter) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct lan743x_csr *csr = &adapter->csr; 7362306a36Sopenharmony_ci u32 id_rev = csr->id_rev; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (((id_rev & 0xFFFF0000) == ID_REV_ID_A011_) || 7662306a36Sopenharmony_ci ((id_rev & 0xFFFF0000) == ID_REV_ID_A041_)) { 7762306a36Sopenharmony_ci return true; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci return false; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void lan743x_pci_cleanup(struct lan743x_adapter *adapter) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci pci_release_selected_regions(adapter->pdev, 8562306a36Sopenharmony_ci pci_select_bars(adapter->pdev, 8662306a36Sopenharmony_ci IORESOURCE_MEM)); 8762306a36Sopenharmony_ci pci_disable_device(adapter->pdev); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int lan743x_pci_init(struct lan743x_adapter *adapter, 9162306a36Sopenharmony_ci struct pci_dev *pdev) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci unsigned long bars = 0; 9462306a36Sopenharmony_ci int ret; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci adapter->pdev = pdev; 9762306a36Sopenharmony_ci ret = pci_enable_device_mem(pdev); 9862306a36Sopenharmony_ci if (ret) 9962306a36Sopenharmony_ci goto return_error; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci netif_info(adapter, probe, adapter->netdev, 10262306a36Sopenharmony_ci "PCI: Vendor ID = 0x%04X, Device ID = 0x%04X\n", 10362306a36Sopenharmony_ci pdev->vendor, pdev->device); 10462306a36Sopenharmony_ci bars = pci_select_bars(pdev, IORESOURCE_MEM); 10562306a36Sopenharmony_ci if (!test_bit(0, &bars)) 10662306a36Sopenharmony_ci goto disable_device; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ret = pci_request_selected_regions(pdev, bars, DRIVER_NAME); 10962306a36Sopenharmony_ci if (ret) 11062306a36Sopenharmony_ci goto disable_device; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci pci_set_master(pdev); 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cidisable_device: 11662306a36Sopenharmony_ci pci_disable_device(adapter->pdev); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cireturn_error: 11962306a36Sopenharmony_ci return ret; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciu32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return ioread32(&adapter->csr.csr_address[offset]); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid lan743x_csr_write(struct lan743x_adapter *adapter, int offset, 12862306a36Sopenharmony_ci u32 data) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci iowrite32(data, &adapter->csr.csr_address[offset]); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define LAN743X_CSR_READ_OP(offset) lan743x_csr_read(adapter, offset) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int lan743x_csr_light_reset(struct lan743x_adapter *adapter) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci u32 data; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci data = lan743x_csr_read(adapter, HW_CFG); 14062306a36Sopenharmony_ci data |= HW_CFG_LRST_; 14162306a36Sopenharmony_ci lan743x_csr_write(adapter, HW_CFG, data); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, HW_CFG, data, 14462306a36Sopenharmony_ci !(data & HW_CFG_LRST_), 100000, 10000000); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int lan743x_csr_wait_for_bit_atomic(struct lan743x_adapter *adapter, 14862306a36Sopenharmony_ci int offset, u32 bit_mask, 14962306a36Sopenharmony_ci int target_value, int udelay_min, 15062306a36Sopenharmony_ci int udelay_max, int count) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci u32 data; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return readx_poll_timeout_atomic(LAN743X_CSR_READ_OP, offset, data, 15562306a36Sopenharmony_ci target_value == !!(data & bit_mask), 15662306a36Sopenharmony_ci udelay_max, udelay_min * count); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic int lan743x_csr_wait_for_bit(struct lan743x_adapter *adapter, 16062306a36Sopenharmony_ci int offset, u32 bit_mask, 16162306a36Sopenharmony_ci int target_value, int usleep_min, 16262306a36Sopenharmony_ci int usleep_max, int count) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci u32 data; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, offset, data, 16762306a36Sopenharmony_ci target_value == !!(data & bit_mask), 16862306a36Sopenharmony_ci usleep_max, usleep_min * count); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int lan743x_csr_init(struct lan743x_adapter *adapter) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct lan743x_csr *csr = &adapter->csr; 17462306a36Sopenharmony_ci resource_size_t bar_start, bar_length; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci bar_start = pci_resource_start(adapter->pdev, 0); 17762306a36Sopenharmony_ci bar_length = pci_resource_len(adapter->pdev, 0); 17862306a36Sopenharmony_ci csr->csr_address = devm_ioremap(&adapter->pdev->dev, 17962306a36Sopenharmony_ci bar_start, bar_length); 18062306a36Sopenharmony_ci if (!csr->csr_address) 18162306a36Sopenharmony_ci return -ENOMEM; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci csr->id_rev = lan743x_csr_read(adapter, ID_REV); 18462306a36Sopenharmony_ci csr->fpga_rev = lan743x_csr_read(adapter, FPGA_REV); 18562306a36Sopenharmony_ci netif_info(adapter, probe, adapter->netdev, 18662306a36Sopenharmony_ci "ID_REV = 0x%08X, FPGA_REV = %d.%d\n", 18762306a36Sopenharmony_ci csr->id_rev, FPGA_REV_GET_MAJOR_(csr->fpga_rev), 18862306a36Sopenharmony_ci FPGA_REV_GET_MINOR_(csr->fpga_rev)); 18962306a36Sopenharmony_ci if (!ID_REV_IS_VALID_CHIP_ID_(csr->id_rev)) 19062306a36Sopenharmony_ci return -ENODEV; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci csr->flags = LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR; 19362306a36Sopenharmony_ci switch (csr->id_rev & ID_REV_CHIP_REV_MASK_) { 19462306a36Sopenharmony_ci case ID_REV_CHIP_REV_A0_: 19562306a36Sopenharmony_ci csr->flags |= LAN743X_CSR_FLAG_IS_A0; 19662306a36Sopenharmony_ci csr->flags &= ~LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR; 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci case ID_REV_CHIP_REV_B0_: 19962306a36Sopenharmony_ci csr->flags |= LAN743X_CSR_FLAG_IS_B0; 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return lan743x_csr_light_reset(adapter); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void lan743x_intr_software_isr(struct lan743x_adapter *adapter) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* disable the interrupt to prevent repeated re-triggering */ 21162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_); 21262306a36Sopenharmony_ci intr->software_isr_flag = true; 21362306a36Sopenharmony_ci wake_up(&intr->software_isr_wq); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void lan743x_tx_isr(void *context, u32 int_sts, u32 flags) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct lan743x_tx *tx = context; 21962306a36Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 22062306a36Sopenharmony_ci bool enable_flag = true; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci lan743x_csr_read(adapter, INT_EN_SET); 22362306a36Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) { 22462306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 22562306a36Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (int_sts & INT_BIT_DMA_TX_(tx->channel_number)) { 22962306a36Sopenharmony_ci u32 ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number); 23062306a36Sopenharmony_ci u32 dmac_int_sts; 23162306a36Sopenharmony_ci u32 dmac_int_en; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) 23462306a36Sopenharmony_ci dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS); 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci dmac_int_sts = ioc_bit; 23762306a36Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) 23862306a36Sopenharmony_ci dmac_int_en = lan743x_csr_read(adapter, 23962306a36Sopenharmony_ci DMAC_INT_EN_SET); 24062306a36Sopenharmony_ci else 24162306a36Sopenharmony_ci dmac_int_en = ioc_bit; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dmac_int_en &= ioc_bit; 24462306a36Sopenharmony_ci dmac_int_sts &= dmac_int_en; 24562306a36Sopenharmony_ci if (dmac_int_sts & ioc_bit) { 24662306a36Sopenharmony_ci napi_schedule(&tx->napi); 24762306a36Sopenharmony_ci enable_flag = false;/* poll func will enable later */ 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (enable_flag) 25262306a36Sopenharmony_ci /* enable isr */ 25362306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 25462306a36Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic void lan743x_rx_isr(void *context, u32 int_sts, u32 flags) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct lan743x_rx *rx = context; 26062306a36Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 26162306a36Sopenharmony_ci bool enable_flag = true; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) { 26462306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 26562306a36Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (int_sts & INT_BIT_DMA_RX_(rx->channel_number)) { 26962306a36Sopenharmony_ci u32 rx_frame_bit = DMAC_INT_BIT_RXFRM_(rx->channel_number); 27062306a36Sopenharmony_ci u32 dmac_int_sts; 27162306a36Sopenharmony_ci u32 dmac_int_en; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) 27462306a36Sopenharmony_ci dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS); 27562306a36Sopenharmony_ci else 27662306a36Sopenharmony_ci dmac_int_sts = rx_frame_bit; 27762306a36Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) 27862306a36Sopenharmony_ci dmac_int_en = lan743x_csr_read(adapter, 27962306a36Sopenharmony_ci DMAC_INT_EN_SET); 28062306a36Sopenharmony_ci else 28162306a36Sopenharmony_ci dmac_int_en = rx_frame_bit; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci dmac_int_en &= rx_frame_bit; 28462306a36Sopenharmony_ci dmac_int_sts &= dmac_int_en; 28562306a36Sopenharmony_ci if (dmac_int_sts & rx_frame_bit) { 28662306a36Sopenharmony_ci napi_schedule(&rx->napi); 28762306a36Sopenharmony_ci enable_flag = false;/* poll funct will enable later */ 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (enable_flag) { 29262306a36Sopenharmony_ci /* enable isr */ 29362306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 29462306a36Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void lan743x_intr_shared_isr(void *context, u32 int_sts, u32 flags) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct lan743x_adapter *adapter = context; 30162306a36Sopenharmony_ci unsigned int channel; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (int_sts & INT_BIT_ALL_RX_) { 30462306a36Sopenharmony_ci for (channel = 0; channel < LAN743X_USED_RX_CHANNELS; 30562306a36Sopenharmony_ci channel++) { 30662306a36Sopenharmony_ci u32 int_bit = INT_BIT_DMA_RX_(channel); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (int_sts & int_bit) { 30962306a36Sopenharmony_ci lan743x_rx_isr(&adapter->rx[channel], 31062306a36Sopenharmony_ci int_bit, flags); 31162306a36Sopenharmony_ci int_sts &= ~int_bit; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci if (int_sts & INT_BIT_ALL_TX_) { 31662306a36Sopenharmony_ci for (channel = 0; channel < adapter->used_tx_channels; 31762306a36Sopenharmony_ci channel++) { 31862306a36Sopenharmony_ci u32 int_bit = INT_BIT_DMA_TX_(channel); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (int_sts & int_bit) { 32162306a36Sopenharmony_ci lan743x_tx_isr(&adapter->tx[channel], 32262306a36Sopenharmony_ci int_bit, flags); 32362306a36Sopenharmony_ci int_sts &= ~int_bit; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci if (int_sts & INT_BIT_ALL_OTHER_) { 32862306a36Sopenharmony_ci if (int_sts & INT_BIT_SW_GP_) { 32962306a36Sopenharmony_ci lan743x_intr_software_isr(adapter); 33062306a36Sopenharmony_ci int_sts &= ~INT_BIT_SW_GP_; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci if (int_sts & INT_BIT_1588_) { 33362306a36Sopenharmony_ci lan743x_ptp_isr(adapter); 33462306a36Sopenharmony_ci int_sts &= ~INT_BIT_1588_; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci if (int_sts) 33862306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, int_sts); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic irqreturn_t lan743x_intr_entry_isr(int irq, void *ptr) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct lan743x_vector *vector = ptr; 34462306a36Sopenharmony_ci struct lan743x_adapter *adapter = vector->adapter; 34562306a36Sopenharmony_ci irqreturn_t result = IRQ_NONE; 34662306a36Sopenharmony_ci u32 int_enables; 34762306a36Sopenharmony_ci u32 int_sts; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) { 35062306a36Sopenharmony_ci int_sts = lan743x_csr_read(adapter, INT_STS); 35162306a36Sopenharmony_ci } else if (vector->flags & 35262306a36Sopenharmony_ci (LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C | 35362306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)) { 35462306a36Sopenharmony_ci int_sts = lan743x_csr_read(adapter, INT_STS_R2C); 35562306a36Sopenharmony_ci } else { 35662306a36Sopenharmony_ci /* use mask as implied status */ 35762306a36Sopenharmony_ci int_sts = vector->int_mask | INT_BIT_MAS_; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (!(int_sts & INT_BIT_MAS_)) 36162306a36Sopenharmony_ci goto irq_done; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR) 36462306a36Sopenharmony_ci /* disable vector interrupt */ 36562306a36Sopenharmony_ci lan743x_csr_write(adapter, 36662306a36Sopenharmony_ci INT_VEC_EN_CLR, 36762306a36Sopenharmony_ci INT_VEC_EN_(vector->vector_index)); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR) 37062306a36Sopenharmony_ci /* disable master interrupt */ 37162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) { 37462306a36Sopenharmony_ci int_enables = lan743x_csr_read(adapter, INT_EN_SET); 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci /* use vector mask as implied enable mask */ 37762306a36Sopenharmony_ci int_enables = vector->int_mask; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci int_sts &= int_enables; 38162306a36Sopenharmony_ci int_sts &= vector->int_mask; 38262306a36Sopenharmony_ci if (int_sts) { 38362306a36Sopenharmony_ci if (vector->handler) { 38462306a36Sopenharmony_ci vector->handler(vector->context, 38562306a36Sopenharmony_ci int_sts, vector->flags); 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci /* disable interrupts on this vector */ 38862306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 38962306a36Sopenharmony_ci vector->int_mask); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci result = IRQ_HANDLED; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET) 39562306a36Sopenharmony_ci /* enable master interrupt */ 39662306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET) 39962306a36Sopenharmony_ci /* enable vector interrupt */ 40062306a36Sopenharmony_ci lan743x_csr_write(adapter, 40162306a36Sopenharmony_ci INT_VEC_EN_SET, 40262306a36Sopenharmony_ci INT_VEC_EN_(vector->vector_index)); 40362306a36Sopenharmony_ciirq_done: 40462306a36Sopenharmony_ci return result; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int lan743x_intr_test_isr(struct lan743x_adapter *adapter) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 41062306a36Sopenharmony_ci int ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci intr->software_isr_flag = false; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* enable and activate test interrupt */ 41562306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_SW_GP_); 41662306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_SET, INT_BIT_SW_GP_); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = wait_event_timeout(intr->software_isr_wq, 41962306a36Sopenharmony_ci intr->software_isr_flag, 42062306a36Sopenharmony_ci msecs_to_jiffies(200)); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* disable test interrupt */ 42362306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return ret > 0 ? 0 : -ENODEV; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int lan743x_intr_register_isr(struct lan743x_adapter *adapter, 42962306a36Sopenharmony_ci int vector_index, u32 flags, 43062306a36Sopenharmony_ci u32 int_mask, 43162306a36Sopenharmony_ci lan743x_vector_handler handler, 43262306a36Sopenharmony_ci void *context) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct lan743x_vector *vector = &adapter->intr.vector_list 43562306a36Sopenharmony_ci [vector_index]; 43662306a36Sopenharmony_ci int ret; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci vector->adapter = adapter; 43962306a36Sopenharmony_ci vector->flags = flags; 44062306a36Sopenharmony_ci vector->vector_index = vector_index; 44162306a36Sopenharmony_ci vector->int_mask = int_mask; 44262306a36Sopenharmony_ci vector->handler = handler; 44362306a36Sopenharmony_ci vector->context = context; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ret = request_irq(vector->irq, 44662306a36Sopenharmony_ci lan743x_intr_entry_isr, 44762306a36Sopenharmony_ci (flags & LAN743X_VECTOR_FLAG_IRQ_SHARED) ? 44862306a36Sopenharmony_ci IRQF_SHARED : 0, DRIVER_NAME, vector); 44962306a36Sopenharmony_ci if (ret) { 45062306a36Sopenharmony_ci vector->handler = NULL; 45162306a36Sopenharmony_ci vector->context = NULL; 45262306a36Sopenharmony_ci vector->int_mask = 0; 45362306a36Sopenharmony_ci vector->flags = 0; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci return ret; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void lan743x_intr_unregister_isr(struct lan743x_adapter *adapter, 45962306a36Sopenharmony_ci int vector_index) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct lan743x_vector *vector = &adapter->intr.vector_list 46262306a36Sopenharmony_ci [vector_index]; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci free_irq(vector->irq, vector); 46562306a36Sopenharmony_ci vector->handler = NULL; 46662306a36Sopenharmony_ci vector->context = NULL; 46762306a36Sopenharmony_ci vector->int_mask = 0; 46862306a36Sopenharmony_ci vector->flags = 0; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic u32 lan743x_intr_get_vector_flags(struct lan743x_adapter *adapter, 47262306a36Sopenharmony_ci u32 int_mask) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci int index; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci for (index = 0; index < adapter->max_vector_count; index++) { 47762306a36Sopenharmony_ci if (adapter->intr.vector_list[index].int_mask & int_mask) 47862306a36Sopenharmony_ci return adapter->intr.vector_list[index].flags; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic void lan743x_intr_close(struct lan743x_adapter *adapter) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 48662306a36Sopenharmony_ci int index = 0; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_); 48962306a36Sopenharmony_ci if (adapter->is_pci11x1x) 49062306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x0000FFFF); 49162306a36Sopenharmony_ci else 49262306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x000000FF); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci for (index = 0; index < intr->number_of_vectors; index++) { 49562306a36Sopenharmony_ci if (intr->flags & INTR_FLAG_IRQ_REQUESTED(index)) { 49662306a36Sopenharmony_ci lan743x_intr_unregister_isr(adapter, index); 49762306a36Sopenharmony_ci intr->flags &= ~INTR_FLAG_IRQ_REQUESTED(index); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (intr->flags & INTR_FLAG_MSI_ENABLED) { 50262306a36Sopenharmony_ci pci_disable_msi(adapter->pdev); 50362306a36Sopenharmony_ci intr->flags &= ~INTR_FLAG_MSI_ENABLED; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (intr->flags & INTR_FLAG_MSIX_ENABLED) { 50762306a36Sopenharmony_ci pci_disable_msix(adapter->pdev); 50862306a36Sopenharmony_ci intr->flags &= ~INTR_FLAG_MSIX_ENABLED; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int lan743x_intr_open(struct lan743x_adapter *adapter) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct msix_entry msix_entries[PCI11X1X_MAX_VECTOR_COUNT]; 51562306a36Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 51662306a36Sopenharmony_ci unsigned int used_tx_channels; 51762306a36Sopenharmony_ci u32 int_vec_en_auto_clr = 0; 51862306a36Sopenharmony_ci u8 max_vector_count; 51962306a36Sopenharmony_ci u32 int_vec_map0 = 0; 52062306a36Sopenharmony_ci u32 int_vec_map1 = 0; 52162306a36Sopenharmony_ci int ret = -ENODEV; 52262306a36Sopenharmony_ci int index = 0; 52362306a36Sopenharmony_ci u32 flags = 0; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci intr->number_of_vectors = 0; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Try to set up MSIX interrupts */ 52862306a36Sopenharmony_ci max_vector_count = adapter->max_vector_count; 52962306a36Sopenharmony_ci memset(&msix_entries[0], 0, 53062306a36Sopenharmony_ci sizeof(struct msix_entry) * max_vector_count); 53162306a36Sopenharmony_ci for (index = 0; index < max_vector_count; index++) 53262306a36Sopenharmony_ci msix_entries[index].entry = index; 53362306a36Sopenharmony_ci used_tx_channels = adapter->used_tx_channels; 53462306a36Sopenharmony_ci ret = pci_enable_msix_range(adapter->pdev, 53562306a36Sopenharmony_ci msix_entries, 1, 53662306a36Sopenharmony_ci 1 + used_tx_channels + 53762306a36Sopenharmony_ci LAN743X_USED_RX_CHANNELS); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (ret > 0) { 54062306a36Sopenharmony_ci intr->flags |= INTR_FLAG_MSIX_ENABLED; 54162306a36Sopenharmony_ci intr->number_of_vectors = ret; 54262306a36Sopenharmony_ci intr->using_vectors = true; 54362306a36Sopenharmony_ci for (index = 0; index < intr->number_of_vectors; index++) 54462306a36Sopenharmony_ci intr->vector_list[index].irq = msix_entries 54562306a36Sopenharmony_ci [index].vector; 54662306a36Sopenharmony_ci netif_info(adapter, ifup, adapter->netdev, 54762306a36Sopenharmony_ci "using MSIX interrupts, number of vectors = %d\n", 54862306a36Sopenharmony_ci intr->number_of_vectors); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* If MSIX failed try to setup using MSI interrupts */ 55262306a36Sopenharmony_ci if (!intr->number_of_vectors) { 55362306a36Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 55462306a36Sopenharmony_ci if (!pci_enable_msi(adapter->pdev)) { 55562306a36Sopenharmony_ci intr->flags |= INTR_FLAG_MSI_ENABLED; 55662306a36Sopenharmony_ci intr->number_of_vectors = 1; 55762306a36Sopenharmony_ci intr->using_vectors = true; 55862306a36Sopenharmony_ci intr->vector_list[0].irq = 55962306a36Sopenharmony_ci adapter->pdev->irq; 56062306a36Sopenharmony_ci netif_info(adapter, ifup, adapter->netdev, 56162306a36Sopenharmony_ci "using MSI interrupts, number of vectors = %d\n", 56262306a36Sopenharmony_ci intr->number_of_vectors); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* If MSIX, and MSI failed, setup using legacy interrupt */ 56862306a36Sopenharmony_ci if (!intr->number_of_vectors) { 56962306a36Sopenharmony_ci intr->number_of_vectors = 1; 57062306a36Sopenharmony_ci intr->using_vectors = false; 57162306a36Sopenharmony_ci intr->vector_list[0].irq = intr->irq; 57262306a36Sopenharmony_ci netif_info(adapter, ifup, adapter->netdev, 57362306a36Sopenharmony_ci "using legacy interrupts\n"); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* At this point we must have at least one irq */ 57762306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0xFFFFFFFF); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* map all interrupts to vector 0 */ 58062306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP0, 0x00000000); 58162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP1, 0x00000000); 58262306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP2, 0x00000000); 58362306a36Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ | 58462306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C | 58562306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK | 58662306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (intr->using_vectors) { 58962306a36Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR | 59062306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET; 59162306a36Sopenharmony_ci } else { 59262306a36Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR | 59362306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET | 59462306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_IRQ_SHARED; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (adapter->csr.flags & LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) { 59862306a36Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ; 59962306a36Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C; 60062306a36Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR; 60162306a36Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK; 60262306a36Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C; 60362306a36Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci init_waitqueue_head(&intr->software_isr_wq); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci ret = lan743x_intr_register_isr(adapter, 0, flags, 60962306a36Sopenharmony_ci INT_BIT_ALL_RX_ | INT_BIT_ALL_TX_ | 61062306a36Sopenharmony_ci INT_BIT_ALL_OTHER_, 61162306a36Sopenharmony_ci lan743x_intr_shared_isr, adapter); 61262306a36Sopenharmony_ci if (ret) 61362306a36Sopenharmony_ci goto clean_up; 61462306a36Sopenharmony_ci intr->flags |= INTR_FLAG_IRQ_REQUESTED(0); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (intr->using_vectors) 61762306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_SET, 61862306a36Sopenharmony_ci INT_VEC_EN_(0)); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 62162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG0, LAN743X_INT_MOD); 62262306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG1, LAN743X_INT_MOD); 62362306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG2, LAN743X_INT_MOD); 62462306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG3, LAN743X_INT_MOD); 62562306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG4, LAN743X_INT_MOD); 62662306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG5, LAN743X_INT_MOD); 62762306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG6, LAN743X_INT_MOD); 62862306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG7, LAN743X_INT_MOD); 62962306a36Sopenharmony_ci if (adapter->is_pci11x1x) { 63062306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG8, LAN743X_INT_MOD); 63162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG9, LAN743X_INT_MOD); 63262306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP0, 0x00007654); 63362306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP1, 0x00003210); 63462306a36Sopenharmony_ci } else { 63562306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP0, 0x00005432); 63662306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP1, 0x00000001); 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP2, 0x00FFFFFF); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* enable interrupts */ 64262306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_); 64362306a36Sopenharmony_ci ret = lan743x_intr_test_isr(adapter); 64462306a36Sopenharmony_ci if (ret) 64562306a36Sopenharmony_ci goto clean_up; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (intr->number_of_vectors > 1) { 64862306a36Sopenharmony_ci int number_of_tx_vectors = intr->number_of_vectors - 1; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (number_of_tx_vectors > used_tx_channels) 65162306a36Sopenharmony_ci number_of_tx_vectors = used_tx_channels; 65262306a36Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ | 65362306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C | 65462306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK | 65562306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR | 65662306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR | 65762306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (adapter->csr.flags & 66062306a36Sopenharmony_ci LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) { 66162306a36Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET | 66262306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET | 66362306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR | 66462306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci for (index = 0; index < number_of_tx_vectors; index++) { 66862306a36Sopenharmony_ci u32 int_bit = INT_BIT_DMA_TX_(index); 66962306a36Sopenharmony_ci int vector = index + 1; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* map TX interrupt to vector */ 67262306a36Sopenharmony_ci int_vec_map1 |= INT_VEC_MAP1_TX_VEC_(index, vector); 67362306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP1, int_vec_map1); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Remove TX interrupt from shared mask */ 67662306a36Sopenharmony_ci intr->vector_list[0].int_mask &= ~int_bit; 67762306a36Sopenharmony_ci ret = lan743x_intr_register_isr(adapter, vector, flags, 67862306a36Sopenharmony_ci int_bit, lan743x_tx_isr, 67962306a36Sopenharmony_ci &adapter->tx[index]); 68062306a36Sopenharmony_ci if (ret) 68162306a36Sopenharmony_ci goto clean_up; 68262306a36Sopenharmony_ci intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector); 68362306a36Sopenharmony_ci if (!(flags & 68462306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET)) 68562306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_SET, 68662306a36Sopenharmony_ci INT_VEC_EN_(vector)); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci if ((intr->number_of_vectors - used_tx_channels) > 1) { 69062306a36Sopenharmony_ci int number_of_rx_vectors = intr->number_of_vectors - 69162306a36Sopenharmony_ci used_tx_channels - 1; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (number_of_rx_vectors > LAN743X_USED_RX_CHANNELS) 69462306a36Sopenharmony_ci number_of_rx_vectors = LAN743X_USED_RX_CHANNELS; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ | 69762306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C | 69862306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK | 69962306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR | 70062306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR | 70162306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (adapter->csr.flags & 70462306a36Sopenharmony_ci LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) { 70562306a36Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR | 70662306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET | 70762306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET | 70862306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR | 70962306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci for (index = 0; index < number_of_rx_vectors; index++) { 71262306a36Sopenharmony_ci int vector = index + 1 + used_tx_channels; 71362306a36Sopenharmony_ci u32 int_bit = INT_BIT_DMA_RX_(index); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* map RX interrupt to vector */ 71662306a36Sopenharmony_ci int_vec_map0 |= INT_VEC_MAP0_RX_VEC_(index, vector); 71762306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP0, int_vec_map0); 71862306a36Sopenharmony_ci if (flags & 71962306a36Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR) { 72062306a36Sopenharmony_ci int_vec_en_auto_clr |= INT_VEC_EN_(vector); 72162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_AUTO_CLR, 72262306a36Sopenharmony_ci int_vec_en_auto_clr); 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Remove RX interrupt from shared mask */ 72662306a36Sopenharmony_ci intr->vector_list[0].int_mask &= ~int_bit; 72762306a36Sopenharmony_ci ret = lan743x_intr_register_isr(adapter, vector, flags, 72862306a36Sopenharmony_ci int_bit, lan743x_rx_isr, 72962306a36Sopenharmony_ci &adapter->rx[index]); 73062306a36Sopenharmony_ci if (ret) 73162306a36Sopenharmony_ci goto clean_up; 73262306a36Sopenharmony_ci intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_SET, 73562306a36Sopenharmony_ci INT_VEC_EN_(vector)); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ciclean_up: 74162306a36Sopenharmony_ci lan743x_intr_close(adapter); 74262306a36Sopenharmony_ci return ret; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int lan743x_dp_write(struct lan743x_adapter *adapter, 74662306a36Sopenharmony_ci u32 select, u32 addr, u32 length, u32 *buf) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci u32 dp_sel; 74962306a36Sopenharmony_ci int i; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL, DP_SEL_DPRDY_, 75262306a36Sopenharmony_ci 1, 40, 100, 100)) 75362306a36Sopenharmony_ci return -EIO; 75462306a36Sopenharmony_ci dp_sel = lan743x_csr_read(adapter, DP_SEL); 75562306a36Sopenharmony_ci dp_sel &= ~DP_SEL_MASK_; 75662306a36Sopenharmony_ci dp_sel |= select; 75762306a36Sopenharmony_ci lan743x_csr_write(adapter, DP_SEL, dp_sel); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci for (i = 0; i < length; i++) { 76062306a36Sopenharmony_ci lan743x_csr_write(adapter, DP_ADDR, addr + i); 76162306a36Sopenharmony_ci lan743x_csr_write(adapter, DP_DATA_0, buf[i]); 76262306a36Sopenharmony_ci lan743x_csr_write(adapter, DP_CMD, DP_CMD_WRITE_); 76362306a36Sopenharmony_ci if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL, 76462306a36Sopenharmony_ci DP_SEL_DPRDY_, 76562306a36Sopenharmony_ci 1, 40, 100, 100)) 76662306a36Sopenharmony_ci return -EIO; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci return 0; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic u32 lan743x_mac_mii_access(u16 id, u16 index, int read) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci u32 ret; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) & 77762306a36Sopenharmony_ci MAC_MII_ACC_PHY_ADDR_MASK_; 77862306a36Sopenharmony_ci ret |= (index << MAC_MII_ACC_MIIRINDA_SHIFT_) & 77962306a36Sopenharmony_ci MAC_MII_ACC_MIIRINDA_MASK_; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (read) 78262306a36Sopenharmony_ci ret |= MAC_MII_ACC_MII_READ_; 78362306a36Sopenharmony_ci else 78462306a36Sopenharmony_ci ret |= MAC_MII_ACC_MII_WRITE_; 78562306a36Sopenharmony_ci ret |= MAC_MII_ACC_MII_BUSY_; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci return ret; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci u32 data; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, MAC_MII_ACC, data, 79562306a36Sopenharmony_ci !(data & MAC_MII_ACC_MII_BUSY_), 0, 1000000); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int lan743x_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int index) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct lan743x_adapter *adapter = bus->priv; 80162306a36Sopenharmony_ci u32 val, mii_access; 80262306a36Sopenharmony_ci int ret; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* comfirm MII not busy */ 80562306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 80662306a36Sopenharmony_ci if (ret < 0) 80762306a36Sopenharmony_ci return ret; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* set the address, index & direction (read from PHY) */ 81062306a36Sopenharmony_ci mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_READ); 81162306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mii_access); 81262306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 81362306a36Sopenharmony_ci if (ret < 0) 81462306a36Sopenharmony_ci return ret; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci val = lan743x_csr_read(adapter, MAC_MII_DATA); 81762306a36Sopenharmony_ci return (int)(val & 0xFFFF); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int lan743x_mdiobus_write_c22(struct mii_bus *bus, 82162306a36Sopenharmony_ci int phy_id, int index, u16 regval) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct lan743x_adapter *adapter = bus->priv; 82462306a36Sopenharmony_ci u32 val, mii_access; 82562306a36Sopenharmony_ci int ret; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* confirm MII not busy */ 82862306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 82962306a36Sopenharmony_ci if (ret < 0) 83062306a36Sopenharmony_ci return ret; 83162306a36Sopenharmony_ci val = (u32)regval; 83262306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_DATA, val); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* set the address, index & direction (write to PHY) */ 83562306a36Sopenharmony_ci mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_WRITE); 83662306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mii_access); 83762306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 83862306a36Sopenharmony_ci return ret; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic u32 lan743x_mac_mmd_access(int id, int dev_addr, int op) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci u32 ret; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) & 84662306a36Sopenharmony_ci MAC_MII_ACC_PHY_ADDR_MASK_; 84762306a36Sopenharmony_ci ret |= (dev_addr << MAC_MII_ACC_MIIMMD_SHIFT_) & 84862306a36Sopenharmony_ci MAC_MII_ACC_MIIMMD_MASK_; 84962306a36Sopenharmony_ci if (op == MMD_ACCESS_WRITE) 85062306a36Sopenharmony_ci ret |= MAC_MII_ACC_MIICMD_WRITE_; 85162306a36Sopenharmony_ci else if (op == MMD_ACCESS_READ) 85262306a36Sopenharmony_ci ret |= MAC_MII_ACC_MIICMD_READ_; 85362306a36Sopenharmony_ci else if (op == MMD_ACCESS_READ_INC) 85462306a36Sopenharmony_ci ret |= MAC_MII_ACC_MIICMD_READ_INC_; 85562306a36Sopenharmony_ci else 85662306a36Sopenharmony_ci ret |= MAC_MII_ACC_MIICMD_ADDR_; 85762306a36Sopenharmony_ci ret |= (MAC_MII_ACC_MII_BUSY_ | MAC_MII_ACC_MIICL45_); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci return ret; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic int lan743x_mdiobus_read_c45(struct mii_bus *bus, int phy_id, 86362306a36Sopenharmony_ci int dev_addr, int index) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct lan743x_adapter *adapter = bus->priv; 86662306a36Sopenharmony_ci u32 mmd_access; 86762306a36Sopenharmony_ci int ret; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci /* comfirm MII not busy */ 87062306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 87162306a36Sopenharmony_ci if (ret < 0) 87262306a36Sopenharmony_ci return ret; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* Load Register Address */ 87562306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_DATA, index); 87662306a36Sopenharmony_ci mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr, 87762306a36Sopenharmony_ci MMD_ACCESS_ADDRESS); 87862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access); 87962306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 88062306a36Sopenharmony_ci if (ret < 0) 88162306a36Sopenharmony_ci return ret; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* Read Data */ 88462306a36Sopenharmony_ci mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr, 88562306a36Sopenharmony_ci MMD_ACCESS_READ); 88662306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access); 88762306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 88862306a36Sopenharmony_ci if (ret < 0) 88962306a36Sopenharmony_ci return ret; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci ret = lan743x_csr_read(adapter, MAC_MII_DATA); 89262306a36Sopenharmony_ci return (int)(ret & 0xFFFF); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int lan743x_mdiobus_write_c45(struct mii_bus *bus, int phy_id, 89662306a36Sopenharmony_ci int dev_addr, int index, u16 regval) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct lan743x_adapter *adapter = bus->priv; 89962306a36Sopenharmony_ci u32 mmd_access; 90062306a36Sopenharmony_ci int ret; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* confirm MII not busy */ 90362306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 90462306a36Sopenharmony_ci if (ret < 0) 90562306a36Sopenharmony_ci return ret; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* Load Register Address */ 90862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_DATA, (u32)index); 90962306a36Sopenharmony_ci mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr, 91062306a36Sopenharmony_ci MMD_ACCESS_ADDRESS); 91162306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access); 91262306a36Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 91362306a36Sopenharmony_ci if (ret < 0) 91462306a36Sopenharmony_ci return ret; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* Write Data */ 91762306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_DATA, (u32)regval); 91862306a36Sopenharmony_ci mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr, 91962306a36Sopenharmony_ci MMD_ACCESS_WRITE); 92062306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci return lan743x_mac_mii_wait_till_not_busy(adapter); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter *adapter) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci u32 data; 92862306a36Sopenharmony_ci int ret; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci ret = readx_poll_timeout(LAN743X_CSR_READ_OP, SGMII_ACC, data, 93162306a36Sopenharmony_ci !(data & SGMII_ACC_SGMII_BZY_), 100, 1000000); 93262306a36Sopenharmony_ci if (ret < 0) 93362306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 93462306a36Sopenharmony_ci "%s: error %d sgmii wait timeout\n", __func__, ret); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return ret; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ciint lan743x_sgmii_read(struct lan743x_adapter *adapter, u8 mmd, u16 addr) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci u32 mmd_access; 94262306a36Sopenharmony_ci int ret; 94362306a36Sopenharmony_ci u32 val; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (mmd > 31) { 94662306a36Sopenharmony_ci netif_err(adapter, probe, adapter->netdev, 94762306a36Sopenharmony_ci "%s mmd should <= 31\n", __func__); 94862306a36Sopenharmony_ci return -EINVAL; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci mutex_lock(&adapter->sgmii_rw_lock); 95262306a36Sopenharmony_ci /* Load Register Address */ 95362306a36Sopenharmony_ci mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_; 95462306a36Sopenharmony_ci mmd_access |= (addr | SGMII_ACC_SGMII_BZY_); 95562306a36Sopenharmony_ci lan743x_csr_write(adapter, SGMII_ACC, mmd_access); 95662306a36Sopenharmony_ci ret = lan743x_sgmii_wait_till_not_busy(adapter); 95762306a36Sopenharmony_ci if (ret < 0) 95862306a36Sopenharmony_ci goto sgmii_unlock; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci val = lan743x_csr_read(adapter, SGMII_DATA); 96162306a36Sopenharmony_ci ret = (int)(val & SGMII_DATA_MASK_); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cisgmii_unlock: 96462306a36Sopenharmony_ci mutex_unlock(&adapter->sgmii_rw_lock); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci return ret; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic int lan743x_sgmii_write(struct lan743x_adapter *adapter, 97062306a36Sopenharmony_ci u8 mmd, u16 addr, u16 val) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci u32 mmd_access; 97362306a36Sopenharmony_ci int ret; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (mmd > 31) { 97662306a36Sopenharmony_ci netif_err(adapter, probe, adapter->netdev, 97762306a36Sopenharmony_ci "%s mmd should <= 31\n", __func__); 97862306a36Sopenharmony_ci return -EINVAL; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci mutex_lock(&adapter->sgmii_rw_lock); 98162306a36Sopenharmony_ci /* Load Register Data */ 98262306a36Sopenharmony_ci lan743x_csr_write(adapter, SGMII_DATA, (u32)(val & SGMII_DATA_MASK_)); 98362306a36Sopenharmony_ci /* Load Register Address */ 98462306a36Sopenharmony_ci mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_; 98562306a36Sopenharmony_ci mmd_access |= (addr | SGMII_ACC_SGMII_BZY_ | SGMII_ACC_SGMII_WR_); 98662306a36Sopenharmony_ci lan743x_csr_write(adapter, SGMII_ACC, mmd_access); 98762306a36Sopenharmony_ci ret = lan743x_sgmii_wait_till_not_busy(adapter); 98862306a36Sopenharmony_ci mutex_unlock(&adapter->sgmii_rw_lock); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci return ret; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cistatic int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter, 99462306a36Sopenharmony_ci u16 baud) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci int mpllctrl0; 99762306a36Sopenharmony_ci int mpllctrl1; 99862306a36Sopenharmony_ci int miscctrl1; 99962306a36Sopenharmony_ci int ret; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci mpllctrl0 = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, 100262306a36Sopenharmony_ci VR_MII_GEN2_4_MPLL_CTRL0); 100362306a36Sopenharmony_ci if (mpllctrl0 < 0) 100462306a36Sopenharmony_ci return mpllctrl0; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci mpllctrl0 &= ~VR_MII_MPLL_CTRL0_USE_REFCLK_PAD_; 100762306a36Sopenharmony_ci if (baud == VR_MII_BAUD_RATE_1P25GBPS) { 100862306a36Sopenharmony_ci mpllctrl1 = VR_MII_MPLL_MULTIPLIER_100; 100962306a36Sopenharmony_ci /* mpll_baud_clk/4 */ 101062306a36Sopenharmony_ci miscctrl1 = 0xA; 101162306a36Sopenharmony_ci } else { 101262306a36Sopenharmony_ci mpllctrl1 = VR_MII_MPLL_MULTIPLIER_125; 101362306a36Sopenharmony_ci /* mpll_baud_clk/2 */ 101462306a36Sopenharmony_ci miscctrl1 = 0x5; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, 101862306a36Sopenharmony_ci VR_MII_GEN2_4_MPLL_CTRL0, mpllctrl0); 101962306a36Sopenharmony_ci if (ret < 0) 102062306a36Sopenharmony_ci return ret; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, 102362306a36Sopenharmony_ci VR_MII_GEN2_4_MPLL_CTRL1, mpllctrl1); 102462306a36Sopenharmony_ci if (ret < 0) 102562306a36Sopenharmony_ci return ret; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, 102862306a36Sopenharmony_ci VR_MII_GEN2_4_MISC_CTRL1, miscctrl1); 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic int lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter *adapter, 103262306a36Sopenharmony_ci bool enable) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci if (enable) 103562306a36Sopenharmony_ci return lan743x_sgmii_mpll_set(adapter, 103662306a36Sopenharmony_ci VR_MII_BAUD_RATE_3P125GBPS); 103762306a36Sopenharmony_ci else 103862306a36Sopenharmony_ci return lan743x_sgmii_mpll_set(adapter, 103962306a36Sopenharmony_ci VR_MII_BAUD_RATE_1P25GBPS); 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int lan743x_is_sgmii_2_5G_mode(struct lan743x_adapter *adapter, 104362306a36Sopenharmony_ci bool *status) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci int ret; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci ret = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, 104862306a36Sopenharmony_ci VR_MII_GEN2_4_MPLL_CTRL1); 104962306a36Sopenharmony_ci if (ret < 0) 105062306a36Sopenharmony_ci return ret; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (ret == VR_MII_MPLL_MULTIPLIER_125 || 105362306a36Sopenharmony_ci ret == VR_MII_MPLL_MULTIPLIER_50) 105462306a36Sopenharmony_ci *status = true; 105562306a36Sopenharmony_ci else 105662306a36Sopenharmony_ci *status = false; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int lan743x_sgmii_aneg_update(struct lan743x_adapter *adapter) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci enum lan743x_sgmii_lsd lsd = adapter->sgmii_lsd; 106462306a36Sopenharmony_ci int mii_ctrl; 106562306a36Sopenharmony_ci int dgt_ctrl; 106662306a36Sopenharmony_ci int an_ctrl; 106762306a36Sopenharmony_ci int ret; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE) 107062306a36Sopenharmony_ci /* Switch to 2.5 Gbps */ 107162306a36Sopenharmony_ci ret = lan743x_sgmii_2_5G_mode_set(adapter, true); 107262306a36Sopenharmony_ci else 107362306a36Sopenharmony_ci /* Switch to 10/100/1000 Mbps clock */ 107462306a36Sopenharmony_ci ret = lan743x_sgmii_2_5G_mode_set(adapter, false); 107562306a36Sopenharmony_ci if (ret < 0) 107662306a36Sopenharmony_ci return ret; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Enable SGMII Auto NEG */ 107962306a36Sopenharmony_ci mii_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR); 108062306a36Sopenharmony_ci if (mii_ctrl < 0) 108162306a36Sopenharmony_ci return mii_ctrl; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci an_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, VR_MII_AN_CTRL); 108462306a36Sopenharmony_ci if (an_ctrl < 0) 108562306a36Sopenharmony_ci return an_ctrl; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci dgt_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, 108862306a36Sopenharmony_ci VR_MII_DIG_CTRL1); 108962306a36Sopenharmony_ci if (dgt_ctrl < 0) 109062306a36Sopenharmony_ci return dgt_ctrl; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE) { 109362306a36Sopenharmony_ci mii_ctrl &= ~(BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100); 109462306a36Sopenharmony_ci mii_ctrl |= BMCR_SPEED1000; 109562306a36Sopenharmony_ci dgt_ctrl |= VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_; 109662306a36Sopenharmony_ci dgt_ctrl &= ~VR_MII_DIG_CTRL1_MAC_AUTO_SW_; 109762306a36Sopenharmony_ci /* In order for Auto-Negotiation to operate properly at 109862306a36Sopenharmony_ci * 2.5 Gbps the 1.6ms link timer values must be adjusted 109962306a36Sopenharmony_ci * The VR_MII_LINK_TIMER_CTRL Register must be set to 110062306a36Sopenharmony_ci * 16'h7A1 and The CL37_TMR_OVR_RIDE bit of the 110162306a36Sopenharmony_ci * VR_MII_DIG_CTRL1 Register set to 1 110262306a36Sopenharmony_ci */ 110362306a36Sopenharmony_ci ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, 110462306a36Sopenharmony_ci VR_MII_LINK_TIMER_CTRL, 0x7A1); 110562306a36Sopenharmony_ci if (ret < 0) 110662306a36Sopenharmony_ci return ret; 110762306a36Sopenharmony_ci } else { 110862306a36Sopenharmony_ci mii_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART); 110962306a36Sopenharmony_ci an_ctrl &= ~VR_MII_AN_CTRL_SGMII_LINK_STS_; 111062306a36Sopenharmony_ci dgt_ctrl &= ~VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_; 111162306a36Sopenharmony_ci dgt_ctrl |= VR_MII_DIG_CTRL1_MAC_AUTO_SW_; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, 111562306a36Sopenharmony_ci mii_ctrl); 111662306a36Sopenharmony_ci if (ret < 0) 111762306a36Sopenharmony_ci return ret; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, 112062306a36Sopenharmony_ci VR_MII_DIG_CTRL1, dgt_ctrl); 112162306a36Sopenharmony_ci if (ret < 0) 112262306a36Sopenharmony_ci return ret; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, 112562306a36Sopenharmony_ci VR_MII_AN_CTRL, an_ctrl); 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci u8 wait_cnt = 0; 113162306a36Sopenharmony_ci u32 dig_sts; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci do { 113462306a36Sopenharmony_ci dig_sts = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, 113562306a36Sopenharmony_ci VR_MII_DIG_STS); 113662306a36Sopenharmony_ci if (((dig_sts & VR_MII_DIG_STS_PSEQ_STATE_MASK_) >> 113762306a36Sopenharmony_ci VR_MII_DIG_STS_PSEQ_STATE_POS_) == state) 113862306a36Sopenharmony_ci break; 113962306a36Sopenharmony_ci usleep_range(1000, 2000); 114062306a36Sopenharmony_ci } while (wait_cnt++ < 10); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (wait_cnt >= 10) 114362306a36Sopenharmony_ci return -ETIMEDOUT; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic int lan743x_sgmii_config(struct lan743x_adapter *adapter) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 115162306a36Sopenharmony_ci struct phy_device *phydev = netdev->phydev; 115262306a36Sopenharmony_ci enum lan743x_sgmii_lsd lsd = POWER_DOWN; 115362306a36Sopenharmony_ci int mii_ctl; 115462306a36Sopenharmony_ci bool status; 115562306a36Sopenharmony_ci int ret; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci switch (phydev->speed) { 115862306a36Sopenharmony_ci case SPEED_2500: 115962306a36Sopenharmony_ci if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER) 116062306a36Sopenharmony_ci lsd = LINK_2500_MASTER; 116162306a36Sopenharmony_ci else 116262306a36Sopenharmony_ci lsd = LINK_2500_SLAVE; 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci case SPEED_1000: 116562306a36Sopenharmony_ci if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER) 116662306a36Sopenharmony_ci lsd = LINK_1000_MASTER; 116762306a36Sopenharmony_ci else 116862306a36Sopenharmony_ci lsd = LINK_1000_SLAVE; 116962306a36Sopenharmony_ci break; 117062306a36Sopenharmony_ci case SPEED_100: 117162306a36Sopenharmony_ci if (phydev->duplex) 117262306a36Sopenharmony_ci lsd = LINK_100FD; 117362306a36Sopenharmony_ci else 117462306a36Sopenharmony_ci lsd = LINK_100HD; 117562306a36Sopenharmony_ci break; 117662306a36Sopenharmony_ci case SPEED_10: 117762306a36Sopenharmony_ci if (phydev->duplex) 117862306a36Sopenharmony_ci lsd = LINK_10FD; 117962306a36Sopenharmony_ci else 118062306a36Sopenharmony_ci lsd = LINK_10HD; 118162306a36Sopenharmony_ci break; 118262306a36Sopenharmony_ci default: 118362306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 118462306a36Sopenharmony_ci "Invalid speed %d\n", phydev->speed); 118562306a36Sopenharmony_ci return -EINVAL; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci adapter->sgmii_lsd = lsd; 118962306a36Sopenharmony_ci ret = lan743x_sgmii_aneg_update(adapter); 119062306a36Sopenharmony_ci if (ret < 0) { 119162306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 119262306a36Sopenharmony_ci "error %d SGMII cfg failed\n", ret); 119362306a36Sopenharmony_ci return ret; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci ret = lan743x_is_sgmii_2_5G_mode(adapter, &status); 119762306a36Sopenharmony_ci if (ret < 0) { 119862306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 119962306a36Sopenharmony_ci "erro %d SGMII get mode failed\n", ret); 120062306a36Sopenharmony_ci return ret; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (status) 120462306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, 120562306a36Sopenharmony_ci "SGMII 2.5G mode enable\n"); 120662306a36Sopenharmony_ci else 120762306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, 120862306a36Sopenharmony_ci "SGMII 1G mode enable\n"); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* SGMII/1000/2500BASE-X PCS power down */ 121162306a36Sopenharmony_ci mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR); 121262306a36Sopenharmony_ci if (mii_ctl < 0) 121362306a36Sopenharmony_ci return mii_ctl; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci mii_ctl |= BMCR_PDOWN; 121662306a36Sopenharmony_ci ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl); 121762306a36Sopenharmony_ci if (ret < 0) 121862306a36Sopenharmony_ci return ret; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_DOWN); 122162306a36Sopenharmony_ci if (ret < 0) 122262306a36Sopenharmony_ci return ret; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* SGMII/1000/2500BASE-X PCS power up */ 122562306a36Sopenharmony_ci mii_ctl &= ~BMCR_PDOWN; 122662306a36Sopenharmony_ci ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl); 122762306a36Sopenharmony_ci if (ret < 0) 122862306a36Sopenharmony_ci return ret; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP); 123162306a36Sopenharmony_ci if (ret < 0) 123262306a36Sopenharmony_ci return ret; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci return 0; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_cistatic void lan743x_mac_set_address(struct lan743x_adapter *adapter, 123862306a36Sopenharmony_ci u8 *addr) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci u32 addr_lo, addr_hi; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci addr_lo = addr[0] | 124362306a36Sopenharmony_ci addr[1] << 8 | 124462306a36Sopenharmony_ci addr[2] << 16 | 124562306a36Sopenharmony_ci addr[3] << 24; 124662306a36Sopenharmony_ci addr_hi = addr[4] | 124762306a36Sopenharmony_ci addr[5] << 8; 124862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX_ADDRL, addr_lo); 124962306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX_ADDRH, addr_hi); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci ether_addr_copy(adapter->mac_address, addr); 125262306a36Sopenharmony_ci netif_info(adapter, drv, adapter->netdev, 125362306a36Sopenharmony_ci "MAC address set to %pM\n", addr); 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic int lan743x_mac_init(struct lan743x_adapter *adapter) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci bool mac_address_valid = true; 125962306a36Sopenharmony_ci struct net_device *netdev; 126062306a36Sopenharmony_ci u32 mac_addr_hi = 0; 126162306a36Sopenharmony_ci u32 mac_addr_lo = 0; 126262306a36Sopenharmony_ci u32 data; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci netdev = adapter->netdev; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* disable auto duplex, and speed detection. Phylib does that */ 126762306a36Sopenharmony_ci data = lan743x_csr_read(adapter, MAC_CR); 126862306a36Sopenharmony_ci data &= ~(MAC_CR_ADD_ | MAC_CR_ASD_); 126962306a36Sopenharmony_ci data |= MAC_CR_CNTR_RST_; 127062306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, data); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (!is_valid_ether_addr(adapter->mac_address)) { 127362306a36Sopenharmony_ci mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH); 127462306a36Sopenharmony_ci mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL); 127562306a36Sopenharmony_ci adapter->mac_address[0] = mac_addr_lo & 0xFF; 127662306a36Sopenharmony_ci adapter->mac_address[1] = (mac_addr_lo >> 8) & 0xFF; 127762306a36Sopenharmony_ci adapter->mac_address[2] = (mac_addr_lo >> 16) & 0xFF; 127862306a36Sopenharmony_ci adapter->mac_address[3] = (mac_addr_lo >> 24) & 0xFF; 127962306a36Sopenharmony_ci adapter->mac_address[4] = mac_addr_hi & 0xFF; 128062306a36Sopenharmony_ci adapter->mac_address[5] = (mac_addr_hi >> 8) & 0xFF; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) && 128362306a36Sopenharmony_ci mac_addr_lo == 0xFFFFFFFF) { 128462306a36Sopenharmony_ci mac_address_valid = false; 128562306a36Sopenharmony_ci } else if (!is_valid_ether_addr(adapter->mac_address)) { 128662306a36Sopenharmony_ci mac_address_valid = false; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (!mac_address_valid) 129062306a36Sopenharmony_ci eth_random_addr(adapter->mac_address); 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci lan743x_mac_set_address(adapter, adapter->mac_address); 129362306a36Sopenharmony_ci eth_hw_addr_set(netdev, adapter->mac_address); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci return 0; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic int lan743x_mac_open(struct lan743x_adapter *adapter) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci u32 temp; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_RX); 130362306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, temp | MAC_RX_RXEN_); 130462306a36Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_TX); 130562306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_TX, temp | MAC_TX_TXEN_); 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic void lan743x_mac_close(struct lan743x_adapter *adapter) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci u32 temp; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_TX); 131462306a36Sopenharmony_ci temp &= ~MAC_TX_TXEN_; 131562306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_TX, temp); 131662306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, MAC_TX, MAC_TX_TXD_, 131762306a36Sopenharmony_ci 1, 1000, 20000, 100); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_RX); 132062306a36Sopenharmony_ci temp &= ~MAC_RX_RXEN_; 132162306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, temp); 132262306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, 132362306a36Sopenharmony_ci 1, 1000, 20000, 100); 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_civoid lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter, 132762306a36Sopenharmony_ci bool tx_enable, bool rx_enable) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci u32 flow_setting = 0; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci /* set maximum pause time because when fifo space frees 133262306a36Sopenharmony_ci * up a zero value pause frame will be sent to release the pause 133362306a36Sopenharmony_ci */ 133462306a36Sopenharmony_ci flow_setting = MAC_FLOW_CR_FCPT_MASK_; 133562306a36Sopenharmony_ci if (tx_enable) 133662306a36Sopenharmony_ci flow_setting |= MAC_FLOW_CR_TX_FCEN_; 133762306a36Sopenharmony_ci if (rx_enable) 133862306a36Sopenharmony_ci flow_setting |= MAC_FLOW_CR_RX_FCEN_; 133962306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_FLOW, flow_setting); 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic int lan743x_mac_set_mtu(struct lan743x_adapter *adapter, int new_mtu) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci int enabled = 0; 134562306a36Sopenharmony_ci u32 mac_rx = 0; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci mac_rx = lan743x_csr_read(adapter, MAC_RX); 134862306a36Sopenharmony_ci if (mac_rx & MAC_RX_RXEN_) { 134962306a36Sopenharmony_ci enabled = 1; 135062306a36Sopenharmony_ci if (mac_rx & MAC_RX_RXD_) { 135162306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 135262306a36Sopenharmony_ci mac_rx &= ~MAC_RX_RXD_; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci mac_rx &= ~MAC_RX_RXEN_; 135562306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 135662306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, 135762306a36Sopenharmony_ci 1, 1000, 20000, 100); 135862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx | MAC_RX_RXD_); 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci mac_rx &= ~(MAC_RX_MAX_SIZE_MASK_); 136262306a36Sopenharmony_ci mac_rx |= (((new_mtu + ETH_HLEN + ETH_FCS_LEN) 136362306a36Sopenharmony_ci << MAC_RX_MAX_SIZE_SHIFT_) & MAC_RX_MAX_SIZE_MASK_); 136462306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (enabled) { 136762306a36Sopenharmony_ci mac_rx |= MAC_RX_RXEN_; 136862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci return 0; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci/* PHY */ 137462306a36Sopenharmony_cistatic int lan743x_phy_reset(struct lan743x_adapter *adapter) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci u32 data; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* Only called with in probe, and before mdiobus_register */ 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci data = lan743x_csr_read(adapter, PMT_CTL); 138162306a36Sopenharmony_ci data |= PMT_CTL_ETH_PHY_RST_; 138262306a36Sopenharmony_ci lan743x_csr_write(adapter, PMT_CTL, data); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, PMT_CTL, data, 138562306a36Sopenharmony_ci (!(data & PMT_CTL_ETH_PHY_RST_) && 138662306a36Sopenharmony_ci (data & PMT_CTL_READY_)), 138762306a36Sopenharmony_ci 50000, 1000000); 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_cistatic void lan743x_phy_update_flowcontrol(struct lan743x_adapter *adapter, 139162306a36Sopenharmony_ci u16 local_adv, u16 remote_adv) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct lan743x_phy *phy = &adapter->phy; 139462306a36Sopenharmony_ci u8 cap; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (phy->fc_autoneg) 139762306a36Sopenharmony_ci cap = mii_resolve_flowctrl_fdx(local_adv, remote_adv); 139862306a36Sopenharmony_ci else 139962306a36Sopenharmony_ci cap = phy->fc_request_control; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci lan743x_mac_flow_ctrl_set_enables(adapter, 140262306a36Sopenharmony_ci cap & FLOW_CTRL_TX, 140362306a36Sopenharmony_ci cap & FLOW_CTRL_RX); 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cistatic int lan743x_phy_init(struct lan743x_adapter *adapter) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci return lan743x_phy_reset(adapter); 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_cistatic void lan743x_phy_link_status_change(struct net_device *netdev) 141262306a36Sopenharmony_ci{ 141362306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 141462306a36Sopenharmony_ci struct phy_device *phydev = netdev->phydev; 141562306a36Sopenharmony_ci u32 data; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci phy_print_status(phydev); 141862306a36Sopenharmony_ci if (phydev->state == PHY_RUNNING) { 141962306a36Sopenharmony_ci int remote_advertisement = 0; 142062306a36Sopenharmony_ci int local_advertisement = 0; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci data = lan743x_csr_read(adapter, MAC_CR); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci /* set duplex mode */ 142562306a36Sopenharmony_ci if (phydev->duplex) 142662306a36Sopenharmony_ci data |= MAC_CR_DPX_; 142762306a36Sopenharmony_ci else 142862306a36Sopenharmony_ci data &= ~MAC_CR_DPX_; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* set bus speed */ 143162306a36Sopenharmony_ci switch (phydev->speed) { 143262306a36Sopenharmony_ci case SPEED_10: 143362306a36Sopenharmony_ci data &= ~MAC_CR_CFG_H_; 143462306a36Sopenharmony_ci data &= ~MAC_CR_CFG_L_; 143562306a36Sopenharmony_ci break; 143662306a36Sopenharmony_ci case SPEED_100: 143762306a36Sopenharmony_ci data &= ~MAC_CR_CFG_H_; 143862306a36Sopenharmony_ci data |= MAC_CR_CFG_L_; 143962306a36Sopenharmony_ci break; 144062306a36Sopenharmony_ci case SPEED_1000: 144162306a36Sopenharmony_ci data |= MAC_CR_CFG_H_; 144262306a36Sopenharmony_ci data &= ~MAC_CR_CFG_L_; 144362306a36Sopenharmony_ci break; 144462306a36Sopenharmony_ci case SPEED_2500: 144562306a36Sopenharmony_ci data |= MAC_CR_CFG_H_; 144662306a36Sopenharmony_ci data |= MAC_CR_CFG_L_; 144762306a36Sopenharmony_ci break; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, data); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci local_advertisement = 145262306a36Sopenharmony_ci linkmode_adv_to_mii_adv_t(phydev->advertising); 145362306a36Sopenharmony_ci remote_advertisement = 145462306a36Sopenharmony_ci linkmode_adv_to_mii_adv_t(phydev->lp_advertising); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci lan743x_phy_update_flowcontrol(adapter, local_advertisement, 145762306a36Sopenharmony_ci remote_advertisement); 145862306a36Sopenharmony_ci lan743x_ptp_update_latency(adapter, phydev->speed); 145962306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_SGMII || 146062306a36Sopenharmony_ci phydev->interface == PHY_INTERFACE_MODE_1000BASEX || 146162306a36Sopenharmony_ci phydev->interface == PHY_INTERFACE_MODE_2500BASEX) 146262306a36Sopenharmony_ci lan743x_sgmii_config(adapter); 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic void lan743x_phy_close(struct lan743x_adapter *adapter) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci phy_stop(netdev->phydev); 147162306a36Sopenharmony_ci phy_disconnect(netdev->phydev); 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_cistatic void lan743x_phy_interface_select(struct lan743x_adapter *adapter) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci u32 id_rev; 147762306a36Sopenharmony_ci u32 data; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci data = lan743x_csr_read(adapter, MAC_CR); 148062306a36Sopenharmony_ci id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci if (adapter->is_pci11x1x && adapter->is_sgmii_en) 148362306a36Sopenharmony_ci adapter->phy_interface = PHY_INTERFACE_MODE_SGMII; 148462306a36Sopenharmony_ci else if (id_rev == ID_REV_ID_LAN7430_) 148562306a36Sopenharmony_ci adapter->phy_interface = PHY_INTERFACE_MODE_GMII; 148662306a36Sopenharmony_ci else if ((id_rev == ID_REV_ID_LAN7431_) && (data & MAC_CR_MII_EN_)) 148762306a36Sopenharmony_ci adapter->phy_interface = PHY_INTERFACE_MODE_MII; 148862306a36Sopenharmony_ci else 148962306a36Sopenharmony_ci adapter->phy_interface = PHY_INTERFACE_MODE_RGMII; 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic int lan743x_phy_open(struct lan743x_adapter *adapter) 149362306a36Sopenharmony_ci{ 149462306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 149562306a36Sopenharmony_ci struct lan743x_phy *phy = &adapter->phy; 149662306a36Sopenharmony_ci struct fixed_phy_status fphy_status = { 149762306a36Sopenharmony_ci .link = 1, 149862306a36Sopenharmony_ci .speed = SPEED_1000, 149962306a36Sopenharmony_ci .duplex = DUPLEX_FULL, 150062306a36Sopenharmony_ci }; 150162306a36Sopenharmony_ci struct phy_device *phydev; 150262306a36Sopenharmony_ci int ret = -EIO; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci /* try devicetree phy, or fixed link */ 150562306a36Sopenharmony_ci phydev = of_phy_get_and_connect(netdev, adapter->pdev->dev.of_node, 150662306a36Sopenharmony_ci lan743x_phy_link_status_change); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (!phydev) { 150962306a36Sopenharmony_ci /* try internal phy */ 151062306a36Sopenharmony_ci phydev = phy_find_first(adapter->mdiobus); 151162306a36Sopenharmony_ci if (!phydev) { 151262306a36Sopenharmony_ci if ((adapter->csr.id_rev & ID_REV_ID_MASK_) == 151362306a36Sopenharmony_ci ID_REV_ID_LAN7431_) { 151462306a36Sopenharmony_ci phydev = fixed_phy_register(PHY_POLL, 151562306a36Sopenharmony_ci &fphy_status, NULL); 151662306a36Sopenharmony_ci if (IS_ERR(phydev)) { 151762306a36Sopenharmony_ci netdev_err(netdev, "No PHY/fixed_PHY found\n"); 151862306a36Sopenharmony_ci return PTR_ERR(phydev); 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci } else { 152162306a36Sopenharmony_ci goto return_error; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci lan743x_phy_interface_select(adapter); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci ret = phy_connect_direct(netdev, phydev, 152862306a36Sopenharmony_ci lan743x_phy_link_status_change, 152962306a36Sopenharmony_ci adapter->phy_interface); 153062306a36Sopenharmony_ci if (ret) 153162306a36Sopenharmony_ci goto return_error; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* MAC doesn't support 1000T Half */ 153562306a36Sopenharmony_ci phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci /* support both flow controls */ 153862306a36Sopenharmony_ci phy_support_asym_pause(phydev); 153962306a36Sopenharmony_ci phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX); 154062306a36Sopenharmony_ci phy->fc_autoneg = phydev->autoneg; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci phy_start(phydev); 154362306a36Sopenharmony_ci phy_start_aneg(phydev); 154462306a36Sopenharmony_ci phy_attached_info(phydev); 154562306a36Sopenharmony_ci return 0; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_cireturn_error: 154862306a36Sopenharmony_ci return ret; 154962306a36Sopenharmony_ci} 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic void lan743x_rfe_open(struct lan743x_adapter *adapter) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci lan743x_csr_write(adapter, RFE_RSS_CFG, 155462306a36Sopenharmony_ci RFE_RSS_CFG_UDP_IPV6_EX_ | 155562306a36Sopenharmony_ci RFE_RSS_CFG_TCP_IPV6_EX_ | 155662306a36Sopenharmony_ci RFE_RSS_CFG_IPV6_EX_ | 155762306a36Sopenharmony_ci RFE_RSS_CFG_UDP_IPV6_ | 155862306a36Sopenharmony_ci RFE_RSS_CFG_TCP_IPV6_ | 155962306a36Sopenharmony_ci RFE_RSS_CFG_IPV6_ | 156062306a36Sopenharmony_ci RFE_RSS_CFG_UDP_IPV4_ | 156162306a36Sopenharmony_ci RFE_RSS_CFG_TCP_IPV4_ | 156262306a36Sopenharmony_ci RFE_RSS_CFG_IPV4_ | 156362306a36Sopenharmony_ci RFE_RSS_CFG_VALID_HASH_BITS_ | 156462306a36Sopenharmony_ci RFE_RSS_CFG_RSS_QUEUE_ENABLE_ | 156562306a36Sopenharmony_ci RFE_RSS_CFG_RSS_HASH_STORE_ | 156662306a36Sopenharmony_ci RFE_RSS_CFG_RSS_ENABLE_); 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic void lan743x_rfe_update_mac_address(struct lan743x_adapter *adapter) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci u8 *mac_addr; 157262306a36Sopenharmony_ci u32 mac_addr_hi = 0; 157362306a36Sopenharmony_ci u32 mac_addr_lo = 0; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci /* Add mac address to perfect Filter */ 157662306a36Sopenharmony_ci mac_addr = adapter->mac_address; 157762306a36Sopenharmony_ci mac_addr_lo = ((((u32)(mac_addr[0])) << 0) | 157862306a36Sopenharmony_ci (((u32)(mac_addr[1])) << 8) | 157962306a36Sopenharmony_ci (((u32)(mac_addr[2])) << 16) | 158062306a36Sopenharmony_ci (((u32)(mac_addr[3])) << 24)); 158162306a36Sopenharmony_ci mac_addr_hi = ((((u32)(mac_addr[4])) << 0) | 158262306a36Sopenharmony_ci (((u32)(mac_addr[5])) << 8)); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci lan743x_csr_write(adapter, RFE_ADDR_FILT_LO(0), mac_addr_lo); 158562306a36Sopenharmony_ci lan743x_csr_write(adapter, RFE_ADDR_FILT_HI(0), 158662306a36Sopenharmony_ci mac_addr_hi | RFE_ADDR_FILT_HI_VALID_); 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_cistatic void lan743x_rfe_set_multicast(struct lan743x_adapter *adapter) 159062306a36Sopenharmony_ci{ 159162306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 159262306a36Sopenharmony_ci u32 hash_table[DP_SEL_VHF_HASH_LEN]; 159362306a36Sopenharmony_ci u32 rfctl; 159462306a36Sopenharmony_ci u32 data; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci rfctl = lan743x_csr_read(adapter, RFE_CTL); 159762306a36Sopenharmony_ci rfctl &= ~(RFE_CTL_AU_ | RFE_CTL_AM_ | 159862306a36Sopenharmony_ci RFE_CTL_DA_PERFECT_ | RFE_CTL_MCAST_HASH_); 159962306a36Sopenharmony_ci rfctl |= RFE_CTL_AB_; 160062306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 160162306a36Sopenharmony_ci rfctl |= RFE_CTL_AM_ | RFE_CTL_AU_; 160262306a36Sopenharmony_ci } else { 160362306a36Sopenharmony_ci if (netdev->flags & IFF_ALLMULTI) 160462306a36Sopenharmony_ci rfctl |= RFE_CTL_AM_; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (netdev->features & NETIF_F_RXCSUM) 160862306a36Sopenharmony_ci rfctl |= RFE_CTL_IP_COE_ | RFE_CTL_TCP_UDP_COE_; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci memset(hash_table, 0, DP_SEL_VHF_HASH_LEN * sizeof(u32)); 161162306a36Sopenharmony_ci if (netdev_mc_count(netdev)) { 161262306a36Sopenharmony_ci struct netdev_hw_addr *ha; 161362306a36Sopenharmony_ci int i; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci rfctl |= RFE_CTL_DA_PERFECT_; 161662306a36Sopenharmony_ci i = 1; 161762306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 161862306a36Sopenharmony_ci /* set first 32 into Perfect Filter */ 161962306a36Sopenharmony_ci if (i < 33) { 162062306a36Sopenharmony_ci lan743x_csr_write(adapter, 162162306a36Sopenharmony_ci RFE_ADDR_FILT_HI(i), 0); 162262306a36Sopenharmony_ci data = ha->addr[3]; 162362306a36Sopenharmony_ci data = ha->addr[2] | (data << 8); 162462306a36Sopenharmony_ci data = ha->addr[1] | (data << 8); 162562306a36Sopenharmony_ci data = ha->addr[0] | (data << 8); 162662306a36Sopenharmony_ci lan743x_csr_write(adapter, 162762306a36Sopenharmony_ci RFE_ADDR_FILT_LO(i), data); 162862306a36Sopenharmony_ci data = ha->addr[5]; 162962306a36Sopenharmony_ci data = ha->addr[4] | (data << 8); 163062306a36Sopenharmony_ci data |= RFE_ADDR_FILT_HI_VALID_; 163162306a36Sopenharmony_ci lan743x_csr_write(adapter, 163262306a36Sopenharmony_ci RFE_ADDR_FILT_HI(i), data); 163362306a36Sopenharmony_ci } else { 163462306a36Sopenharmony_ci u32 bitnum = (ether_crc(ETH_ALEN, ha->addr) >> 163562306a36Sopenharmony_ci 23) & 0x1FF; 163662306a36Sopenharmony_ci hash_table[bitnum / 32] |= (1 << (bitnum % 32)); 163762306a36Sopenharmony_ci rfctl |= RFE_CTL_MCAST_HASH_; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci i++; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci lan743x_dp_write(adapter, DP_SEL_RFE_RAM, 164462306a36Sopenharmony_ci DP_SEL_VHF_VLAN_LEN, 164562306a36Sopenharmony_ci DP_SEL_VHF_HASH_LEN, hash_table); 164662306a36Sopenharmony_ci lan743x_csr_write(adapter, RFE_CTL, rfctl); 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic int lan743x_dmac_init(struct lan743x_adapter *adapter) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci u32 data = 0; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_SWR_); 165462306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, DMAC_CMD, DMAC_CMD_SWR_, 165562306a36Sopenharmony_ci 0, 1000, 20000, 100); 165662306a36Sopenharmony_ci switch (DEFAULT_DMA_DESCRIPTOR_SPACING) { 165762306a36Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_16: 165862306a36Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_16_; 165962306a36Sopenharmony_ci break; 166062306a36Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_32: 166162306a36Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_32_; 166262306a36Sopenharmony_ci break; 166362306a36Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_64: 166462306a36Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_64_; 166562306a36Sopenharmony_ci break; 166662306a36Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_128: 166762306a36Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_128_; 166862306a36Sopenharmony_ci break; 166962306a36Sopenharmony_ci default: 167062306a36Sopenharmony_ci return -EPERM; 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) 167362306a36Sopenharmony_ci data |= DMAC_CFG_COAL_EN_; 167462306a36Sopenharmony_ci data |= DMAC_CFG_CH_ARB_SEL_RX_HIGH_; 167562306a36Sopenharmony_ci data |= DMAC_CFG_MAX_READ_REQ_SET_(6); 167662306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CFG, data); 167762306a36Sopenharmony_ci data = DMAC_COAL_CFG_TIMER_LIMIT_SET_(1); 167862306a36Sopenharmony_ci data |= DMAC_COAL_CFG_TIMER_TX_START_; 167962306a36Sopenharmony_ci data |= DMAC_COAL_CFG_FLUSH_INTS_; 168062306a36Sopenharmony_ci data |= DMAC_COAL_CFG_INT_EXIT_COAL_; 168162306a36Sopenharmony_ci data |= DMAC_COAL_CFG_CSR_EXIT_COAL_; 168262306a36Sopenharmony_ci data |= DMAC_COAL_CFG_TX_THRES_SET_(0x0A); 168362306a36Sopenharmony_ci data |= DMAC_COAL_CFG_RX_THRES_SET_(0x0C); 168462306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_COAL_CFG, data); 168562306a36Sopenharmony_ci data = DMAC_OBFF_TX_THRES_SET_(0x08); 168662306a36Sopenharmony_ci data |= DMAC_OBFF_RX_THRES_SET_(0x0A); 168762306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_OBFF_CFG, data); 168862306a36Sopenharmony_ci return 0; 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cistatic int lan743x_dmac_tx_get_state(struct lan743x_adapter *adapter, 169262306a36Sopenharmony_ci int tx_channel) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci u32 dmac_cmd = 0; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD); 169762306a36Sopenharmony_ci return DMAC_CHANNEL_STATE_SET((dmac_cmd & 169862306a36Sopenharmony_ci DMAC_CMD_START_T_(tx_channel)), 169962306a36Sopenharmony_ci (dmac_cmd & 170062306a36Sopenharmony_ci DMAC_CMD_STOP_T_(tx_channel))); 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cistatic int lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter *adapter, 170462306a36Sopenharmony_ci int tx_channel) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci int timeout = 100; 170762306a36Sopenharmony_ci int result = 0; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci while (timeout && 171062306a36Sopenharmony_ci ((result = lan743x_dmac_tx_get_state(adapter, tx_channel)) == 171162306a36Sopenharmony_ci DMAC_CHANNEL_STATE_STOP_PENDING)) { 171262306a36Sopenharmony_ci usleep_range(1000, 20000); 171362306a36Sopenharmony_ci timeout--; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci if (result == DMAC_CHANNEL_STATE_STOP_PENDING) 171662306a36Sopenharmony_ci result = -ENODEV; 171762306a36Sopenharmony_ci return result; 171862306a36Sopenharmony_ci} 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_cistatic int lan743x_dmac_rx_get_state(struct lan743x_adapter *adapter, 172162306a36Sopenharmony_ci int rx_channel) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci u32 dmac_cmd = 0; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD); 172662306a36Sopenharmony_ci return DMAC_CHANNEL_STATE_SET((dmac_cmd & 172762306a36Sopenharmony_ci DMAC_CMD_START_R_(rx_channel)), 172862306a36Sopenharmony_ci (dmac_cmd & 172962306a36Sopenharmony_ci DMAC_CMD_STOP_R_(rx_channel))); 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_cistatic int lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter *adapter, 173362306a36Sopenharmony_ci int rx_channel) 173462306a36Sopenharmony_ci{ 173562306a36Sopenharmony_ci int timeout = 100; 173662306a36Sopenharmony_ci int result = 0; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci while (timeout && 173962306a36Sopenharmony_ci ((result = lan743x_dmac_rx_get_state(adapter, rx_channel)) == 174062306a36Sopenharmony_ci DMAC_CHANNEL_STATE_STOP_PENDING)) { 174162306a36Sopenharmony_ci usleep_range(1000, 20000); 174262306a36Sopenharmony_ci timeout--; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci if (result == DMAC_CHANNEL_STATE_STOP_PENDING) 174562306a36Sopenharmony_ci result = -ENODEV; 174662306a36Sopenharmony_ci return result; 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_cistatic void lan743x_tx_release_desc(struct lan743x_tx *tx, 175062306a36Sopenharmony_ci int descriptor_index, bool cleanup) 175162306a36Sopenharmony_ci{ 175262306a36Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 175362306a36Sopenharmony_ci struct lan743x_tx_descriptor *descriptor = NULL; 175462306a36Sopenharmony_ci u32 descriptor_type = 0; 175562306a36Sopenharmony_ci bool ignore_sync; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci descriptor = &tx->ring_cpu_ptr[descriptor_index]; 175862306a36Sopenharmony_ci buffer_info = &tx->buffer_info[descriptor_index]; 175962306a36Sopenharmony_ci if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_ACTIVE)) 176062306a36Sopenharmony_ci goto done; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci descriptor_type = le32_to_cpu(descriptor->data0) & 176362306a36Sopenharmony_ci TX_DESC_DATA0_DTYPE_MASK_; 176462306a36Sopenharmony_ci if (descriptor_type == TX_DESC_DATA0_DTYPE_DATA_) 176562306a36Sopenharmony_ci goto clean_up_data_descriptor; 176662306a36Sopenharmony_ci else 176762306a36Sopenharmony_ci goto clear_active; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ciclean_up_data_descriptor: 177062306a36Sopenharmony_ci if (buffer_info->dma_ptr) { 177162306a36Sopenharmony_ci if (buffer_info->flags & 177262306a36Sopenharmony_ci TX_BUFFER_INFO_FLAG_SKB_FRAGMENT) { 177362306a36Sopenharmony_ci dma_unmap_page(&tx->adapter->pdev->dev, 177462306a36Sopenharmony_ci buffer_info->dma_ptr, 177562306a36Sopenharmony_ci buffer_info->buffer_length, 177662306a36Sopenharmony_ci DMA_TO_DEVICE); 177762306a36Sopenharmony_ci } else { 177862306a36Sopenharmony_ci dma_unmap_single(&tx->adapter->pdev->dev, 177962306a36Sopenharmony_ci buffer_info->dma_ptr, 178062306a36Sopenharmony_ci buffer_info->buffer_length, 178162306a36Sopenharmony_ci DMA_TO_DEVICE); 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci buffer_info->dma_ptr = 0; 178462306a36Sopenharmony_ci buffer_info->buffer_length = 0; 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci if (!buffer_info->skb) 178762306a36Sopenharmony_ci goto clear_active; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED)) { 179062306a36Sopenharmony_ci dev_kfree_skb_any(buffer_info->skb); 179162306a36Sopenharmony_ci goto clear_skb; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci if (cleanup) { 179562306a36Sopenharmony_ci lan743x_ptp_unrequest_tx_timestamp(tx->adapter); 179662306a36Sopenharmony_ci dev_kfree_skb_any(buffer_info->skb); 179762306a36Sopenharmony_ci } else { 179862306a36Sopenharmony_ci ignore_sync = (buffer_info->flags & 179962306a36Sopenharmony_ci TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0; 180062306a36Sopenharmony_ci lan743x_ptp_tx_timestamp_skb(tx->adapter, 180162306a36Sopenharmony_ci buffer_info->skb, ignore_sync); 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ciclear_skb: 180562306a36Sopenharmony_ci buffer_info->skb = NULL; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ciclear_active: 180862306a36Sopenharmony_ci buffer_info->flags &= ~TX_BUFFER_INFO_FLAG_ACTIVE; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cidone: 181162306a36Sopenharmony_ci memset(buffer_info, 0, sizeof(*buffer_info)); 181262306a36Sopenharmony_ci memset(descriptor, 0, sizeof(*descriptor)); 181362306a36Sopenharmony_ci} 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_cistatic int lan743x_tx_next_index(struct lan743x_tx *tx, int index) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci return ((++index) % tx->ring_size); 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic void lan743x_tx_release_completed_descriptors(struct lan743x_tx *tx) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci while (le32_to_cpu(*tx->head_cpu_ptr) != (tx->last_head)) { 182362306a36Sopenharmony_ci lan743x_tx_release_desc(tx, tx->last_head, false); 182462306a36Sopenharmony_ci tx->last_head = lan743x_tx_next_index(tx, tx->last_head); 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci} 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_cistatic void lan743x_tx_release_all_descriptors(struct lan743x_tx *tx) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci u32 original_head = 0; 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci original_head = tx->last_head; 183362306a36Sopenharmony_ci do { 183462306a36Sopenharmony_ci lan743x_tx_release_desc(tx, tx->last_head, true); 183562306a36Sopenharmony_ci tx->last_head = lan743x_tx_next_index(tx, tx->last_head); 183662306a36Sopenharmony_ci } while (tx->last_head != original_head); 183762306a36Sopenharmony_ci memset(tx->ring_cpu_ptr, 0, 183862306a36Sopenharmony_ci sizeof(*tx->ring_cpu_ptr) * (tx->ring_size)); 183962306a36Sopenharmony_ci memset(tx->buffer_info, 0, 184062306a36Sopenharmony_ci sizeof(*tx->buffer_info) * (tx->ring_size)); 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic int lan743x_tx_get_desc_cnt(struct lan743x_tx *tx, 184462306a36Sopenharmony_ci struct sk_buff *skb) 184562306a36Sopenharmony_ci{ 184662306a36Sopenharmony_ci int result = 1; /* 1 for the main skb buffer */ 184762306a36Sopenharmony_ci int nr_frags = 0; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci if (skb_is_gso(skb)) 185062306a36Sopenharmony_ci result++; /* requires an extension descriptor */ 185162306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 185262306a36Sopenharmony_ci result += nr_frags; /* 1 for each fragment buffer */ 185362306a36Sopenharmony_ci return result; 185462306a36Sopenharmony_ci} 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_cistatic int lan743x_tx_get_avail_desc(struct lan743x_tx *tx) 185762306a36Sopenharmony_ci{ 185862306a36Sopenharmony_ci int last_head = tx->last_head; 185962306a36Sopenharmony_ci int last_tail = tx->last_tail; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci if (last_tail >= last_head) 186262306a36Sopenharmony_ci return tx->ring_size - last_tail + last_head - 1; 186362306a36Sopenharmony_ci else 186462306a36Sopenharmony_ci return last_head - last_tail - 1; 186562306a36Sopenharmony_ci} 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_civoid lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx, 186862306a36Sopenharmony_ci bool enable_timestamping, 186962306a36Sopenharmony_ci bool enable_onestep_sync) 187062306a36Sopenharmony_ci{ 187162306a36Sopenharmony_ci if (enable_timestamping) 187262306a36Sopenharmony_ci tx->ts_flags |= TX_TS_FLAG_TIMESTAMPING_ENABLED; 187362306a36Sopenharmony_ci else 187462306a36Sopenharmony_ci tx->ts_flags &= ~TX_TS_FLAG_TIMESTAMPING_ENABLED; 187562306a36Sopenharmony_ci if (enable_onestep_sync) 187662306a36Sopenharmony_ci tx->ts_flags |= TX_TS_FLAG_ONE_STEP_SYNC; 187762306a36Sopenharmony_ci else 187862306a36Sopenharmony_ci tx->ts_flags &= ~TX_TS_FLAG_ONE_STEP_SYNC; 187962306a36Sopenharmony_ci} 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_cistatic int lan743x_tx_frame_start(struct lan743x_tx *tx, 188262306a36Sopenharmony_ci unsigned char *first_buffer, 188362306a36Sopenharmony_ci unsigned int first_buffer_length, 188462306a36Sopenharmony_ci unsigned int frame_length, 188562306a36Sopenharmony_ci bool time_stamp, 188662306a36Sopenharmony_ci bool check_sum) 188762306a36Sopenharmony_ci{ 188862306a36Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame. 188962306a36Sopenharmony_ci * assuming tx->ring_lock has already been acquired. 189062306a36Sopenharmony_ci */ 189162306a36Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 189262306a36Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 189362306a36Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 189462306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 189562306a36Sopenharmony_ci dma_addr_t dma_ptr; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci tx->frame_flags |= TX_FRAME_FLAG_IN_PROGRESS; 189862306a36Sopenharmony_ci tx->frame_first = tx->last_tail; 189962306a36Sopenharmony_ci tx->frame_tail = tx->frame_first; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 190262306a36Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 190362306a36Sopenharmony_ci dma_ptr = dma_map_single(dev, first_buffer, first_buffer_length, 190462306a36Sopenharmony_ci DMA_TO_DEVICE); 190562306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_ptr)) 190662306a36Sopenharmony_ci return -ENOMEM; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr)); 190962306a36Sopenharmony_ci tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr)); 191062306a36Sopenharmony_ci tx_descriptor->data3 = cpu_to_le32((frame_length << 16) & 191162306a36Sopenharmony_ci TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci buffer_info->skb = NULL; 191462306a36Sopenharmony_ci buffer_info->dma_ptr = dma_ptr; 191562306a36Sopenharmony_ci buffer_info->buffer_length = first_buffer_length; 191662306a36Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci tx->frame_data0 = (first_buffer_length & 191962306a36Sopenharmony_ci TX_DESC_DATA0_BUF_LENGTH_MASK_) | 192062306a36Sopenharmony_ci TX_DESC_DATA0_DTYPE_DATA_ | 192162306a36Sopenharmony_ci TX_DESC_DATA0_FS_ | 192262306a36Sopenharmony_ci TX_DESC_DATA0_FCS_; 192362306a36Sopenharmony_ci if (time_stamp) 192462306a36Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_TSE_; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci if (check_sum) 192762306a36Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_ICE_ | 192862306a36Sopenharmony_ci TX_DESC_DATA0_IPE_ | 192962306a36Sopenharmony_ci TX_DESC_DATA0_TPE_; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci /* data0 will be programmed in one of other frame assembler functions */ 193262306a36Sopenharmony_ci return 0; 193362306a36Sopenharmony_ci} 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_cistatic void lan743x_tx_frame_add_lso(struct lan743x_tx *tx, 193662306a36Sopenharmony_ci unsigned int frame_length, 193762306a36Sopenharmony_ci int nr_frags) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame. 194062306a36Sopenharmony_ci * assuming tx->ring_lock has already been acquired. 194162306a36Sopenharmony_ci */ 194262306a36Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 194362306a36Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /* wrap up previous descriptor */ 194662306a36Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_EXT_; 194762306a36Sopenharmony_ci if (nr_frags <= 0) { 194862306a36Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_LS_; 194962306a36Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_IOC_; 195062306a36Sopenharmony_ci } 195162306a36Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 195262306a36Sopenharmony_ci tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci /* move to next descriptor */ 195562306a36Sopenharmony_ci tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); 195662306a36Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 195762306a36Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci /* add extension descriptor */ 196062306a36Sopenharmony_ci tx_descriptor->data1 = 0; 196162306a36Sopenharmony_ci tx_descriptor->data2 = 0; 196262306a36Sopenharmony_ci tx_descriptor->data3 = 0; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci buffer_info->skb = NULL; 196562306a36Sopenharmony_ci buffer_info->dma_ptr = 0; 196662306a36Sopenharmony_ci buffer_info->buffer_length = 0; 196762306a36Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci tx->frame_data0 = (frame_length & TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_) | 197062306a36Sopenharmony_ci TX_DESC_DATA0_DTYPE_EXT_ | 197162306a36Sopenharmony_ci TX_DESC_DATA0_EXT_LSO_; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci /* data0 will be programmed in one of other frame assembler functions */ 197462306a36Sopenharmony_ci} 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_cistatic int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx, 197762306a36Sopenharmony_ci const skb_frag_t *fragment, 197862306a36Sopenharmony_ci unsigned int frame_length) 197962306a36Sopenharmony_ci{ 198062306a36Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame 198162306a36Sopenharmony_ci * assuming tx->ring_lock has already been acquired 198262306a36Sopenharmony_ci */ 198362306a36Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 198462306a36Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 198562306a36Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 198662306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 198762306a36Sopenharmony_ci unsigned int fragment_length = 0; 198862306a36Sopenharmony_ci dma_addr_t dma_ptr; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci fragment_length = skb_frag_size(fragment); 199162306a36Sopenharmony_ci if (!fragment_length) 199262306a36Sopenharmony_ci return 0; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci /* wrap up previous descriptor */ 199562306a36Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 199662306a36Sopenharmony_ci tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci /* move to next descriptor */ 199962306a36Sopenharmony_ci tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); 200062306a36Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 200162306a36Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 200262306a36Sopenharmony_ci dma_ptr = skb_frag_dma_map(dev, fragment, 200362306a36Sopenharmony_ci 0, fragment_length, 200462306a36Sopenharmony_ci DMA_TO_DEVICE); 200562306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_ptr)) { 200662306a36Sopenharmony_ci int desc_index; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci /* cleanup all previously setup descriptors */ 200962306a36Sopenharmony_ci desc_index = tx->frame_first; 201062306a36Sopenharmony_ci while (desc_index != tx->frame_tail) { 201162306a36Sopenharmony_ci lan743x_tx_release_desc(tx, desc_index, true); 201262306a36Sopenharmony_ci desc_index = lan743x_tx_next_index(tx, desc_index); 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci dma_wmb(); 201562306a36Sopenharmony_ci tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS; 201662306a36Sopenharmony_ci tx->frame_first = 0; 201762306a36Sopenharmony_ci tx->frame_data0 = 0; 201862306a36Sopenharmony_ci tx->frame_tail = 0; 201962306a36Sopenharmony_ci return -ENOMEM; 202062306a36Sopenharmony_ci } 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr)); 202362306a36Sopenharmony_ci tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr)); 202462306a36Sopenharmony_ci tx_descriptor->data3 = cpu_to_le32((frame_length << 16) & 202562306a36Sopenharmony_ci TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_); 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci buffer_info->skb = NULL; 202862306a36Sopenharmony_ci buffer_info->dma_ptr = dma_ptr; 202962306a36Sopenharmony_ci buffer_info->buffer_length = fragment_length; 203062306a36Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE; 203162306a36Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_SKB_FRAGMENT; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci tx->frame_data0 = (fragment_length & TX_DESC_DATA0_BUF_LENGTH_MASK_) | 203462306a36Sopenharmony_ci TX_DESC_DATA0_DTYPE_DATA_ | 203562306a36Sopenharmony_ci TX_DESC_DATA0_FCS_; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci /* data0 will be programmed in one of other frame assembler functions */ 203862306a36Sopenharmony_ci return 0; 203962306a36Sopenharmony_ci} 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_cistatic void lan743x_tx_frame_end(struct lan743x_tx *tx, 204262306a36Sopenharmony_ci struct sk_buff *skb, 204362306a36Sopenharmony_ci bool time_stamp, 204462306a36Sopenharmony_ci bool ignore_sync) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame 204762306a36Sopenharmony_ci * assuming tx->ring_lock has already been acquired 204862306a36Sopenharmony_ci */ 204962306a36Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 205062306a36Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 205162306a36Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 205262306a36Sopenharmony_ci u32 tx_tail_flags = 0; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci /* wrap up previous descriptor */ 205562306a36Sopenharmony_ci if ((tx->frame_data0 & TX_DESC_DATA0_DTYPE_MASK_) == 205662306a36Sopenharmony_ci TX_DESC_DATA0_DTYPE_DATA_) { 205762306a36Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_LS_; 205862306a36Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_IOC_; 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 206262306a36Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 206362306a36Sopenharmony_ci buffer_info->skb = skb; 206462306a36Sopenharmony_ci if (time_stamp) 206562306a36Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED; 206662306a36Sopenharmony_ci if (ignore_sync) 206762306a36Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); 207062306a36Sopenharmony_ci tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); 207162306a36Sopenharmony_ci tx->last_tail = tx->frame_tail; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci dma_wmb(); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET) 207662306a36Sopenharmony_ci tx_tail_flags |= TX_TAIL_SET_TOP_INT_VEC_EN_; 207762306a36Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET) 207862306a36Sopenharmony_ci tx_tail_flags |= TX_TAIL_SET_DMAC_INT_EN_ | 207962306a36Sopenharmony_ci TX_TAIL_SET_TOP_INT_EN_; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci lan743x_csr_write(adapter, TX_TAIL(tx->channel_number), 208262306a36Sopenharmony_ci tx_tail_flags | tx->frame_tail); 208362306a36Sopenharmony_ci tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS; 208462306a36Sopenharmony_ci} 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_cistatic netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx, 208762306a36Sopenharmony_ci struct sk_buff *skb) 208862306a36Sopenharmony_ci{ 208962306a36Sopenharmony_ci int required_number_of_descriptors = 0; 209062306a36Sopenharmony_ci unsigned int start_frame_length = 0; 209162306a36Sopenharmony_ci netdev_tx_t retval = NETDEV_TX_OK; 209262306a36Sopenharmony_ci unsigned int frame_length = 0; 209362306a36Sopenharmony_ci unsigned int head_length = 0; 209462306a36Sopenharmony_ci unsigned long irq_flags = 0; 209562306a36Sopenharmony_ci bool do_timestamp = false; 209662306a36Sopenharmony_ci bool ignore_sync = false; 209762306a36Sopenharmony_ci struct netdev_queue *txq; 209862306a36Sopenharmony_ci int nr_frags = 0; 209962306a36Sopenharmony_ci bool gso = false; 210062306a36Sopenharmony_ci int j; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci required_number_of_descriptors = lan743x_tx_get_desc_cnt(tx, skb); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci spin_lock_irqsave(&tx->ring_lock, irq_flags); 210562306a36Sopenharmony_ci if (required_number_of_descriptors > 210662306a36Sopenharmony_ci lan743x_tx_get_avail_desc(tx)) { 210762306a36Sopenharmony_ci if (required_number_of_descriptors > (tx->ring_size - 1)) { 210862306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 210962306a36Sopenharmony_ci } else { 211062306a36Sopenharmony_ci /* save how many descriptors we needed to restart the queue */ 211162306a36Sopenharmony_ci tx->rqd_descriptors = required_number_of_descriptors; 211262306a36Sopenharmony_ci retval = NETDEV_TX_BUSY; 211362306a36Sopenharmony_ci txq = netdev_get_tx_queue(tx->adapter->netdev, 211462306a36Sopenharmony_ci tx->channel_number); 211562306a36Sopenharmony_ci netif_tx_stop_queue(txq); 211662306a36Sopenharmony_ci } 211762306a36Sopenharmony_ci goto unlock; 211862306a36Sopenharmony_ci } 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci /* space available, transmit skb */ 212162306a36Sopenharmony_ci if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && 212262306a36Sopenharmony_ci (tx->ts_flags & TX_TS_FLAG_TIMESTAMPING_ENABLED) && 212362306a36Sopenharmony_ci (lan743x_ptp_request_tx_timestamp(tx->adapter))) { 212462306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 212562306a36Sopenharmony_ci do_timestamp = true; 212662306a36Sopenharmony_ci if (tx->ts_flags & TX_TS_FLAG_ONE_STEP_SYNC) 212762306a36Sopenharmony_ci ignore_sync = true; 212862306a36Sopenharmony_ci } 212962306a36Sopenharmony_ci head_length = skb_headlen(skb); 213062306a36Sopenharmony_ci frame_length = skb_pagelen(skb); 213162306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 213262306a36Sopenharmony_ci start_frame_length = frame_length; 213362306a36Sopenharmony_ci gso = skb_is_gso(skb); 213462306a36Sopenharmony_ci if (gso) { 213562306a36Sopenharmony_ci start_frame_length = max(skb_shinfo(skb)->gso_size, 213662306a36Sopenharmony_ci (unsigned short)8); 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (lan743x_tx_frame_start(tx, 214062306a36Sopenharmony_ci skb->data, head_length, 214162306a36Sopenharmony_ci start_frame_length, 214262306a36Sopenharmony_ci do_timestamp, 214362306a36Sopenharmony_ci skb->ip_summed == CHECKSUM_PARTIAL)) { 214462306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 214562306a36Sopenharmony_ci goto unlock; 214662306a36Sopenharmony_ci } 214762306a36Sopenharmony_ci tx->frame_count++; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci if (gso) 215062306a36Sopenharmony_ci lan743x_tx_frame_add_lso(tx, frame_length, nr_frags); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci if (nr_frags <= 0) 215362306a36Sopenharmony_ci goto finish; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci for (j = 0; j < nr_frags; j++) { 215662306a36Sopenharmony_ci const skb_frag_t *frag = &(skb_shinfo(skb)->frags[j]); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci if (lan743x_tx_frame_add_fragment(tx, frag, frame_length)) { 215962306a36Sopenharmony_ci /* upon error no need to call 216062306a36Sopenharmony_ci * lan743x_tx_frame_end 216162306a36Sopenharmony_ci * frame assembler clean up was performed inside 216262306a36Sopenharmony_ci * lan743x_tx_frame_add_fragment 216362306a36Sopenharmony_ci */ 216462306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 216562306a36Sopenharmony_ci goto unlock; 216662306a36Sopenharmony_ci } 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_cifinish: 217062306a36Sopenharmony_ci lan743x_tx_frame_end(tx, skb, do_timestamp, ignore_sync); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ciunlock: 217362306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->ring_lock, irq_flags); 217462306a36Sopenharmony_ci return retval; 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_cistatic int lan743x_tx_napi_poll(struct napi_struct *napi, int weight) 217862306a36Sopenharmony_ci{ 217962306a36Sopenharmony_ci struct lan743x_tx *tx = container_of(napi, struct lan743x_tx, napi); 218062306a36Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 218162306a36Sopenharmony_ci unsigned long irq_flags = 0; 218262306a36Sopenharmony_ci struct netdev_queue *txq; 218362306a36Sopenharmony_ci u32 ioc_bit = 0; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number); 218662306a36Sopenharmony_ci lan743x_csr_read(adapter, DMAC_INT_STS); 218762306a36Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C) 218862306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_STS, ioc_bit); 218962306a36Sopenharmony_ci spin_lock_irqsave(&tx->ring_lock, irq_flags); 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci /* clean up tx ring */ 219262306a36Sopenharmony_ci lan743x_tx_release_completed_descriptors(tx); 219362306a36Sopenharmony_ci txq = netdev_get_tx_queue(adapter->netdev, tx->channel_number); 219462306a36Sopenharmony_ci if (netif_tx_queue_stopped(txq)) { 219562306a36Sopenharmony_ci if (tx->rqd_descriptors) { 219662306a36Sopenharmony_ci if (tx->rqd_descriptors <= 219762306a36Sopenharmony_ci lan743x_tx_get_avail_desc(tx)) { 219862306a36Sopenharmony_ci tx->rqd_descriptors = 0; 219962306a36Sopenharmony_ci netif_tx_wake_queue(txq); 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci } else { 220262306a36Sopenharmony_ci netif_tx_wake_queue(txq); 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci } 220562306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->ring_lock, irq_flags); 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci if (!napi_complete(napi)) 220862306a36Sopenharmony_ci goto done; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci /* enable isr */ 221162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 221262306a36Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 221362306a36Sopenharmony_ci lan743x_csr_read(adapter, INT_STS); 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_cidone: 221662306a36Sopenharmony_ci return 0; 221762306a36Sopenharmony_ci} 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_cistatic void lan743x_tx_ring_cleanup(struct lan743x_tx *tx) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci if (tx->head_cpu_ptr) { 222262306a36Sopenharmony_ci dma_free_coherent(&tx->adapter->pdev->dev, 222362306a36Sopenharmony_ci sizeof(*tx->head_cpu_ptr), tx->head_cpu_ptr, 222462306a36Sopenharmony_ci tx->head_dma_ptr); 222562306a36Sopenharmony_ci tx->head_cpu_ptr = NULL; 222662306a36Sopenharmony_ci tx->head_dma_ptr = 0; 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci kfree(tx->buffer_info); 222962306a36Sopenharmony_ci tx->buffer_info = NULL; 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci if (tx->ring_cpu_ptr) { 223262306a36Sopenharmony_ci dma_free_coherent(&tx->adapter->pdev->dev, 223362306a36Sopenharmony_ci tx->ring_allocation_size, tx->ring_cpu_ptr, 223462306a36Sopenharmony_ci tx->ring_dma_ptr); 223562306a36Sopenharmony_ci tx->ring_allocation_size = 0; 223662306a36Sopenharmony_ci tx->ring_cpu_ptr = NULL; 223762306a36Sopenharmony_ci tx->ring_dma_ptr = 0; 223862306a36Sopenharmony_ci } 223962306a36Sopenharmony_ci tx->ring_size = 0; 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_cistatic int lan743x_tx_ring_init(struct lan743x_tx *tx) 224362306a36Sopenharmony_ci{ 224462306a36Sopenharmony_ci size_t ring_allocation_size = 0; 224562306a36Sopenharmony_ci void *cpu_ptr = NULL; 224662306a36Sopenharmony_ci dma_addr_t dma_ptr; 224762306a36Sopenharmony_ci int ret = -ENOMEM; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci tx->ring_size = LAN743X_TX_RING_SIZE; 225062306a36Sopenharmony_ci if (tx->ring_size & ~TX_CFG_B_TX_RING_LEN_MASK_) { 225162306a36Sopenharmony_ci ret = -EINVAL; 225262306a36Sopenharmony_ci goto cleanup; 225362306a36Sopenharmony_ci } 225462306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&tx->adapter->pdev->dev, 225562306a36Sopenharmony_ci DMA_BIT_MASK(64))) { 225662306a36Sopenharmony_ci dev_warn(&tx->adapter->pdev->dev, 225762306a36Sopenharmony_ci "lan743x_: No suitable DMA available\n"); 225862306a36Sopenharmony_ci ret = -ENOMEM; 225962306a36Sopenharmony_ci goto cleanup; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci ring_allocation_size = ALIGN(tx->ring_size * 226262306a36Sopenharmony_ci sizeof(struct lan743x_tx_descriptor), 226362306a36Sopenharmony_ci PAGE_SIZE); 226462306a36Sopenharmony_ci dma_ptr = 0; 226562306a36Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev, 226662306a36Sopenharmony_ci ring_allocation_size, &dma_ptr, GFP_KERNEL); 226762306a36Sopenharmony_ci if (!cpu_ptr) { 226862306a36Sopenharmony_ci ret = -ENOMEM; 226962306a36Sopenharmony_ci goto cleanup; 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci tx->ring_allocation_size = ring_allocation_size; 227362306a36Sopenharmony_ci tx->ring_cpu_ptr = (struct lan743x_tx_descriptor *)cpu_ptr; 227462306a36Sopenharmony_ci tx->ring_dma_ptr = dma_ptr; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci cpu_ptr = kcalloc(tx->ring_size, sizeof(*tx->buffer_info), GFP_KERNEL); 227762306a36Sopenharmony_ci if (!cpu_ptr) { 227862306a36Sopenharmony_ci ret = -ENOMEM; 227962306a36Sopenharmony_ci goto cleanup; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci tx->buffer_info = (struct lan743x_tx_buffer_info *)cpu_ptr; 228262306a36Sopenharmony_ci dma_ptr = 0; 228362306a36Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev, 228462306a36Sopenharmony_ci sizeof(*tx->head_cpu_ptr), &dma_ptr, 228562306a36Sopenharmony_ci GFP_KERNEL); 228662306a36Sopenharmony_ci if (!cpu_ptr) { 228762306a36Sopenharmony_ci ret = -ENOMEM; 228862306a36Sopenharmony_ci goto cleanup; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci tx->head_cpu_ptr = cpu_ptr; 229262306a36Sopenharmony_ci tx->head_dma_ptr = dma_ptr; 229362306a36Sopenharmony_ci if (tx->head_dma_ptr & 0x3) { 229462306a36Sopenharmony_ci ret = -ENOMEM; 229562306a36Sopenharmony_ci goto cleanup; 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci return 0; 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_cicleanup: 230162306a36Sopenharmony_ci lan743x_tx_ring_cleanup(tx); 230262306a36Sopenharmony_ci return ret; 230362306a36Sopenharmony_ci} 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_cistatic void lan743x_tx_close(struct lan743x_tx *tx) 230662306a36Sopenharmony_ci{ 230762306a36Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci lan743x_csr_write(adapter, 231062306a36Sopenharmony_ci DMAC_CMD, 231162306a36Sopenharmony_ci DMAC_CMD_STOP_T_(tx->channel_number)); 231262306a36Sopenharmony_ci lan743x_dmac_tx_wait_till_stopped(adapter, tx->channel_number); 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci lan743x_csr_write(adapter, 231562306a36Sopenharmony_ci DMAC_INT_EN_CLR, 231662306a36Sopenharmony_ci DMAC_INT_BIT_TX_IOC_(tx->channel_number)); 231762306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 231862306a36Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 231962306a36Sopenharmony_ci napi_disable(&tx->napi); 232062306a36Sopenharmony_ci netif_napi_del(&tx->napi); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci lan743x_csr_write(adapter, FCT_TX_CTL, 232362306a36Sopenharmony_ci FCT_TX_CTL_DIS_(tx->channel_number)); 232462306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL, 232562306a36Sopenharmony_ci FCT_TX_CTL_EN_(tx->channel_number), 232662306a36Sopenharmony_ci 0, 1000, 20000, 100); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci lan743x_tx_release_all_descriptors(tx); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci tx->rqd_descriptors = 0; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci lan743x_tx_ring_cleanup(tx); 233362306a36Sopenharmony_ci} 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_cistatic int lan743x_tx_open(struct lan743x_tx *tx) 233662306a36Sopenharmony_ci{ 233762306a36Sopenharmony_ci struct lan743x_adapter *adapter = NULL; 233862306a36Sopenharmony_ci u32 data = 0; 233962306a36Sopenharmony_ci int ret; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci adapter = tx->adapter; 234262306a36Sopenharmony_ci ret = lan743x_tx_ring_init(tx); 234362306a36Sopenharmony_ci if (ret) 234462306a36Sopenharmony_ci return ret; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci /* initialize fifo */ 234762306a36Sopenharmony_ci lan743x_csr_write(adapter, FCT_TX_CTL, 234862306a36Sopenharmony_ci FCT_TX_CTL_RESET_(tx->channel_number)); 234962306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL, 235062306a36Sopenharmony_ci FCT_TX_CTL_RESET_(tx->channel_number), 235162306a36Sopenharmony_ci 0, 1000, 20000, 100); 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci /* enable fifo */ 235462306a36Sopenharmony_ci lan743x_csr_write(adapter, FCT_TX_CTL, 235562306a36Sopenharmony_ci FCT_TX_CTL_EN_(tx->channel_number)); 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci /* reset tx channel */ 235862306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 235962306a36Sopenharmony_ci DMAC_CMD_TX_SWR_(tx->channel_number)); 236062306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, DMAC_CMD, 236162306a36Sopenharmony_ci DMAC_CMD_TX_SWR_(tx->channel_number), 236262306a36Sopenharmony_ci 0, 1000, 20000, 100); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci /* Write TX_BASE_ADDR */ 236562306a36Sopenharmony_ci lan743x_csr_write(adapter, 236662306a36Sopenharmony_ci TX_BASE_ADDRH(tx->channel_number), 236762306a36Sopenharmony_ci DMA_ADDR_HIGH32(tx->ring_dma_ptr)); 236862306a36Sopenharmony_ci lan743x_csr_write(adapter, 236962306a36Sopenharmony_ci TX_BASE_ADDRL(tx->channel_number), 237062306a36Sopenharmony_ci DMA_ADDR_LOW32(tx->ring_dma_ptr)); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci /* Write TX_CFG_B */ 237362306a36Sopenharmony_ci data = lan743x_csr_read(adapter, TX_CFG_B(tx->channel_number)); 237462306a36Sopenharmony_ci data &= ~TX_CFG_B_TX_RING_LEN_MASK_; 237562306a36Sopenharmony_ci data |= ((tx->ring_size) & TX_CFG_B_TX_RING_LEN_MASK_); 237662306a36Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) 237762306a36Sopenharmony_ci data |= TX_CFG_B_TDMABL_512_; 237862306a36Sopenharmony_ci lan743x_csr_write(adapter, TX_CFG_B(tx->channel_number), data); 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci /* Write TX_CFG_A */ 238162306a36Sopenharmony_ci data = TX_CFG_A_TX_TMR_HPWB_SEL_IOC_ | TX_CFG_A_TX_HP_WB_EN_; 238262306a36Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 238362306a36Sopenharmony_ci data |= TX_CFG_A_TX_HP_WB_ON_INT_TMR_; 238462306a36Sopenharmony_ci data |= TX_CFG_A_TX_PF_THRES_SET_(0x10); 238562306a36Sopenharmony_ci data |= TX_CFG_A_TX_PF_PRI_THRES_SET_(0x04); 238662306a36Sopenharmony_ci data |= TX_CFG_A_TX_HP_WB_THRES_SET_(0x07); 238762306a36Sopenharmony_ci } 238862306a36Sopenharmony_ci lan743x_csr_write(adapter, TX_CFG_A(tx->channel_number), data); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci /* Write TX_HEAD_WRITEBACK_ADDR */ 239162306a36Sopenharmony_ci lan743x_csr_write(adapter, 239262306a36Sopenharmony_ci TX_HEAD_WRITEBACK_ADDRH(tx->channel_number), 239362306a36Sopenharmony_ci DMA_ADDR_HIGH32(tx->head_dma_ptr)); 239462306a36Sopenharmony_ci lan743x_csr_write(adapter, 239562306a36Sopenharmony_ci TX_HEAD_WRITEBACK_ADDRL(tx->channel_number), 239662306a36Sopenharmony_ci DMA_ADDR_LOW32(tx->head_dma_ptr)); 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci /* set last head */ 239962306a36Sopenharmony_ci tx->last_head = lan743x_csr_read(adapter, TX_HEAD(tx->channel_number)); 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci /* write TX_TAIL */ 240262306a36Sopenharmony_ci tx->last_tail = 0; 240362306a36Sopenharmony_ci lan743x_csr_write(adapter, TX_TAIL(tx->channel_number), 240462306a36Sopenharmony_ci (u32)(tx->last_tail)); 240562306a36Sopenharmony_ci tx->vector_flags = lan743x_intr_get_vector_flags(adapter, 240662306a36Sopenharmony_ci INT_BIT_DMA_TX_ 240762306a36Sopenharmony_ci (tx->channel_number)); 240862306a36Sopenharmony_ci netif_napi_add_tx_weight(adapter->netdev, 240962306a36Sopenharmony_ci &tx->napi, lan743x_tx_napi_poll, 241062306a36Sopenharmony_ci NAPI_POLL_WEIGHT); 241162306a36Sopenharmony_ci napi_enable(&tx->napi); 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci data = 0; 241462306a36Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR) 241562306a36Sopenharmony_ci data |= TX_CFG_C_TX_TOP_INT_EN_AUTO_CLR_; 241662306a36Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR) 241762306a36Sopenharmony_ci data |= TX_CFG_C_TX_DMA_INT_STS_AUTO_CLR_; 241862306a36Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C) 241962306a36Sopenharmony_ci data |= TX_CFG_C_TX_INT_STS_R2C_MODE_MASK_; 242062306a36Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C) 242162306a36Sopenharmony_ci data |= TX_CFG_C_TX_INT_EN_R2C_; 242262306a36Sopenharmony_ci lan743x_csr_write(adapter, TX_CFG_C(tx->channel_number), data); 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci if (!(tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET)) 242562306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 242662306a36Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 242762306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_EN_SET, 242862306a36Sopenharmony_ci DMAC_INT_BIT_TX_IOC_(tx->channel_number)); 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci /* start dmac channel */ 243162306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 243262306a36Sopenharmony_ci DMAC_CMD_START_T_(tx->channel_number)); 243362306a36Sopenharmony_ci return 0; 243462306a36Sopenharmony_ci} 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_cistatic int lan743x_rx_next_index(struct lan743x_rx *rx, int index) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci return ((++index) % rx->ring_size); 243962306a36Sopenharmony_ci} 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_cistatic void lan743x_rx_update_tail(struct lan743x_rx *rx, int index) 244262306a36Sopenharmony_ci{ 244362306a36Sopenharmony_ci /* update the tail once per 8 descriptors */ 244462306a36Sopenharmony_ci if ((index & 7) == 7) 244562306a36Sopenharmony_ci lan743x_csr_write(rx->adapter, RX_TAIL(rx->channel_number), 244662306a36Sopenharmony_ci index); 244762306a36Sopenharmony_ci} 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_cistatic int lan743x_rx_init_ring_element(struct lan743x_rx *rx, int index, 245062306a36Sopenharmony_ci gfp_t gfp) 245162306a36Sopenharmony_ci{ 245262306a36Sopenharmony_ci struct net_device *netdev = rx->adapter->netdev; 245362306a36Sopenharmony_ci struct device *dev = &rx->adapter->pdev->dev; 245462306a36Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 245562306a36Sopenharmony_ci unsigned int buffer_length, used_length; 245662306a36Sopenharmony_ci struct lan743x_rx_descriptor *descriptor; 245762306a36Sopenharmony_ci struct sk_buff *skb; 245862306a36Sopenharmony_ci dma_addr_t dma_ptr; 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci buffer_length = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + RX_HEAD_PADDING; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 246362306a36Sopenharmony_ci buffer_info = &rx->buffer_info[index]; 246462306a36Sopenharmony_ci skb = __netdev_alloc_skb(netdev, buffer_length, gfp); 246562306a36Sopenharmony_ci if (!skb) 246662306a36Sopenharmony_ci return -ENOMEM; 246762306a36Sopenharmony_ci dma_ptr = dma_map_single(dev, skb->data, buffer_length, DMA_FROM_DEVICE); 246862306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_ptr)) { 246962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 247062306a36Sopenharmony_ci return -ENOMEM; 247162306a36Sopenharmony_ci } 247262306a36Sopenharmony_ci if (buffer_info->dma_ptr) { 247362306a36Sopenharmony_ci /* sync used area of buffer only */ 247462306a36Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_) 247562306a36Sopenharmony_ci /* frame length is valid only if LS bit is set. 247662306a36Sopenharmony_ci * it's a safe upper bound for the used area in this 247762306a36Sopenharmony_ci * buffer. 247862306a36Sopenharmony_ci */ 247962306a36Sopenharmony_ci used_length = min(RX_DESC_DATA0_FRAME_LENGTH_GET_ 248062306a36Sopenharmony_ci (le32_to_cpu(descriptor->data0)), 248162306a36Sopenharmony_ci buffer_info->buffer_length); 248262306a36Sopenharmony_ci else 248362306a36Sopenharmony_ci used_length = buffer_info->buffer_length; 248462306a36Sopenharmony_ci dma_sync_single_for_cpu(dev, buffer_info->dma_ptr, 248562306a36Sopenharmony_ci used_length, 248662306a36Sopenharmony_ci DMA_FROM_DEVICE); 248762306a36Sopenharmony_ci dma_unmap_single_attrs(dev, buffer_info->dma_ptr, 248862306a36Sopenharmony_ci buffer_info->buffer_length, 248962306a36Sopenharmony_ci DMA_FROM_DEVICE, 249062306a36Sopenharmony_ci DMA_ATTR_SKIP_CPU_SYNC); 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci buffer_info->skb = skb; 249462306a36Sopenharmony_ci buffer_info->dma_ptr = dma_ptr; 249562306a36Sopenharmony_ci buffer_info->buffer_length = buffer_length; 249662306a36Sopenharmony_ci descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr)); 249762306a36Sopenharmony_ci descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr)); 249862306a36Sopenharmony_ci descriptor->data3 = 0; 249962306a36Sopenharmony_ci descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ | 250062306a36Sopenharmony_ci (buffer_length & RX_DESC_DATA0_BUF_LENGTH_MASK_))); 250162306a36Sopenharmony_ci lan743x_rx_update_tail(rx, index); 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci return 0; 250462306a36Sopenharmony_ci} 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_cistatic void lan743x_rx_reuse_ring_element(struct lan743x_rx *rx, int index) 250762306a36Sopenharmony_ci{ 250862306a36Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 250962306a36Sopenharmony_ci struct lan743x_rx_descriptor *descriptor; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 251262306a36Sopenharmony_ci buffer_info = &rx->buffer_info[index]; 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr)); 251562306a36Sopenharmony_ci descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr)); 251662306a36Sopenharmony_ci descriptor->data3 = 0; 251762306a36Sopenharmony_ci descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ | 251862306a36Sopenharmony_ci ((buffer_info->buffer_length) & 251962306a36Sopenharmony_ci RX_DESC_DATA0_BUF_LENGTH_MASK_))); 252062306a36Sopenharmony_ci lan743x_rx_update_tail(rx, index); 252162306a36Sopenharmony_ci} 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_cistatic void lan743x_rx_release_ring_element(struct lan743x_rx *rx, int index) 252462306a36Sopenharmony_ci{ 252562306a36Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 252662306a36Sopenharmony_ci struct lan743x_rx_descriptor *descriptor; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 252962306a36Sopenharmony_ci buffer_info = &rx->buffer_info[index]; 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci memset(descriptor, 0, sizeof(*descriptor)); 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci if (buffer_info->dma_ptr) { 253462306a36Sopenharmony_ci dma_unmap_single(&rx->adapter->pdev->dev, 253562306a36Sopenharmony_ci buffer_info->dma_ptr, 253662306a36Sopenharmony_ci buffer_info->buffer_length, 253762306a36Sopenharmony_ci DMA_FROM_DEVICE); 253862306a36Sopenharmony_ci buffer_info->dma_ptr = 0; 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci if (buffer_info->skb) { 254262306a36Sopenharmony_ci dev_kfree_skb(buffer_info->skb); 254362306a36Sopenharmony_ci buffer_info->skb = NULL; 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci memset(buffer_info, 0, sizeof(*buffer_info)); 254762306a36Sopenharmony_ci} 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_cistatic struct sk_buff * 255062306a36Sopenharmony_cilan743x_rx_trim_skb(struct sk_buff *skb, int frame_length) 255162306a36Sopenharmony_ci{ 255262306a36Sopenharmony_ci if (skb_linearize(skb)) { 255362306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 255462306a36Sopenharmony_ci return NULL; 255562306a36Sopenharmony_ci } 255662306a36Sopenharmony_ci frame_length = max_t(int, 0, frame_length - ETH_FCS_LEN); 255762306a36Sopenharmony_ci if (skb->len > frame_length) { 255862306a36Sopenharmony_ci skb->tail -= skb->len - frame_length; 255962306a36Sopenharmony_ci skb->len = frame_length; 256062306a36Sopenharmony_ci } 256162306a36Sopenharmony_ci return skb; 256262306a36Sopenharmony_ci} 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_cistatic int lan743x_rx_process_buffer(struct lan743x_rx *rx) 256562306a36Sopenharmony_ci{ 256662306a36Sopenharmony_ci int current_head_index = le32_to_cpu(*rx->head_cpu_ptr); 256762306a36Sopenharmony_ci struct lan743x_rx_descriptor *descriptor, *desc_ext; 256862306a36Sopenharmony_ci struct net_device *netdev = rx->adapter->netdev; 256962306a36Sopenharmony_ci int result = RX_PROCESS_RESULT_NOTHING_TO_DO; 257062306a36Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 257162306a36Sopenharmony_ci int frame_length, buffer_length; 257262306a36Sopenharmony_ci bool is_ice, is_tce, is_icsm; 257362306a36Sopenharmony_ci int extension_index = -1; 257462306a36Sopenharmony_ci bool is_last, is_first; 257562306a36Sopenharmony_ci struct sk_buff *skb; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci if (current_head_index < 0 || current_head_index >= rx->ring_size) 257862306a36Sopenharmony_ci goto done; 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci if (rx->last_head < 0 || rx->last_head >= rx->ring_size) 258162306a36Sopenharmony_ci goto done; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci if (rx->last_head == current_head_index) 258462306a36Sopenharmony_ci goto done; 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[rx->last_head]; 258762306a36Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_OWN_) 258862306a36Sopenharmony_ci goto done; 258962306a36Sopenharmony_ci buffer_info = &rx->buffer_info[rx->last_head]; 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci is_last = le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_; 259262306a36Sopenharmony_ci is_first = le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_FS_; 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci if (is_last && le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_EXT_) { 259562306a36Sopenharmony_ci /* extension is expected to follow */ 259662306a36Sopenharmony_ci int index = lan743x_rx_next_index(rx, rx->last_head); 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci if (index == current_head_index) 259962306a36Sopenharmony_ci /* extension not yet available */ 260062306a36Sopenharmony_ci goto done; 260162306a36Sopenharmony_ci desc_ext = &rx->ring_cpu_ptr[index]; 260262306a36Sopenharmony_ci if (le32_to_cpu(desc_ext->data0) & RX_DESC_DATA0_OWN_) 260362306a36Sopenharmony_ci /* extension not yet available */ 260462306a36Sopenharmony_ci goto done; 260562306a36Sopenharmony_ci if (!(le32_to_cpu(desc_ext->data0) & RX_DESC_DATA0_EXT_)) 260662306a36Sopenharmony_ci goto move_forward; 260762306a36Sopenharmony_ci extension_index = index; 260862306a36Sopenharmony_ci } 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci /* Only the last buffer in a multi-buffer frame contains the total frame 261162306a36Sopenharmony_ci * length. The chip occasionally sends more buffers than strictly 261262306a36Sopenharmony_ci * required to reach the total frame length. 261362306a36Sopenharmony_ci * Handle this by adding all buffers to the skb in their entirety. 261462306a36Sopenharmony_ci * Once the real frame length is known, trim the skb. 261562306a36Sopenharmony_ci */ 261662306a36Sopenharmony_ci frame_length = 261762306a36Sopenharmony_ci RX_DESC_DATA0_FRAME_LENGTH_GET_(le32_to_cpu(descriptor->data0)); 261862306a36Sopenharmony_ci buffer_length = buffer_info->buffer_length; 261962306a36Sopenharmony_ci is_ice = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_ICE_; 262062306a36Sopenharmony_ci is_tce = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_TCE_; 262162306a36Sopenharmony_ci is_icsm = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_ICSM_; 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci netdev_dbg(netdev, "%s%schunk: %d/%d", 262462306a36Sopenharmony_ci is_first ? "first " : " ", 262562306a36Sopenharmony_ci is_last ? "last " : " ", 262662306a36Sopenharmony_ci frame_length, buffer_length); 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci /* save existing skb, allocate new skb and map to dma */ 262962306a36Sopenharmony_ci skb = buffer_info->skb; 263062306a36Sopenharmony_ci if (lan743x_rx_init_ring_element(rx, rx->last_head, 263162306a36Sopenharmony_ci GFP_ATOMIC | GFP_DMA)) { 263262306a36Sopenharmony_ci /* failed to allocate next skb. 263362306a36Sopenharmony_ci * Memory is very low. 263462306a36Sopenharmony_ci * Drop this packet and reuse buffer. 263562306a36Sopenharmony_ci */ 263662306a36Sopenharmony_ci lan743x_rx_reuse_ring_element(rx, rx->last_head); 263762306a36Sopenharmony_ci /* drop packet that was being assembled */ 263862306a36Sopenharmony_ci dev_kfree_skb_irq(rx->skb_head); 263962306a36Sopenharmony_ci rx->skb_head = NULL; 264062306a36Sopenharmony_ci goto process_extension; 264162306a36Sopenharmony_ci } 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci /* add buffers to skb via skb->frag_list */ 264462306a36Sopenharmony_ci if (is_first) { 264562306a36Sopenharmony_ci skb_reserve(skb, RX_HEAD_PADDING); 264662306a36Sopenharmony_ci skb_put(skb, buffer_length - RX_HEAD_PADDING); 264762306a36Sopenharmony_ci if (rx->skb_head) 264862306a36Sopenharmony_ci dev_kfree_skb_irq(rx->skb_head); 264962306a36Sopenharmony_ci rx->skb_head = skb; 265062306a36Sopenharmony_ci } else if (rx->skb_head) { 265162306a36Sopenharmony_ci skb_put(skb, buffer_length); 265262306a36Sopenharmony_ci if (skb_shinfo(rx->skb_head)->frag_list) 265362306a36Sopenharmony_ci rx->skb_tail->next = skb; 265462306a36Sopenharmony_ci else 265562306a36Sopenharmony_ci skb_shinfo(rx->skb_head)->frag_list = skb; 265662306a36Sopenharmony_ci rx->skb_tail = skb; 265762306a36Sopenharmony_ci rx->skb_head->len += skb->len; 265862306a36Sopenharmony_ci rx->skb_head->data_len += skb->len; 265962306a36Sopenharmony_ci rx->skb_head->truesize += skb->truesize; 266062306a36Sopenharmony_ci } else { 266162306a36Sopenharmony_ci /* packet to assemble has already been dropped because one or 266262306a36Sopenharmony_ci * more of its buffers could not be allocated 266362306a36Sopenharmony_ci */ 266462306a36Sopenharmony_ci netdev_dbg(netdev, "drop buffer intended for dropped packet"); 266562306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ciprocess_extension: 266962306a36Sopenharmony_ci if (extension_index >= 0) { 267062306a36Sopenharmony_ci u32 ts_sec; 267162306a36Sopenharmony_ci u32 ts_nsec; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci ts_sec = le32_to_cpu(desc_ext->data1); 267462306a36Sopenharmony_ci ts_nsec = (le32_to_cpu(desc_ext->data2) & 267562306a36Sopenharmony_ci RX_DESC_DATA2_TS_NS_MASK_); 267662306a36Sopenharmony_ci if (rx->skb_head) 267762306a36Sopenharmony_ci skb_hwtstamps(rx->skb_head)->hwtstamp = 267862306a36Sopenharmony_ci ktime_set(ts_sec, ts_nsec); 267962306a36Sopenharmony_ci lan743x_rx_reuse_ring_element(rx, extension_index); 268062306a36Sopenharmony_ci rx->last_head = extension_index; 268162306a36Sopenharmony_ci netdev_dbg(netdev, "process extension"); 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci if (is_last && rx->skb_head) 268562306a36Sopenharmony_ci rx->skb_head = lan743x_rx_trim_skb(rx->skb_head, frame_length); 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci if (is_last && rx->skb_head) { 268862306a36Sopenharmony_ci rx->skb_head->protocol = eth_type_trans(rx->skb_head, 268962306a36Sopenharmony_ci rx->adapter->netdev); 269062306a36Sopenharmony_ci if (rx->adapter->netdev->features & NETIF_F_RXCSUM) { 269162306a36Sopenharmony_ci if (!is_ice && !is_tce && !is_icsm) 269262306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 269362306a36Sopenharmony_ci } 269462306a36Sopenharmony_ci netdev_dbg(netdev, "sending %d byte frame to OS", 269562306a36Sopenharmony_ci rx->skb_head->len); 269662306a36Sopenharmony_ci napi_gro_receive(&rx->napi, rx->skb_head); 269762306a36Sopenharmony_ci rx->skb_head = NULL; 269862306a36Sopenharmony_ci } 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_cimove_forward: 270162306a36Sopenharmony_ci /* push tail and head forward */ 270262306a36Sopenharmony_ci rx->last_tail = rx->last_head; 270362306a36Sopenharmony_ci rx->last_head = lan743x_rx_next_index(rx, rx->last_head); 270462306a36Sopenharmony_ci result = RX_PROCESS_RESULT_BUFFER_RECEIVED; 270562306a36Sopenharmony_cidone: 270662306a36Sopenharmony_ci return result; 270762306a36Sopenharmony_ci} 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_cistatic int lan743x_rx_napi_poll(struct napi_struct *napi, int weight) 271062306a36Sopenharmony_ci{ 271162306a36Sopenharmony_ci struct lan743x_rx *rx = container_of(napi, struct lan743x_rx, napi); 271262306a36Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 271362306a36Sopenharmony_ci int result = RX_PROCESS_RESULT_NOTHING_TO_DO; 271462306a36Sopenharmony_ci u32 rx_tail_flags = 0; 271562306a36Sopenharmony_ci int count; 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C) { 271862306a36Sopenharmony_ci /* clear int status bit before reading packet */ 271962306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_STS, 272062306a36Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 272162306a36Sopenharmony_ci } 272262306a36Sopenharmony_ci for (count = 0; count < weight; count++) { 272362306a36Sopenharmony_ci result = lan743x_rx_process_buffer(rx); 272462306a36Sopenharmony_ci if (result == RX_PROCESS_RESULT_NOTHING_TO_DO) 272562306a36Sopenharmony_ci break; 272662306a36Sopenharmony_ci } 272762306a36Sopenharmony_ci rx->frame_count += count; 272862306a36Sopenharmony_ci if (count == weight || result == RX_PROCESS_RESULT_BUFFER_RECEIVED) 272962306a36Sopenharmony_ci return weight; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci if (!napi_complete_done(napi, count)) 273262306a36Sopenharmony_ci return count; 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ci /* re-arm interrupts, must write to rx tail on some chip variants */ 273562306a36Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET) 273662306a36Sopenharmony_ci rx_tail_flags |= RX_TAIL_SET_TOP_INT_VEC_EN_; 273762306a36Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET) { 273862306a36Sopenharmony_ci rx_tail_flags |= RX_TAIL_SET_TOP_INT_EN_; 273962306a36Sopenharmony_ci } else { 274062306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 274162306a36Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 274262306a36Sopenharmony_ci } 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci if (rx_tail_flags) 274562306a36Sopenharmony_ci lan743x_csr_write(adapter, RX_TAIL(rx->channel_number), 274662306a36Sopenharmony_ci rx_tail_flags | rx->last_tail); 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci return count; 274962306a36Sopenharmony_ci} 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_cistatic void lan743x_rx_ring_cleanup(struct lan743x_rx *rx) 275262306a36Sopenharmony_ci{ 275362306a36Sopenharmony_ci if (rx->buffer_info && rx->ring_cpu_ptr) { 275462306a36Sopenharmony_ci int index; 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci for (index = 0; index < rx->ring_size; index++) 275762306a36Sopenharmony_ci lan743x_rx_release_ring_element(rx, index); 275862306a36Sopenharmony_ci } 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci if (rx->head_cpu_ptr) { 276162306a36Sopenharmony_ci dma_free_coherent(&rx->adapter->pdev->dev, 276262306a36Sopenharmony_ci sizeof(*rx->head_cpu_ptr), rx->head_cpu_ptr, 276362306a36Sopenharmony_ci rx->head_dma_ptr); 276462306a36Sopenharmony_ci rx->head_cpu_ptr = NULL; 276562306a36Sopenharmony_ci rx->head_dma_ptr = 0; 276662306a36Sopenharmony_ci } 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci kfree(rx->buffer_info); 276962306a36Sopenharmony_ci rx->buffer_info = NULL; 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci if (rx->ring_cpu_ptr) { 277262306a36Sopenharmony_ci dma_free_coherent(&rx->adapter->pdev->dev, 277362306a36Sopenharmony_ci rx->ring_allocation_size, rx->ring_cpu_ptr, 277462306a36Sopenharmony_ci rx->ring_dma_ptr); 277562306a36Sopenharmony_ci rx->ring_allocation_size = 0; 277662306a36Sopenharmony_ci rx->ring_cpu_ptr = NULL; 277762306a36Sopenharmony_ci rx->ring_dma_ptr = 0; 277862306a36Sopenharmony_ci } 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci rx->ring_size = 0; 278162306a36Sopenharmony_ci rx->last_head = 0; 278262306a36Sopenharmony_ci} 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_cistatic int lan743x_rx_ring_init(struct lan743x_rx *rx) 278562306a36Sopenharmony_ci{ 278662306a36Sopenharmony_ci size_t ring_allocation_size = 0; 278762306a36Sopenharmony_ci dma_addr_t dma_ptr = 0; 278862306a36Sopenharmony_ci void *cpu_ptr = NULL; 278962306a36Sopenharmony_ci int ret = -ENOMEM; 279062306a36Sopenharmony_ci int index = 0; 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci rx->ring_size = LAN743X_RX_RING_SIZE; 279362306a36Sopenharmony_ci if (rx->ring_size <= 1) { 279462306a36Sopenharmony_ci ret = -EINVAL; 279562306a36Sopenharmony_ci goto cleanup; 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci if (rx->ring_size & ~RX_CFG_B_RX_RING_LEN_MASK_) { 279862306a36Sopenharmony_ci ret = -EINVAL; 279962306a36Sopenharmony_ci goto cleanup; 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&rx->adapter->pdev->dev, 280262306a36Sopenharmony_ci DMA_BIT_MASK(64))) { 280362306a36Sopenharmony_ci dev_warn(&rx->adapter->pdev->dev, 280462306a36Sopenharmony_ci "lan743x_: No suitable DMA available\n"); 280562306a36Sopenharmony_ci ret = -ENOMEM; 280662306a36Sopenharmony_ci goto cleanup; 280762306a36Sopenharmony_ci } 280862306a36Sopenharmony_ci ring_allocation_size = ALIGN(rx->ring_size * 280962306a36Sopenharmony_ci sizeof(struct lan743x_rx_descriptor), 281062306a36Sopenharmony_ci PAGE_SIZE); 281162306a36Sopenharmony_ci dma_ptr = 0; 281262306a36Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev, 281362306a36Sopenharmony_ci ring_allocation_size, &dma_ptr, GFP_KERNEL); 281462306a36Sopenharmony_ci if (!cpu_ptr) { 281562306a36Sopenharmony_ci ret = -ENOMEM; 281662306a36Sopenharmony_ci goto cleanup; 281762306a36Sopenharmony_ci } 281862306a36Sopenharmony_ci rx->ring_allocation_size = ring_allocation_size; 281962306a36Sopenharmony_ci rx->ring_cpu_ptr = (struct lan743x_rx_descriptor *)cpu_ptr; 282062306a36Sopenharmony_ci rx->ring_dma_ptr = dma_ptr; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci cpu_ptr = kcalloc(rx->ring_size, sizeof(*rx->buffer_info), 282362306a36Sopenharmony_ci GFP_KERNEL); 282462306a36Sopenharmony_ci if (!cpu_ptr) { 282562306a36Sopenharmony_ci ret = -ENOMEM; 282662306a36Sopenharmony_ci goto cleanup; 282762306a36Sopenharmony_ci } 282862306a36Sopenharmony_ci rx->buffer_info = (struct lan743x_rx_buffer_info *)cpu_ptr; 282962306a36Sopenharmony_ci dma_ptr = 0; 283062306a36Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev, 283162306a36Sopenharmony_ci sizeof(*rx->head_cpu_ptr), &dma_ptr, 283262306a36Sopenharmony_ci GFP_KERNEL); 283362306a36Sopenharmony_ci if (!cpu_ptr) { 283462306a36Sopenharmony_ci ret = -ENOMEM; 283562306a36Sopenharmony_ci goto cleanup; 283662306a36Sopenharmony_ci } 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci rx->head_cpu_ptr = cpu_ptr; 283962306a36Sopenharmony_ci rx->head_dma_ptr = dma_ptr; 284062306a36Sopenharmony_ci if (rx->head_dma_ptr & 0x3) { 284162306a36Sopenharmony_ci ret = -ENOMEM; 284262306a36Sopenharmony_ci goto cleanup; 284362306a36Sopenharmony_ci } 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci rx->last_head = 0; 284662306a36Sopenharmony_ci for (index = 0; index < rx->ring_size; index++) { 284762306a36Sopenharmony_ci ret = lan743x_rx_init_ring_element(rx, index, GFP_KERNEL); 284862306a36Sopenharmony_ci if (ret) 284962306a36Sopenharmony_ci goto cleanup; 285062306a36Sopenharmony_ci } 285162306a36Sopenharmony_ci return 0; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_cicleanup: 285462306a36Sopenharmony_ci netif_warn(rx->adapter, ifup, rx->adapter->netdev, 285562306a36Sopenharmony_ci "Error allocating memory for LAN743x\n"); 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci lan743x_rx_ring_cleanup(rx); 285862306a36Sopenharmony_ci return ret; 285962306a36Sopenharmony_ci} 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_cistatic void lan743x_rx_close(struct lan743x_rx *rx) 286262306a36Sopenharmony_ci{ 286362306a36Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 286462306a36Sopenharmony_ci 286562306a36Sopenharmony_ci lan743x_csr_write(adapter, FCT_RX_CTL, 286662306a36Sopenharmony_ci FCT_RX_CTL_DIS_(rx->channel_number)); 286762306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL, 286862306a36Sopenharmony_ci FCT_RX_CTL_EN_(rx->channel_number), 286962306a36Sopenharmony_ci 0, 1000, 20000, 100); 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 287262306a36Sopenharmony_ci DMAC_CMD_STOP_R_(rx->channel_number)); 287362306a36Sopenharmony_ci lan743x_dmac_rx_wait_till_stopped(adapter, rx->channel_number); 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_EN_CLR, 287662306a36Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 287762306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 287862306a36Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 287962306a36Sopenharmony_ci napi_disable(&rx->napi); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci netif_napi_del(&rx->napi); 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci lan743x_rx_ring_cleanup(rx); 288462306a36Sopenharmony_ci} 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_cistatic int lan743x_rx_open(struct lan743x_rx *rx) 288762306a36Sopenharmony_ci{ 288862306a36Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 288962306a36Sopenharmony_ci u32 data = 0; 289062306a36Sopenharmony_ci int ret; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci rx->frame_count = 0; 289362306a36Sopenharmony_ci ret = lan743x_rx_ring_init(rx); 289462306a36Sopenharmony_ci if (ret) 289562306a36Sopenharmony_ci goto return_error; 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci netif_napi_add(adapter->netdev, &rx->napi, lan743x_rx_napi_poll); 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 290062306a36Sopenharmony_ci DMAC_CMD_RX_SWR_(rx->channel_number)); 290162306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, DMAC_CMD, 290262306a36Sopenharmony_ci DMAC_CMD_RX_SWR_(rx->channel_number), 290362306a36Sopenharmony_ci 0, 1000, 20000, 100); 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci /* set ring base address */ 290662306a36Sopenharmony_ci lan743x_csr_write(adapter, 290762306a36Sopenharmony_ci RX_BASE_ADDRH(rx->channel_number), 290862306a36Sopenharmony_ci DMA_ADDR_HIGH32(rx->ring_dma_ptr)); 290962306a36Sopenharmony_ci lan743x_csr_write(adapter, 291062306a36Sopenharmony_ci RX_BASE_ADDRL(rx->channel_number), 291162306a36Sopenharmony_ci DMA_ADDR_LOW32(rx->ring_dma_ptr)); 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci /* set rx write back address */ 291462306a36Sopenharmony_ci lan743x_csr_write(adapter, 291562306a36Sopenharmony_ci RX_HEAD_WRITEBACK_ADDRH(rx->channel_number), 291662306a36Sopenharmony_ci DMA_ADDR_HIGH32(rx->head_dma_ptr)); 291762306a36Sopenharmony_ci lan743x_csr_write(adapter, 291862306a36Sopenharmony_ci RX_HEAD_WRITEBACK_ADDRL(rx->channel_number), 291962306a36Sopenharmony_ci DMA_ADDR_LOW32(rx->head_dma_ptr)); 292062306a36Sopenharmony_ci data = RX_CFG_A_RX_HP_WB_EN_; 292162306a36Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 292262306a36Sopenharmony_ci data |= (RX_CFG_A_RX_WB_ON_INT_TMR_ | 292362306a36Sopenharmony_ci RX_CFG_A_RX_WB_THRES_SET_(0x7) | 292462306a36Sopenharmony_ci RX_CFG_A_RX_PF_THRES_SET_(16) | 292562306a36Sopenharmony_ci RX_CFG_A_RX_PF_PRI_THRES_SET_(4)); 292662306a36Sopenharmony_ci } 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci /* set RX_CFG_A */ 292962306a36Sopenharmony_ci lan743x_csr_write(adapter, 293062306a36Sopenharmony_ci RX_CFG_A(rx->channel_number), data); 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci /* set RX_CFG_B */ 293362306a36Sopenharmony_ci data = lan743x_csr_read(adapter, RX_CFG_B(rx->channel_number)); 293462306a36Sopenharmony_ci data &= ~RX_CFG_B_RX_PAD_MASK_; 293562306a36Sopenharmony_ci if (!RX_HEAD_PADDING) 293662306a36Sopenharmony_ci data |= RX_CFG_B_RX_PAD_0_; 293762306a36Sopenharmony_ci else 293862306a36Sopenharmony_ci data |= RX_CFG_B_RX_PAD_2_; 293962306a36Sopenharmony_ci data &= ~RX_CFG_B_RX_RING_LEN_MASK_; 294062306a36Sopenharmony_ci data |= ((rx->ring_size) & RX_CFG_B_RX_RING_LEN_MASK_); 294162306a36Sopenharmony_ci data |= RX_CFG_B_TS_ALL_RX_; 294262306a36Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) 294362306a36Sopenharmony_ci data |= RX_CFG_B_RDMABL_512_; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci lan743x_csr_write(adapter, RX_CFG_B(rx->channel_number), data); 294662306a36Sopenharmony_ci rx->vector_flags = lan743x_intr_get_vector_flags(adapter, 294762306a36Sopenharmony_ci INT_BIT_DMA_RX_ 294862306a36Sopenharmony_ci (rx->channel_number)); 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci /* set RX_CFG_C */ 295162306a36Sopenharmony_ci data = 0; 295262306a36Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR) 295362306a36Sopenharmony_ci data |= RX_CFG_C_RX_TOP_INT_EN_AUTO_CLR_; 295462306a36Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR) 295562306a36Sopenharmony_ci data |= RX_CFG_C_RX_DMA_INT_STS_AUTO_CLR_; 295662306a36Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C) 295762306a36Sopenharmony_ci data |= RX_CFG_C_RX_INT_STS_R2C_MODE_MASK_; 295862306a36Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C) 295962306a36Sopenharmony_ci data |= RX_CFG_C_RX_INT_EN_R2C_; 296062306a36Sopenharmony_ci lan743x_csr_write(adapter, RX_CFG_C(rx->channel_number), data); 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci rx->last_tail = ((u32)(rx->ring_size - 1)); 296362306a36Sopenharmony_ci lan743x_csr_write(adapter, RX_TAIL(rx->channel_number), 296462306a36Sopenharmony_ci rx->last_tail); 296562306a36Sopenharmony_ci rx->last_head = lan743x_csr_read(adapter, RX_HEAD(rx->channel_number)); 296662306a36Sopenharmony_ci if (rx->last_head) { 296762306a36Sopenharmony_ci ret = -EIO; 296862306a36Sopenharmony_ci goto napi_delete; 296962306a36Sopenharmony_ci } 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci napi_enable(&rx->napi); 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 297462306a36Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 297562306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_STS, 297662306a36Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 297762306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_EN_SET, 297862306a36Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 297962306a36Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 298062306a36Sopenharmony_ci DMAC_CMD_START_R_(rx->channel_number)); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci /* initialize fifo */ 298362306a36Sopenharmony_ci lan743x_csr_write(adapter, FCT_RX_CTL, 298462306a36Sopenharmony_ci FCT_RX_CTL_RESET_(rx->channel_number)); 298562306a36Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL, 298662306a36Sopenharmony_ci FCT_RX_CTL_RESET_(rx->channel_number), 298762306a36Sopenharmony_ci 0, 1000, 20000, 100); 298862306a36Sopenharmony_ci lan743x_csr_write(adapter, FCT_FLOW(rx->channel_number), 298962306a36Sopenharmony_ci FCT_FLOW_CTL_REQ_EN_ | 299062306a36Sopenharmony_ci FCT_FLOW_CTL_ON_THRESHOLD_SET_(0x2A) | 299162306a36Sopenharmony_ci FCT_FLOW_CTL_OFF_THRESHOLD_SET_(0xA)); 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci /* enable fifo */ 299462306a36Sopenharmony_ci lan743x_csr_write(adapter, FCT_RX_CTL, 299562306a36Sopenharmony_ci FCT_RX_CTL_EN_(rx->channel_number)); 299662306a36Sopenharmony_ci return 0; 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_cinapi_delete: 299962306a36Sopenharmony_ci netif_napi_del(&rx->napi); 300062306a36Sopenharmony_ci lan743x_rx_ring_cleanup(rx); 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_cireturn_error: 300362306a36Sopenharmony_ci return ret; 300462306a36Sopenharmony_ci} 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_cistatic int lan743x_netdev_close(struct net_device *netdev) 300762306a36Sopenharmony_ci{ 300862306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 300962306a36Sopenharmony_ci int index; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci for (index = 0; index < adapter->used_tx_channels; index++) 301262306a36Sopenharmony_ci lan743x_tx_close(&adapter->tx[index]); 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) 301562306a36Sopenharmony_ci lan743x_rx_close(&adapter->rx[index]); 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_ci lan743x_ptp_close(adapter); 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci lan743x_phy_close(adapter); 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci lan743x_mac_close(adapter); 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci lan743x_intr_close(adapter); 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci return 0; 302662306a36Sopenharmony_ci} 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_cistatic int lan743x_netdev_open(struct net_device *netdev) 302962306a36Sopenharmony_ci{ 303062306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 303162306a36Sopenharmony_ci int index; 303262306a36Sopenharmony_ci int ret; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci ret = lan743x_intr_open(adapter); 303562306a36Sopenharmony_ci if (ret) 303662306a36Sopenharmony_ci goto return_error; 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci ret = lan743x_mac_open(adapter); 303962306a36Sopenharmony_ci if (ret) 304062306a36Sopenharmony_ci goto close_intr; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci ret = lan743x_phy_open(adapter); 304362306a36Sopenharmony_ci if (ret) 304462306a36Sopenharmony_ci goto close_mac; 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci ret = lan743x_ptp_open(adapter); 304762306a36Sopenharmony_ci if (ret) 304862306a36Sopenharmony_ci goto close_phy; 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci lan743x_rfe_open(adapter); 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) { 305362306a36Sopenharmony_ci ret = lan743x_rx_open(&adapter->rx[index]); 305462306a36Sopenharmony_ci if (ret) 305562306a36Sopenharmony_ci goto close_rx; 305662306a36Sopenharmony_ci } 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci for (index = 0; index < adapter->used_tx_channels; index++) { 305962306a36Sopenharmony_ci ret = lan743x_tx_open(&adapter->tx[index]); 306062306a36Sopenharmony_ci if (ret) 306162306a36Sopenharmony_ci goto close_tx; 306262306a36Sopenharmony_ci } 306362306a36Sopenharmony_ci return 0; 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ciclose_tx: 306662306a36Sopenharmony_ci for (index = 0; index < adapter->used_tx_channels; index++) { 306762306a36Sopenharmony_ci if (adapter->tx[index].ring_cpu_ptr) 306862306a36Sopenharmony_ci lan743x_tx_close(&adapter->tx[index]); 306962306a36Sopenharmony_ci } 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ciclose_rx: 307262306a36Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) { 307362306a36Sopenharmony_ci if (adapter->rx[index].ring_cpu_ptr) 307462306a36Sopenharmony_ci lan743x_rx_close(&adapter->rx[index]); 307562306a36Sopenharmony_ci } 307662306a36Sopenharmony_ci lan743x_ptp_close(adapter); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ciclose_phy: 307962306a36Sopenharmony_ci lan743x_phy_close(adapter); 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ciclose_mac: 308262306a36Sopenharmony_ci lan743x_mac_close(adapter); 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ciclose_intr: 308562306a36Sopenharmony_ci lan743x_intr_close(adapter); 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_cireturn_error: 308862306a36Sopenharmony_ci netif_warn(adapter, ifup, adapter->netdev, 308962306a36Sopenharmony_ci "Error opening LAN743x\n"); 309062306a36Sopenharmony_ci return ret; 309162306a36Sopenharmony_ci} 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_cistatic netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb, 309462306a36Sopenharmony_ci struct net_device *netdev) 309562306a36Sopenharmony_ci{ 309662306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 309762306a36Sopenharmony_ci u8 ch = 0; 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci if (adapter->is_pci11x1x) 310062306a36Sopenharmony_ci ch = skb->queue_mapping % PCI11X1X_USED_TX_CHANNELS; 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci return lan743x_tx_xmit_frame(&adapter->tx[ch], skb); 310362306a36Sopenharmony_ci} 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_cistatic int lan743x_netdev_ioctl(struct net_device *netdev, 310662306a36Sopenharmony_ci struct ifreq *ifr, int cmd) 310762306a36Sopenharmony_ci{ 310862306a36Sopenharmony_ci if (!netif_running(netdev)) 310962306a36Sopenharmony_ci return -EINVAL; 311062306a36Sopenharmony_ci if (cmd == SIOCSHWTSTAMP) 311162306a36Sopenharmony_ci return lan743x_ptp_ioctl(netdev, ifr, cmd); 311262306a36Sopenharmony_ci return phy_mii_ioctl(netdev->phydev, ifr, cmd); 311362306a36Sopenharmony_ci} 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_cistatic void lan743x_netdev_set_multicast(struct net_device *netdev) 311662306a36Sopenharmony_ci{ 311762306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci lan743x_rfe_set_multicast(adapter); 312062306a36Sopenharmony_ci} 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_cistatic int lan743x_netdev_change_mtu(struct net_device *netdev, int new_mtu) 312362306a36Sopenharmony_ci{ 312462306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 312562306a36Sopenharmony_ci int ret = 0; 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci ret = lan743x_mac_set_mtu(adapter, new_mtu); 312862306a36Sopenharmony_ci if (!ret) 312962306a36Sopenharmony_ci netdev->mtu = new_mtu; 313062306a36Sopenharmony_ci return ret; 313162306a36Sopenharmony_ci} 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_cistatic void lan743x_netdev_get_stats64(struct net_device *netdev, 313462306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 313562306a36Sopenharmony_ci{ 313662306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci stats->rx_packets = lan743x_csr_read(adapter, STAT_RX_TOTAL_FRAMES); 313962306a36Sopenharmony_ci stats->tx_packets = lan743x_csr_read(adapter, STAT_TX_TOTAL_FRAMES); 314062306a36Sopenharmony_ci stats->rx_bytes = lan743x_csr_read(adapter, 314162306a36Sopenharmony_ci STAT_RX_UNICAST_BYTE_COUNT) + 314262306a36Sopenharmony_ci lan743x_csr_read(adapter, 314362306a36Sopenharmony_ci STAT_RX_BROADCAST_BYTE_COUNT) + 314462306a36Sopenharmony_ci lan743x_csr_read(adapter, 314562306a36Sopenharmony_ci STAT_RX_MULTICAST_BYTE_COUNT); 314662306a36Sopenharmony_ci stats->tx_bytes = lan743x_csr_read(adapter, 314762306a36Sopenharmony_ci STAT_TX_UNICAST_BYTE_COUNT) + 314862306a36Sopenharmony_ci lan743x_csr_read(adapter, 314962306a36Sopenharmony_ci STAT_TX_BROADCAST_BYTE_COUNT) + 315062306a36Sopenharmony_ci lan743x_csr_read(adapter, 315162306a36Sopenharmony_ci STAT_TX_MULTICAST_BYTE_COUNT); 315262306a36Sopenharmony_ci stats->rx_errors = lan743x_csr_read(adapter, STAT_RX_FCS_ERRORS) + 315362306a36Sopenharmony_ci lan743x_csr_read(adapter, 315462306a36Sopenharmony_ci STAT_RX_ALIGNMENT_ERRORS) + 315562306a36Sopenharmony_ci lan743x_csr_read(adapter, STAT_RX_JABBER_ERRORS) + 315662306a36Sopenharmony_ci lan743x_csr_read(adapter, 315762306a36Sopenharmony_ci STAT_RX_UNDERSIZE_FRAME_ERRORS) + 315862306a36Sopenharmony_ci lan743x_csr_read(adapter, 315962306a36Sopenharmony_ci STAT_RX_OVERSIZE_FRAME_ERRORS); 316062306a36Sopenharmony_ci stats->tx_errors = lan743x_csr_read(adapter, STAT_TX_FCS_ERRORS) + 316162306a36Sopenharmony_ci lan743x_csr_read(adapter, 316262306a36Sopenharmony_ci STAT_TX_EXCESS_DEFERRAL_ERRORS) + 316362306a36Sopenharmony_ci lan743x_csr_read(adapter, STAT_TX_CARRIER_ERRORS); 316462306a36Sopenharmony_ci stats->rx_dropped = lan743x_csr_read(adapter, 316562306a36Sopenharmony_ci STAT_RX_DROPPED_FRAMES); 316662306a36Sopenharmony_ci stats->tx_dropped = lan743x_csr_read(adapter, 316762306a36Sopenharmony_ci STAT_TX_EXCESSIVE_COLLISION); 316862306a36Sopenharmony_ci stats->multicast = lan743x_csr_read(adapter, 316962306a36Sopenharmony_ci STAT_RX_MULTICAST_FRAMES) + 317062306a36Sopenharmony_ci lan743x_csr_read(adapter, 317162306a36Sopenharmony_ci STAT_TX_MULTICAST_FRAMES); 317262306a36Sopenharmony_ci stats->collisions = lan743x_csr_read(adapter, 317362306a36Sopenharmony_ci STAT_TX_SINGLE_COLLISIONS) + 317462306a36Sopenharmony_ci lan743x_csr_read(adapter, 317562306a36Sopenharmony_ci STAT_TX_MULTIPLE_COLLISIONS) + 317662306a36Sopenharmony_ci lan743x_csr_read(adapter, 317762306a36Sopenharmony_ci STAT_TX_LATE_COLLISIONS); 317862306a36Sopenharmony_ci} 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_cistatic int lan743x_netdev_set_mac_address(struct net_device *netdev, 318162306a36Sopenharmony_ci void *addr) 318262306a36Sopenharmony_ci{ 318362306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 318462306a36Sopenharmony_ci struct sockaddr *sock_addr = addr; 318562306a36Sopenharmony_ci int ret; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci ret = eth_prepare_mac_addr_change(netdev, sock_addr); 318862306a36Sopenharmony_ci if (ret) 318962306a36Sopenharmony_ci return ret; 319062306a36Sopenharmony_ci eth_hw_addr_set(netdev, sock_addr->sa_data); 319162306a36Sopenharmony_ci lan743x_mac_set_address(adapter, sock_addr->sa_data); 319262306a36Sopenharmony_ci lan743x_rfe_update_mac_address(adapter); 319362306a36Sopenharmony_ci return 0; 319462306a36Sopenharmony_ci} 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_cistatic const struct net_device_ops lan743x_netdev_ops = { 319762306a36Sopenharmony_ci .ndo_open = lan743x_netdev_open, 319862306a36Sopenharmony_ci .ndo_stop = lan743x_netdev_close, 319962306a36Sopenharmony_ci .ndo_start_xmit = lan743x_netdev_xmit_frame, 320062306a36Sopenharmony_ci .ndo_eth_ioctl = lan743x_netdev_ioctl, 320162306a36Sopenharmony_ci .ndo_set_rx_mode = lan743x_netdev_set_multicast, 320262306a36Sopenharmony_ci .ndo_change_mtu = lan743x_netdev_change_mtu, 320362306a36Sopenharmony_ci .ndo_get_stats64 = lan743x_netdev_get_stats64, 320462306a36Sopenharmony_ci .ndo_set_mac_address = lan743x_netdev_set_mac_address, 320562306a36Sopenharmony_ci}; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_cistatic void lan743x_hardware_cleanup(struct lan743x_adapter *adapter) 320862306a36Sopenharmony_ci{ 320962306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF); 321062306a36Sopenharmony_ci} 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_cistatic void lan743x_mdiobus_cleanup(struct lan743x_adapter *adapter) 321362306a36Sopenharmony_ci{ 321462306a36Sopenharmony_ci mdiobus_unregister(adapter->mdiobus); 321562306a36Sopenharmony_ci} 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_cistatic void lan743x_full_cleanup(struct lan743x_adapter *adapter) 321862306a36Sopenharmony_ci{ 321962306a36Sopenharmony_ci unregister_netdev(adapter->netdev); 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci lan743x_mdiobus_cleanup(adapter); 322262306a36Sopenharmony_ci lan743x_hardware_cleanup(adapter); 322362306a36Sopenharmony_ci lan743x_pci_cleanup(adapter); 322462306a36Sopenharmony_ci} 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_cistatic int lan743x_hardware_init(struct lan743x_adapter *adapter, 322762306a36Sopenharmony_ci struct pci_dev *pdev) 322862306a36Sopenharmony_ci{ 322962306a36Sopenharmony_ci struct lan743x_tx *tx; 323062306a36Sopenharmony_ci int index; 323162306a36Sopenharmony_ci int ret; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci adapter->is_pci11x1x = is_pci11x1x_chip(adapter); 323462306a36Sopenharmony_ci if (adapter->is_pci11x1x) { 323562306a36Sopenharmony_ci adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS; 323662306a36Sopenharmony_ci adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS; 323762306a36Sopenharmony_ci adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT; 323862306a36Sopenharmony_ci pci11x1x_strap_get_status(adapter); 323962306a36Sopenharmony_ci spin_lock_init(&adapter->eth_syslock_spinlock); 324062306a36Sopenharmony_ci mutex_init(&adapter->sgmii_rw_lock); 324162306a36Sopenharmony_ci } else { 324262306a36Sopenharmony_ci adapter->max_tx_channels = LAN743X_MAX_TX_CHANNELS; 324362306a36Sopenharmony_ci adapter->used_tx_channels = LAN743X_USED_TX_CHANNELS; 324462306a36Sopenharmony_ci adapter->max_vector_count = LAN743X_MAX_VECTOR_COUNT; 324562306a36Sopenharmony_ci } 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci adapter->intr.irq = adapter->pdev->irq; 324862306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF); 324962306a36Sopenharmony_ci 325062306a36Sopenharmony_ci ret = lan743x_gpio_init(adapter); 325162306a36Sopenharmony_ci if (ret) 325262306a36Sopenharmony_ci return ret; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci ret = lan743x_mac_init(adapter); 325562306a36Sopenharmony_ci if (ret) 325662306a36Sopenharmony_ci return ret; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci ret = lan743x_phy_init(adapter); 325962306a36Sopenharmony_ci if (ret) 326062306a36Sopenharmony_ci return ret; 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci ret = lan743x_ptp_init(adapter); 326362306a36Sopenharmony_ci if (ret) 326462306a36Sopenharmony_ci return ret; 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci lan743x_rfe_update_mac_address(adapter); 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci ret = lan743x_dmac_init(adapter); 326962306a36Sopenharmony_ci if (ret) 327062306a36Sopenharmony_ci return ret; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) { 327362306a36Sopenharmony_ci adapter->rx[index].adapter = adapter; 327462306a36Sopenharmony_ci adapter->rx[index].channel_number = index; 327562306a36Sopenharmony_ci } 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci for (index = 0; index < adapter->used_tx_channels; index++) { 327862306a36Sopenharmony_ci tx = &adapter->tx[index]; 327962306a36Sopenharmony_ci tx->adapter = adapter; 328062306a36Sopenharmony_ci tx->channel_number = index; 328162306a36Sopenharmony_ci spin_lock_init(&tx->ring_lock); 328262306a36Sopenharmony_ci } 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci return 0; 328562306a36Sopenharmony_ci} 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_cistatic int lan743x_mdiobus_init(struct lan743x_adapter *adapter) 328862306a36Sopenharmony_ci{ 328962306a36Sopenharmony_ci u32 sgmii_ctl; 329062306a36Sopenharmony_ci int ret; 329162306a36Sopenharmony_ci 329262306a36Sopenharmony_ci adapter->mdiobus = devm_mdiobus_alloc(&adapter->pdev->dev); 329362306a36Sopenharmony_ci if (!(adapter->mdiobus)) { 329462306a36Sopenharmony_ci ret = -ENOMEM; 329562306a36Sopenharmony_ci goto return_error; 329662306a36Sopenharmony_ci } 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci adapter->mdiobus->priv = (void *)adapter; 329962306a36Sopenharmony_ci if (adapter->is_pci11x1x) { 330062306a36Sopenharmony_ci if (adapter->is_sgmii_en) { 330162306a36Sopenharmony_ci sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); 330262306a36Sopenharmony_ci sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_; 330362306a36Sopenharmony_ci sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_; 330462306a36Sopenharmony_ci lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); 330562306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, 330662306a36Sopenharmony_ci "SGMII operation\n"); 330762306a36Sopenharmony_ci adapter->mdiobus->read = lan743x_mdiobus_read_c22; 330862306a36Sopenharmony_ci adapter->mdiobus->write = lan743x_mdiobus_write_c22; 330962306a36Sopenharmony_ci adapter->mdiobus->read_c45 = lan743x_mdiobus_read_c45; 331062306a36Sopenharmony_ci adapter->mdiobus->write_c45 = lan743x_mdiobus_write_c45; 331162306a36Sopenharmony_ci adapter->mdiobus->name = "lan743x-mdiobus-c45"; 331262306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, 331362306a36Sopenharmony_ci "lan743x-mdiobus-c45\n"); 331462306a36Sopenharmony_ci } else { 331562306a36Sopenharmony_ci sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); 331662306a36Sopenharmony_ci sgmii_ctl &= ~SGMII_CTL_SGMII_ENABLE_; 331762306a36Sopenharmony_ci sgmii_ctl |= SGMII_CTL_SGMII_POWER_DN_; 331862306a36Sopenharmony_ci lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); 331962306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, 332062306a36Sopenharmony_ci "RGMII operation\n"); 332162306a36Sopenharmony_ci // Only C22 support when RGMII I/F 332262306a36Sopenharmony_ci adapter->mdiobus->read = lan743x_mdiobus_read_c22; 332362306a36Sopenharmony_ci adapter->mdiobus->write = lan743x_mdiobus_write_c22; 332462306a36Sopenharmony_ci adapter->mdiobus->name = "lan743x-mdiobus"; 332562306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, 332662306a36Sopenharmony_ci "lan743x-mdiobus\n"); 332762306a36Sopenharmony_ci } 332862306a36Sopenharmony_ci } else { 332962306a36Sopenharmony_ci adapter->mdiobus->read = lan743x_mdiobus_read_c22; 333062306a36Sopenharmony_ci adapter->mdiobus->write = lan743x_mdiobus_write_c22; 333162306a36Sopenharmony_ci adapter->mdiobus->name = "lan743x-mdiobus"; 333262306a36Sopenharmony_ci netif_dbg(adapter, drv, adapter->netdev, "lan743x-mdiobus\n"); 333362306a36Sopenharmony_ci } 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ci snprintf(adapter->mdiobus->id, MII_BUS_ID_SIZE, 333662306a36Sopenharmony_ci "pci-%s", pci_name(adapter->pdev)); 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci if ((adapter->csr.id_rev & ID_REV_ID_MASK_) == ID_REV_ID_LAN7430_) 333962306a36Sopenharmony_ci /* LAN7430 uses internal phy at address 1 */ 334062306a36Sopenharmony_ci adapter->mdiobus->phy_mask = ~(u32)BIT(1); 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci /* register mdiobus */ 334362306a36Sopenharmony_ci ret = mdiobus_register(adapter->mdiobus); 334462306a36Sopenharmony_ci if (ret < 0) 334562306a36Sopenharmony_ci goto return_error; 334662306a36Sopenharmony_ci return 0; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_cireturn_error: 334962306a36Sopenharmony_ci return ret; 335062306a36Sopenharmony_ci} 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci/* lan743x_pcidev_probe - Device Initialization Routine 335362306a36Sopenharmony_ci * @pdev: PCI device information struct 335462306a36Sopenharmony_ci * @id: entry in lan743x_pci_tbl 335562306a36Sopenharmony_ci * 335662306a36Sopenharmony_ci * Returns 0 on success, negative on failure 335762306a36Sopenharmony_ci * 335862306a36Sopenharmony_ci * initializes an adapter identified by a pci_dev structure. 335962306a36Sopenharmony_ci * The OS initialization, configuring of the adapter private structure, 336062306a36Sopenharmony_ci * and a hardware reset occur. 336162306a36Sopenharmony_ci **/ 336262306a36Sopenharmony_cistatic int lan743x_pcidev_probe(struct pci_dev *pdev, 336362306a36Sopenharmony_ci const struct pci_device_id *id) 336462306a36Sopenharmony_ci{ 336562306a36Sopenharmony_ci struct lan743x_adapter *adapter = NULL; 336662306a36Sopenharmony_ci struct net_device *netdev = NULL; 336762306a36Sopenharmony_ci int ret = -ENODEV; 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci if (id->device == PCI_DEVICE_ID_SMSC_A011 || 337062306a36Sopenharmony_ci id->device == PCI_DEVICE_ID_SMSC_A041) { 337162306a36Sopenharmony_ci netdev = devm_alloc_etherdev_mqs(&pdev->dev, 337262306a36Sopenharmony_ci sizeof(struct lan743x_adapter), 337362306a36Sopenharmony_ci PCI11X1X_USED_TX_CHANNELS, 337462306a36Sopenharmony_ci LAN743X_USED_RX_CHANNELS); 337562306a36Sopenharmony_ci } else { 337662306a36Sopenharmony_ci netdev = devm_alloc_etherdev_mqs(&pdev->dev, 337762306a36Sopenharmony_ci sizeof(struct lan743x_adapter), 337862306a36Sopenharmony_ci LAN743X_USED_TX_CHANNELS, 337962306a36Sopenharmony_ci LAN743X_USED_RX_CHANNELS); 338062306a36Sopenharmony_ci } 338162306a36Sopenharmony_ci 338262306a36Sopenharmony_ci if (!netdev) 338362306a36Sopenharmony_ci goto return_error; 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 338662306a36Sopenharmony_ci pci_set_drvdata(pdev, netdev); 338762306a36Sopenharmony_ci adapter = netdev_priv(netdev); 338862306a36Sopenharmony_ci adapter->netdev = netdev; 338962306a36Sopenharmony_ci adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE | 339062306a36Sopenharmony_ci NETIF_MSG_LINK | NETIF_MSG_IFUP | 339162306a36Sopenharmony_ci NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED; 339262306a36Sopenharmony_ci netdev->max_mtu = LAN743X_MAX_FRAME_SIZE; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci of_get_mac_address(pdev->dev.of_node, adapter->mac_address); 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci ret = lan743x_pci_init(adapter, pdev); 339762306a36Sopenharmony_ci if (ret) 339862306a36Sopenharmony_ci goto return_error; 339962306a36Sopenharmony_ci 340062306a36Sopenharmony_ci ret = lan743x_csr_init(adapter); 340162306a36Sopenharmony_ci if (ret) 340262306a36Sopenharmony_ci goto cleanup_pci; 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci ret = lan743x_hardware_init(adapter, pdev); 340562306a36Sopenharmony_ci if (ret) 340662306a36Sopenharmony_ci goto cleanup_pci; 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci ret = lan743x_mdiobus_init(adapter); 340962306a36Sopenharmony_ci if (ret) 341062306a36Sopenharmony_ci goto cleanup_hardware; 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci adapter->netdev->netdev_ops = &lan743x_netdev_ops; 341362306a36Sopenharmony_ci adapter->netdev->ethtool_ops = &lan743x_ethtool_ops; 341462306a36Sopenharmony_ci adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO | 341562306a36Sopenharmony_ci NETIF_F_HW_CSUM | NETIF_F_RXCSUM; 341662306a36Sopenharmony_ci adapter->netdev->hw_features = adapter->netdev->features; 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci /* carrier off reporting is important to ethtool even BEFORE open */ 341962306a36Sopenharmony_ci netif_carrier_off(netdev); 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci ret = register_netdev(adapter->netdev); 342262306a36Sopenharmony_ci if (ret < 0) 342362306a36Sopenharmony_ci goto cleanup_mdiobus; 342462306a36Sopenharmony_ci return 0; 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_cicleanup_mdiobus: 342762306a36Sopenharmony_ci lan743x_mdiobus_cleanup(adapter); 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_cicleanup_hardware: 343062306a36Sopenharmony_ci lan743x_hardware_cleanup(adapter); 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_cicleanup_pci: 343362306a36Sopenharmony_ci lan743x_pci_cleanup(adapter); 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_cireturn_error: 343662306a36Sopenharmony_ci pr_warn("Initialization failed\n"); 343762306a36Sopenharmony_ci return ret; 343862306a36Sopenharmony_ci} 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci/** 344162306a36Sopenharmony_ci * lan743x_pcidev_remove - Device Removal Routine 344262306a36Sopenharmony_ci * @pdev: PCI device information struct 344362306a36Sopenharmony_ci * 344462306a36Sopenharmony_ci * this is called by the PCI subsystem to alert the driver 344562306a36Sopenharmony_ci * that it should release a PCI device. This could be caused by a 344662306a36Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from 344762306a36Sopenharmony_ci * memory. 344862306a36Sopenharmony_ci **/ 344962306a36Sopenharmony_cistatic void lan743x_pcidev_remove(struct pci_dev *pdev) 345062306a36Sopenharmony_ci{ 345162306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 345262306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci lan743x_full_cleanup(adapter); 345562306a36Sopenharmony_ci} 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_cistatic void lan743x_pcidev_shutdown(struct pci_dev *pdev) 345862306a36Sopenharmony_ci{ 345962306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 346062306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci rtnl_lock(); 346362306a36Sopenharmony_ci netif_device_detach(netdev); 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci /* close netdev when netdev is at running state. 346662306a36Sopenharmony_ci * For instance, it is true when system goes to sleep by pm-suspend 346762306a36Sopenharmony_ci * However, it is false when system goes to sleep by suspend GUI menu 346862306a36Sopenharmony_ci */ 346962306a36Sopenharmony_ci if (netif_running(netdev)) 347062306a36Sopenharmony_ci lan743x_netdev_close(netdev); 347162306a36Sopenharmony_ci rtnl_unlock(); 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_ci#ifdef CONFIG_PM 347462306a36Sopenharmony_ci pci_save_state(pdev); 347562306a36Sopenharmony_ci#endif 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci /* clean up lan743x portion */ 347862306a36Sopenharmony_ci lan743x_hardware_cleanup(adapter); 347962306a36Sopenharmony_ci} 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 348262306a36Sopenharmony_cistatic u16 lan743x_pm_wakeframe_crc16(const u8 *buf, int len) 348362306a36Sopenharmony_ci{ 348462306a36Sopenharmony_ci return bitrev16(crc16(0xFFFF, buf, len)); 348562306a36Sopenharmony_ci} 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_cistatic void lan743x_pm_set_wol(struct lan743x_adapter *adapter) 348862306a36Sopenharmony_ci{ 348962306a36Sopenharmony_ci const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E }; 349062306a36Sopenharmony_ci const u8 ipv6_multicast[3] = { 0x33, 0x33 }; 349162306a36Sopenharmony_ci const u8 arp_type[2] = { 0x08, 0x06 }; 349262306a36Sopenharmony_ci int mask_index; 349362306a36Sopenharmony_ci u32 sopass; 349462306a36Sopenharmony_ci u32 pmtctl; 349562306a36Sopenharmony_ci u32 wucsr; 349662306a36Sopenharmony_ci u32 macrx; 349762306a36Sopenharmony_ci u16 crc; 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci for (mask_index = 0; mask_index < MAC_NUM_OF_WUF_CFG; mask_index++) 350062306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 0); 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci /* clear wake settings */ 350362306a36Sopenharmony_ci pmtctl = lan743x_csr_read(adapter, PMT_CTL); 350462306a36Sopenharmony_ci pmtctl |= PMT_CTL_WUPS_MASK_; 350562306a36Sopenharmony_ci pmtctl &= ~(PMT_CTL_GPIO_WAKEUP_EN_ | PMT_CTL_EEE_WAKEUP_EN_ | 350662306a36Sopenharmony_ci PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ | 350762306a36Sopenharmony_ci PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ | PMT_CTL_ETH_PHY_WAKE_EN_); 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci macrx = lan743x_csr_read(adapter, MAC_RX); 351062306a36Sopenharmony_ci 351162306a36Sopenharmony_ci wucsr = 0; 351262306a36Sopenharmony_ci mask_index = 0; 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci pmtctl |= PMT_CTL_ETH_PHY_D3_COLD_OVR_ | PMT_CTL_ETH_PHY_D3_OVR_; 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci if (adapter->wolopts & WAKE_PHY) { 351762306a36Sopenharmony_ci pmtctl |= PMT_CTL_ETH_PHY_EDPD_PLL_CTL_; 351862306a36Sopenharmony_ci pmtctl |= PMT_CTL_ETH_PHY_WAKE_EN_; 351962306a36Sopenharmony_ci } 352062306a36Sopenharmony_ci if (adapter->wolopts & WAKE_MAGIC) { 352162306a36Sopenharmony_ci wucsr |= MAC_WUCSR_MPEN_; 352262306a36Sopenharmony_ci macrx |= MAC_RX_RXEN_; 352362306a36Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 352462306a36Sopenharmony_ci } 352562306a36Sopenharmony_ci if (adapter->wolopts & WAKE_UCAST) { 352662306a36Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_PFDA_EN_; 352762306a36Sopenharmony_ci macrx |= MAC_RX_RXEN_; 352862306a36Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 352962306a36Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 353062306a36Sopenharmony_ci } 353162306a36Sopenharmony_ci if (adapter->wolopts & WAKE_BCAST) { 353262306a36Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_BCST_EN_; 353362306a36Sopenharmony_ci macrx |= MAC_RX_RXEN_; 353462306a36Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 353562306a36Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 353662306a36Sopenharmony_ci } 353762306a36Sopenharmony_ci if (adapter->wolopts & WAKE_MCAST) { 353862306a36Sopenharmony_ci /* IPv4 multicast */ 353962306a36Sopenharmony_ci crc = lan743x_pm_wakeframe_crc16(ipv4_multicast, 3); 354062306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 354162306a36Sopenharmony_ci MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ | 354262306a36Sopenharmony_ci (0 << MAC_WUF_CFG_OFFSET_SHIFT_) | 354362306a36Sopenharmony_ci (crc & MAC_WUF_CFG_CRC16_MASK_)); 354462306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 7); 354562306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0); 354662306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0); 354762306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0); 354862306a36Sopenharmony_ci mask_index++; 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_ci /* IPv6 multicast */ 355162306a36Sopenharmony_ci crc = lan743x_pm_wakeframe_crc16(ipv6_multicast, 2); 355262306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 355362306a36Sopenharmony_ci MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ | 355462306a36Sopenharmony_ci (0 << MAC_WUF_CFG_OFFSET_SHIFT_) | 355562306a36Sopenharmony_ci (crc & MAC_WUF_CFG_CRC16_MASK_)); 355662306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 3); 355762306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0); 355862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0); 355962306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0); 356062306a36Sopenharmony_ci mask_index++; 356162306a36Sopenharmony_ci 356262306a36Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_; 356362306a36Sopenharmony_ci macrx |= MAC_RX_RXEN_; 356462306a36Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 356562306a36Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 356662306a36Sopenharmony_ci } 356762306a36Sopenharmony_ci if (adapter->wolopts & WAKE_ARP) { 356862306a36Sopenharmony_ci /* set MAC_WUF_CFG & WUF_MASK 356962306a36Sopenharmony_ci * for packettype (offset 12,13) = ARP (0x0806) 357062306a36Sopenharmony_ci */ 357162306a36Sopenharmony_ci crc = lan743x_pm_wakeframe_crc16(arp_type, 2); 357262306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 357362306a36Sopenharmony_ci MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_ALL_ | 357462306a36Sopenharmony_ci (0 << MAC_WUF_CFG_OFFSET_SHIFT_) | 357562306a36Sopenharmony_ci (crc & MAC_WUF_CFG_CRC16_MASK_)); 357662306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 0x3000); 357762306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0); 357862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0); 357962306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0); 358062306a36Sopenharmony_ci mask_index++; 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_; 358362306a36Sopenharmony_ci macrx |= MAC_RX_RXEN_; 358462306a36Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 358562306a36Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 358662306a36Sopenharmony_ci } 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci if (adapter->wolopts & WAKE_MAGICSECURE) { 358962306a36Sopenharmony_ci sopass = *(u32 *)adapter->sopass; 359062306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MP_SO_LO, sopass); 359162306a36Sopenharmony_ci sopass = *(u16 *)&adapter->sopass[4]; 359262306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_MP_SO_HI, sopass); 359362306a36Sopenharmony_ci wucsr |= MAC_MP_SO_EN_; 359462306a36Sopenharmony_ci } 359562306a36Sopenharmony_ci 359662306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUCSR, wucsr); 359762306a36Sopenharmony_ci lan743x_csr_write(adapter, PMT_CTL, pmtctl); 359862306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, macrx); 359962306a36Sopenharmony_ci} 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_cistatic int lan743x_pm_suspend(struct device *dev) 360262306a36Sopenharmony_ci{ 360362306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 360462306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 360562306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 360662306a36Sopenharmony_ci u32 data; 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci lan743x_pcidev_shutdown(pdev); 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci /* clear all wakes */ 361162306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUCSR, 0); 361262306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUCSR2, 0); 361362306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_WK_SRC, 0xFFFFFFFF); 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci if (adapter->wolopts) 361662306a36Sopenharmony_ci lan743x_pm_set_wol(adapter); 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci if (adapter->is_pci11x1x) { 361962306a36Sopenharmony_ci /* Save HW_CFG to config again in PM resume */ 362062306a36Sopenharmony_ci data = lan743x_csr_read(adapter, HW_CFG); 362162306a36Sopenharmony_ci adapter->hw_cfg = data; 362262306a36Sopenharmony_ci data |= (HW_CFG_RST_PROTECT_PCIE_ | 362362306a36Sopenharmony_ci HW_CFG_D3_RESET_DIS_ | 362462306a36Sopenharmony_ci HW_CFG_D3_VAUX_OVR_ | 362562306a36Sopenharmony_ci HW_CFG_HOT_RESET_DIS_ | 362662306a36Sopenharmony_ci HW_CFG_RST_PROTECT_); 362762306a36Sopenharmony_ci lan743x_csr_write(adapter, HW_CFG, data); 362862306a36Sopenharmony_ci } 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci /* Host sets PME_En, put D3hot */ 363162306a36Sopenharmony_ci return pci_prepare_to_sleep(pdev); 363262306a36Sopenharmony_ci} 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_cistatic int lan743x_pm_resume(struct device *dev) 363562306a36Sopenharmony_ci{ 363662306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 363762306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 363862306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 363962306a36Sopenharmony_ci int ret; 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 364262306a36Sopenharmony_ci pci_restore_state(pdev); 364362306a36Sopenharmony_ci pci_save_state(pdev); 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci /* Restore HW_CFG that was saved during pm suspend */ 364662306a36Sopenharmony_ci if (adapter->is_pci11x1x) 364762306a36Sopenharmony_ci lan743x_csr_write(adapter, HW_CFG, adapter->hw_cfg); 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ci ret = lan743x_hardware_init(adapter, pdev); 365062306a36Sopenharmony_ci if (ret) { 365162306a36Sopenharmony_ci netif_err(adapter, probe, adapter->netdev, 365262306a36Sopenharmony_ci "lan743x_hardware_init returned %d\n", ret); 365362306a36Sopenharmony_ci lan743x_pci_cleanup(adapter); 365462306a36Sopenharmony_ci return ret; 365562306a36Sopenharmony_ci } 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci /* open netdev when netdev is at running state while resume. 365862306a36Sopenharmony_ci * For instance, it is true when system wakesup after pm-suspend 365962306a36Sopenharmony_ci * However, it is false when system wakes up after suspend GUI menu 366062306a36Sopenharmony_ci */ 366162306a36Sopenharmony_ci if (netif_running(netdev)) 366262306a36Sopenharmony_ci lan743x_netdev_open(netdev); 366362306a36Sopenharmony_ci 366462306a36Sopenharmony_ci netif_device_attach(netdev); 366562306a36Sopenharmony_ci ret = lan743x_csr_read(adapter, MAC_WK_SRC); 366662306a36Sopenharmony_ci netif_info(adapter, drv, adapter->netdev, 366762306a36Sopenharmony_ci "Wakeup source : 0x%08X\n", ret); 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci return 0; 367062306a36Sopenharmony_ci} 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_cistatic const struct dev_pm_ops lan743x_pm_ops = { 367362306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(lan743x_pm_suspend, lan743x_pm_resume) 367462306a36Sopenharmony_ci}; 367562306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_cistatic const struct pci_device_id lan743x_pcidev_tbl[] = { 367862306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7430) }, 367962306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7431) }, 368062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_A011) }, 368162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_A041) }, 368262306a36Sopenharmony_ci { 0, } 368362306a36Sopenharmony_ci}; 368462306a36Sopenharmony_ci 368562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, lan743x_pcidev_tbl); 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_cistatic struct pci_driver lan743x_pcidev_driver = { 368862306a36Sopenharmony_ci .name = DRIVER_NAME, 368962306a36Sopenharmony_ci .id_table = lan743x_pcidev_tbl, 369062306a36Sopenharmony_ci .probe = lan743x_pcidev_probe, 369162306a36Sopenharmony_ci .remove = lan743x_pcidev_remove, 369262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 369362306a36Sopenharmony_ci .driver.pm = &lan743x_pm_ops, 369462306a36Sopenharmony_ci#endif 369562306a36Sopenharmony_ci .shutdown = lan743x_pcidev_shutdown, 369662306a36Sopenharmony_ci}; 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_cimodule_pci_driver(lan743x_pcidev_driver); 369962306a36Sopenharmony_ci 370062306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 370162306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 370262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3703