18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */ 28c2ecf20Sopenharmony_ci/* Copyright (C) 2018 Microchip Technology Inc. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/module.h> 58c2ecf20Sopenharmony_ci#include <linux/pci.h> 68c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 78c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 88c2ecf20Sopenharmony_ci#include <linux/crc32.h> 98c2ecf20Sopenharmony_ci#include <linux/microchipphy.h> 108c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 118c2ecf20Sopenharmony_ci#include <linux/of_mdio.h> 128c2ecf20Sopenharmony_ci#include <linux/of_net.h> 138c2ecf20Sopenharmony_ci#include <linux/phy.h> 148c2ecf20Sopenharmony_ci#include <linux/phy_fixed.h> 158c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 168c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 178c2ecf20Sopenharmony_ci#include <linux/crc16.h> 188c2ecf20Sopenharmony_ci#include "lan743x_main.h" 198c2ecf20Sopenharmony_ci#include "lan743x_ethtool.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic void lan743x_pci_cleanup(struct lan743x_adapter *adapter) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci pci_release_selected_regions(adapter->pdev, 248c2ecf20Sopenharmony_ci pci_select_bars(adapter->pdev, 258c2ecf20Sopenharmony_ci IORESOURCE_MEM)); 268c2ecf20Sopenharmony_ci pci_disable_device(adapter->pdev); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int lan743x_pci_init(struct lan743x_adapter *adapter, 308c2ecf20Sopenharmony_ci struct pci_dev *pdev) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci unsigned long bars = 0; 338c2ecf20Sopenharmony_ci int ret; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci adapter->pdev = pdev; 368c2ecf20Sopenharmony_ci ret = pci_enable_device_mem(pdev); 378c2ecf20Sopenharmony_ci if (ret) 388c2ecf20Sopenharmony_ci goto return_error; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci netif_info(adapter, probe, adapter->netdev, 418c2ecf20Sopenharmony_ci "PCI: Vendor ID = 0x%04X, Device ID = 0x%04X\n", 428c2ecf20Sopenharmony_ci pdev->vendor, pdev->device); 438c2ecf20Sopenharmony_ci bars = pci_select_bars(pdev, IORESOURCE_MEM); 448c2ecf20Sopenharmony_ci if (!test_bit(0, &bars)) 458c2ecf20Sopenharmony_ci goto disable_device; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci ret = pci_request_selected_regions(pdev, bars, DRIVER_NAME); 488c2ecf20Sopenharmony_ci if (ret) 498c2ecf20Sopenharmony_ci goto disable_device; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci pci_set_master(pdev); 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cidisable_device: 558c2ecf20Sopenharmony_ci pci_disable_device(adapter->pdev); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cireturn_error: 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciu32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return ioread32(&adapter->csr.csr_address[offset]); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid lan743x_csr_write(struct lan743x_adapter *adapter, int offset, 678c2ecf20Sopenharmony_ci u32 data) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci iowrite32(data, &adapter->csr.csr_address[offset]); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define LAN743X_CSR_READ_OP(offset) lan743x_csr_read(adapter, offset) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int lan743x_csr_light_reset(struct lan743x_adapter *adapter) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci u32 data; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci data = lan743x_csr_read(adapter, HW_CFG); 798c2ecf20Sopenharmony_ci data |= HW_CFG_LRST_; 808c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, HW_CFG, data); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, HW_CFG, data, 838c2ecf20Sopenharmony_ci !(data & HW_CFG_LRST_), 100000, 10000000); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int lan743x_csr_wait_for_bit_atomic(struct lan743x_adapter *adapter, 878c2ecf20Sopenharmony_ci int offset, u32 bit_mask, 888c2ecf20Sopenharmony_ci int target_value, int udelay_min, 898c2ecf20Sopenharmony_ci int udelay_max, int count) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci u32 data; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return readx_poll_timeout_atomic(LAN743X_CSR_READ_OP, offset, data, 948c2ecf20Sopenharmony_ci target_value == !!(data & bit_mask), 958c2ecf20Sopenharmony_ci udelay_max, udelay_min * count); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int lan743x_csr_wait_for_bit(struct lan743x_adapter *adapter, 998c2ecf20Sopenharmony_ci int offset, u32 bit_mask, 1008c2ecf20Sopenharmony_ci int target_value, int usleep_min, 1018c2ecf20Sopenharmony_ci int usleep_max, int count) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci u32 data; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, offset, data, 1068c2ecf20Sopenharmony_ci target_value == ((data & bit_mask) ? 1 : 0), 1078c2ecf20Sopenharmony_ci usleep_max, usleep_min * count); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int lan743x_csr_init(struct lan743x_adapter *adapter) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct lan743x_csr *csr = &adapter->csr; 1138c2ecf20Sopenharmony_ci resource_size_t bar_start, bar_length; 1148c2ecf20Sopenharmony_ci int result; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci bar_start = pci_resource_start(adapter->pdev, 0); 1178c2ecf20Sopenharmony_ci bar_length = pci_resource_len(adapter->pdev, 0); 1188c2ecf20Sopenharmony_ci csr->csr_address = devm_ioremap(&adapter->pdev->dev, 1198c2ecf20Sopenharmony_ci bar_start, bar_length); 1208c2ecf20Sopenharmony_ci if (!csr->csr_address) { 1218c2ecf20Sopenharmony_ci result = -ENOMEM; 1228c2ecf20Sopenharmony_ci goto clean_up; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci csr->id_rev = lan743x_csr_read(adapter, ID_REV); 1268c2ecf20Sopenharmony_ci csr->fpga_rev = lan743x_csr_read(adapter, FPGA_REV); 1278c2ecf20Sopenharmony_ci netif_info(adapter, probe, adapter->netdev, 1288c2ecf20Sopenharmony_ci "ID_REV = 0x%08X, FPGA_REV = %d.%d\n", 1298c2ecf20Sopenharmony_ci csr->id_rev, FPGA_REV_GET_MAJOR_(csr->fpga_rev), 1308c2ecf20Sopenharmony_ci FPGA_REV_GET_MINOR_(csr->fpga_rev)); 1318c2ecf20Sopenharmony_ci if (!ID_REV_IS_VALID_CHIP_ID_(csr->id_rev)) { 1328c2ecf20Sopenharmony_ci result = -ENODEV; 1338c2ecf20Sopenharmony_ci goto clean_up; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci csr->flags = LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR; 1378c2ecf20Sopenharmony_ci switch (csr->id_rev & ID_REV_CHIP_REV_MASK_) { 1388c2ecf20Sopenharmony_ci case ID_REV_CHIP_REV_A0_: 1398c2ecf20Sopenharmony_ci csr->flags |= LAN743X_CSR_FLAG_IS_A0; 1408c2ecf20Sopenharmony_ci csr->flags &= ~LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR; 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci case ID_REV_CHIP_REV_B0_: 1438c2ecf20Sopenharmony_ci csr->flags |= LAN743X_CSR_FLAG_IS_B0; 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci result = lan743x_csr_light_reset(adapter); 1488c2ecf20Sopenharmony_ci if (result) 1498c2ecf20Sopenharmony_ci goto clean_up; 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ciclean_up: 1528c2ecf20Sopenharmony_ci return result; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void lan743x_intr_software_isr(void *context) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = context; 1588c2ecf20Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 1598c2ecf20Sopenharmony_ci u32 int_sts; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci int_sts = lan743x_csr_read(adapter, INT_STS); 1628c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_SW_GP_) { 1638c2ecf20Sopenharmony_ci /* disable the interrupt to prevent repeated re-triggering */ 1648c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_); 1658c2ecf20Sopenharmony_ci intr->software_isr_flag = 1; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void lan743x_tx_isr(void *context, u32 int_sts, u32 flags) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct lan743x_tx *tx = context; 1728c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 1738c2ecf20Sopenharmony_ci bool enable_flag = true; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, INT_EN_SET); 1768c2ecf20Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) { 1778c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 1788c2ecf20Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_DMA_TX_(tx->channel_number)) { 1828c2ecf20Sopenharmony_ci u32 ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number); 1838c2ecf20Sopenharmony_ci u32 dmac_int_sts; 1848c2ecf20Sopenharmony_ci u32 dmac_int_en; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) 1878c2ecf20Sopenharmony_ci dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS); 1888c2ecf20Sopenharmony_ci else 1898c2ecf20Sopenharmony_ci dmac_int_sts = ioc_bit; 1908c2ecf20Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) 1918c2ecf20Sopenharmony_ci dmac_int_en = lan743x_csr_read(adapter, 1928c2ecf20Sopenharmony_ci DMAC_INT_EN_SET); 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci dmac_int_en = ioc_bit; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci dmac_int_en &= ioc_bit; 1978c2ecf20Sopenharmony_ci dmac_int_sts &= dmac_int_en; 1988c2ecf20Sopenharmony_ci if (dmac_int_sts & ioc_bit) { 1998c2ecf20Sopenharmony_ci napi_schedule(&tx->napi); 2008c2ecf20Sopenharmony_ci enable_flag = false;/* poll func will enable later */ 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (enable_flag) 2058c2ecf20Sopenharmony_ci /* enable isr */ 2068c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 2078c2ecf20Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void lan743x_rx_isr(void *context, u32 int_sts, u32 flags) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct lan743x_rx *rx = context; 2138c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 2148c2ecf20Sopenharmony_ci bool enable_flag = true; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) { 2178c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 2188c2ecf20Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_DMA_RX_(rx->channel_number)) { 2228c2ecf20Sopenharmony_ci u32 rx_frame_bit = DMAC_INT_BIT_RXFRM_(rx->channel_number); 2238c2ecf20Sopenharmony_ci u32 dmac_int_sts; 2248c2ecf20Sopenharmony_ci u32 dmac_int_en; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) 2278c2ecf20Sopenharmony_ci dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS); 2288c2ecf20Sopenharmony_ci else 2298c2ecf20Sopenharmony_ci dmac_int_sts = rx_frame_bit; 2308c2ecf20Sopenharmony_ci if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) 2318c2ecf20Sopenharmony_ci dmac_int_en = lan743x_csr_read(adapter, 2328c2ecf20Sopenharmony_ci DMAC_INT_EN_SET); 2338c2ecf20Sopenharmony_ci else 2348c2ecf20Sopenharmony_ci dmac_int_en = rx_frame_bit; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci dmac_int_en &= rx_frame_bit; 2378c2ecf20Sopenharmony_ci dmac_int_sts &= dmac_int_en; 2388c2ecf20Sopenharmony_ci if (dmac_int_sts & rx_frame_bit) { 2398c2ecf20Sopenharmony_ci napi_schedule(&rx->napi); 2408c2ecf20Sopenharmony_ci enable_flag = false;/* poll funct will enable later */ 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (enable_flag) { 2458c2ecf20Sopenharmony_ci /* enable isr */ 2468c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 2478c2ecf20Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void lan743x_intr_shared_isr(void *context, u32 int_sts, u32 flags) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = context; 2548c2ecf20Sopenharmony_ci unsigned int channel; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_ALL_RX_) { 2578c2ecf20Sopenharmony_ci for (channel = 0; channel < LAN743X_USED_RX_CHANNELS; 2588c2ecf20Sopenharmony_ci channel++) { 2598c2ecf20Sopenharmony_ci u32 int_bit = INT_BIT_DMA_RX_(channel); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (int_sts & int_bit) { 2628c2ecf20Sopenharmony_ci lan743x_rx_isr(&adapter->rx[channel], 2638c2ecf20Sopenharmony_ci int_bit, flags); 2648c2ecf20Sopenharmony_ci int_sts &= ~int_bit; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_ALL_TX_) { 2698c2ecf20Sopenharmony_ci for (channel = 0; channel < LAN743X_USED_TX_CHANNELS; 2708c2ecf20Sopenharmony_ci channel++) { 2718c2ecf20Sopenharmony_ci u32 int_bit = INT_BIT_DMA_TX_(channel); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (int_sts & int_bit) { 2748c2ecf20Sopenharmony_ci lan743x_tx_isr(&adapter->tx[channel], 2758c2ecf20Sopenharmony_ci int_bit, flags); 2768c2ecf20Sopenharmony_ci int_sts &= ~int_bit; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_ALL_OTHER_) { 2818c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_SW_GP_) { 2828c2ecf20Sopenharmony_ci lan743x_intr_software_isr(adapter); 2838c2ecf20Sopenharmony_ci int_sts &= ~INT_BIT_SW_GP_; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci if (int_sts & INT_BIT_1588_) { 2868c2ecf20Sopenharmony_ci lan743x_ptp_isr(adapter); 2878c2ecf20Sopenharmony_ci int_sts &= ~INT_BIT_1588_; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci if (int_sts) 2918c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, int_sts); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic irqreturn_t lan743x_intr_entry_isr(int irq, void *ptr) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct lan743x_vector *vector = ptr; 2978c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = vector->adapter; 2988c2ecf20Sopenharmony_ci irqreturn_t result = IRQ_NONE; 2998c2ecf20Sopenharmony_ci u32 int_enables; 3008c2ecf20Sopenharmony_ci u32 int_sts; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) { 3038c2ecf20Sopenharmony_ci int_sts = lan743x_csr_read(adapter, INT_STS); 3048c2ecf20Sopenharmony_ci } else if (vector->flags & 3058c2ecf20Sopenharmony_ci (LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C | 3068c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)) { 3078c2ecf20Sopenharmony_ci int_sts = lan743x_csr_read(adapter, INT_STS_R2C); 3088c2ecf20Sopenharmony_ci } else { 3098c2ecf20Sopenharmony_ci /* use mask as implied status */ 3108c2ecf20Sopenharmony_ci int_sts = vector->int_mask | INT_BIT_MAS_; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!(int_sts & INT_BIT_MAS_)) 3148c2ecf20Sopenharmony_ci goto irq_done; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR) 3178c2ecf20Sopenharmony_ci /* disable vector interrupt */ 3188c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 3198c2ecf20Sopenharmony_ci INT_VEC_EN_CLR, 3208c2ecf20Sopenharmony_ci INT_VEC_EN_(vector->vector_index)); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR) 3238c2ecf20Sopenharmony_ci /* disable master interrupt */ 3248c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) { 3278c2ecf20Sopenharmony_ci int_enables = lan743x_csr_read(adapter, INT_EN_SET); 3288c2ecf20Sopenharmony_ci } else { 3298c2ecf20Sopenharmony_ci /* use vector mask as implied enable mask */ 3308c2ecf20Sopenharmony_ci int_enables = vector->int_mask; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci int_sts &= int_enables; 3348c2ecf20Sopenharmony_ci int_sts &= vector->int_mask; 3358c2ecf20Sopenharmony_ci if (int_sts) { 3368c2ecf20Sopenharmony_ci if (vector->handler) { 3378c2ecf20Sopenharmony_ci vector->handler(vector->context, 3388c2ecf20Sopenharmony_ci int_sts, vector->flags); 3398c2ecf20Sopenharmony_ci } else { 3408c2ecf20Sopenharmony_ci /* disable interrupts on this vector */ 3418c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 3428c2ecf20Sopenharmony_ci vector->int_mask); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci result = IRQ_HANDLED; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET) 3488c2ecf20Sopenharmony_ci /* enable master interrupt */ 3498c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET) 3528c2ecf20Sopenharmony_ci /* enable vector interrupt */ 3538c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 3548c2ecf20Sopenharmony_ci INT_VEC_EN_SET, 3558c2ecf20Sopenharmony_ci INT_VEC_EN_(vector->vector_index)); 3568c2ecf20Sopenharmony_ciirq_done: 3578c2ecf20Sopenharmony_ci return result; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int lan743x_intr_test_isr(struct lan743x_adapter *adapter) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 3638c2ecf20Sopenharmony_ci int result = -ENODEV; 3648c2ecf20Sopenharmony_ci int timeout = 10; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci intr->software_isr_flag = 0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* enable interrupt */ 3698c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_SW_GP_); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* activate interrupt here */ 3728c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_SET, INT_BIT_SW_GP_); 3738c2ecf20Sopenharmony_ci while ((timeout > 0) && (!(intr->software_isr_flag))) { 3748c2ecf20Sopenharmony_ci usleep_range(1000, 20000); 3758c2ecf20Sopenharmony_ci timeout--; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (intr->software_isr_flag) 3798c2ecf20Sopenharmony_ci result = 0; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* disable interrupts */ 3828c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_); 3838c2ecf20Sopenharmony_ci return result; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int lan743x_intr_register_isr(struct lan743x_adapter *adapter, 3878c2ecf20Sopenharmony_ci int vector_index, u32 flags, 3888c2ecf20Sopenharmony_ci u32 int_mask, 3898c2ecf20Sopenharmony_ci lan743x_vector_handler handler, 3908c2ecf20Sopenharmony_ci void *context) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct lan743x_vector *vector = &adapter->intr.vector_list 3938c2ecf20Sopenharmony_ci [vector_index]; 3948c2ecf20Sopenharmony_ci int ret; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci vector->adapter = adapter; 3978c2ecf20Sopenharmony_ci vector->flags = flags; 3988c2ecf20Sopenharmony_ci vector->vector_index = vector_index; 3998c2ecf20Sopenharmony_ci vector->int_mask = int_mask; 4008c2ecf20Sopenharmony_ci vector->handler = handler; 4018c2ecf20Sopenharmony_ci vector->context = context; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci ret = request_irq(vector->irq, 4048c2ecf20Sopenharmony_ci lan743x_intr_entry_isr, 4058c2ecf20Sopenharmony_ci (flags & LAN743X_VECTOR_FLAG_IRQ_SHARED) ? 4068c2ecf20Sopenharmony_ci IRQF_SHARED : 0, DRIVER_NAME, vector); 4078c2ecf20Sopenharmony_ci if (ret) { 4088c2ecf20Sopenharmony_ci vector->handler = NULL; 4098c2ecf20Sopenharmony_ci vector->context = NULL; 4108c2ecf20Sopenharmony_ci vector->int_mask = 0; 4118c2ecf20Sopenharmony_ci vector->flags = 0; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci return ret; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void lan743x_intr_unregister_isr(struct lan743x_adapter *adapter, 4178c2ecf20Sopenharmony_ci int vector_index) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct lan743x_vector *vector = &adapter->intr.vector_list 4208c2ecf20Sopenharmony_ci [vector_index]; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci free_irq(vector->irq, vector); 4238c2ecf20Sopenharmony_ci vector->handler = NULL; 4248c2ecf20Sopenharmony_ci vector->context = NULL; 4258c2ecf20Sopenharmony_ci vector->int_mask = 0; 4268c2ecf20Sopenharmony_ci vector->flags = 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic u32 lan743x_intr_get_vector_flags(struct lan743x_adapter *adapter, 4308c2ecf20Sopenharmony_ci u32 int_mask) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci int index; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci for (index = 0; index < LAN743X_MAX_VECTOR_COUNT; index++) { 4358c2ecf20Sopenharmony_ci if (adapter->intr.vector_list[index].int_mask & int_mask) 4368c2ecf20Sopenharmony_ci return adapter->intr.vector_list[index].flags; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void lan743x_intr_close(struct lan743x_adapter *adapter) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 4448c2ecf20Sopenharmony_ci int index = 0; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_); 4478c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x000000FF); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci for (index = 0; index < LAN743X_MAX_VECTOR_COUNT; index++) { 4508c2ecf20Sopenharmony_ci if (intr->flags & INTR_FLAG_IRQ_REQUESTED(index)) { 4518c2ecf20Sopenharmony_ci lan743x_intr_unregister_isr(adapter, index); 4528c2ecf20Sopenharmony_ci intr->flags &= ~INTR_FLAG_IRQ_REQUESTED(index); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (intr->flags & INTR_FLAG_MSI_ENABLED) { 4578c2ecf20Sopenharmony_ci pci_disable_msi(adapter->pdev); 4588c2ecf20Sopenharmony_ci intr->flags &= ~INTR_FLAG_MSI_ENABLED; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (intr->flags & INTR_FLAG_MSIX_ENABLED) { 4628c2ecf20Sopenharmony_ci pci_disable_msix(adapter->pdev); 4638c2ecf20Sopenharmony_ci intr->flags &= ~INTR_FLAG_MSIX_ENABLED; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int lan743x_intr_open(struct lan743x_adapter *adapter) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct msix_entry msix_entries[LAN743X_MAX_VECTOR_COUNT]; 4708c2ecf20Sopenharmony_ci struct lan743x_intr *intr = &adapter->intr; 4718c2ecf20Sopenharmony_ci u32 int_vec_en_auto_clr = 0; 4728c2ecf20Sopenharmony_ci u32 int_vec_map0 = 0; 4738c2ecf20Sopenharmony_ci u32 int_vec_map1 = 0; 4748c2ecf20Sopenharmony_ci int ret = -ENODEV; 4758c2ecf20Sopenharmony_ci int index = 0; 4768c2ecf20Sopenharmony_ci u32 flags = 0; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci intr->number_of_vectors = 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Try to set up MSIX interrupts */ 4818c2ecf20Sopenharmony_ci memset(&msix_entries[0], 0, 4828c2ecf20Sopenharmony_ci sizeof(struct msix_entry) * LAN743X_MAX_VECTOR_COUNT); 4838c2ecf20Sopenharmony_ci for (index = 0; index < LAN743X_MAX_VECTOR_COUNT; index++) 4848c2ecf20Sopenharmony_ci msix_entries[index].entry = index; 4858c2ecf20Sopenharmony_ci ret = pci_enable_msix_range(adapter->pdev, 4868c2ecf20Sopenharmony_ci msix_entries, 1, 4878c2ecf20Sopenharmony_ci 1 + LAN743X_USED_TX_CHANNELS + 4888c2ecf20Sopenharmony_ci LAN743X_USED_RX_CHANNELS); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (ret > 0) { 4918c2ecf20Sopenharmony_ci intr->flags |= INTR_FLAG_MSIX_ENABLED; 4928c2ecf20Sopenharmony_ci intr->number_of_vectors = ret; 4938c2ecf20Sopenharmony_ci intr->using_vectors = true; 4948c2ecf20Sopenharmony_ci for (index = 0; index < intr->number_of_vectors; index++) 4958c2ecf20Sopenharmony_ci intr->vector_list[index].irq = msix_entries 4968c2ecf20Sopenharmony_ci [index].vector; 4978c2ecf20Sopenharmony_ci netif_info(adapter, ifup, adapter->netdev, 4988c2ecf20Sopenharmony_ci "using MSIX interrupts, number of vectors = %d\n", 4998c2ecf20Sopenharmony_ci intr->number_of_vectors); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* If MSIX failed try to setup using MSI interrupts */ 5038c2ecf20Sopenharmony_ci if (!intr->number_of_vectors) { 5048c2ecf20Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 5058c2ecf20Sopenharmony_ci if (!pci_enable_msi(adapter->pdev)) { 5068c2ecf20Sopenharmony_ci intr->flags |= INTR_FLAG_MSI_ENABLED; 5078c2ecf20Sopenharmony_ci intr->number_of_vectors = 1; 5088c2ecf20Sopenharmony_ci intr->using_vectors = true; 5098c2ecf20Sopenharmony_ci intr->vector_list[0].irq = 5108c2ecf20Sopenharmony_ci adapter->pdev->irq; 5118c2ecf20Sopenharmony_ci netif_info(adapter, ifup, adapter->netdev, 5128c2ecf20Sopenharmony_ci "using MSI interrupts, number of vectors = %d\n", 5138c2ecf20Sopenharmony_ci intr->number_of_vectors); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* If MSIX, and MSI failed, setup using legacy interrupt */ 5198c2ecf20Sopenharmony_ci if (!intr->number_of_vectors) { 5208c2ecf20Sopenharmony_ci intr->number_of_vectors = 1; 5218c2ecf20Sopenharmony_ci intr->using_vectors = false; 5228c2ecf20Sopenharmony_ci intr->vector_list[0].irq = intr->irq; 5238c2ecf20Sopenharmony_ci netif_info(adapter, ifup, adapter->netdev, 5248c2ecf20Sopenharmony_ci "using legacy interrupts\n"); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* At this point we must have at least one irq */ 5288c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0xFFFFFFFF); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* map all interrupts to vector 0 */ 5318c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP0, 0x00000000); 5328c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP1, 0x00000000); 5338c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP2, 0x00000000); 5348c2ecf20Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ | 5358c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C | 5368c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK | 5378c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (intr->using_vectors) { 5408c2ecf20Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR | 5418c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET; 5428c2ecf20Sopenharmony_ci } else { 5438c2ecf20Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR | 5448c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET | 5458c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_IRQ_SHARED; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (adapter->csr.flags & LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) { 5498c2ecf20Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ; 5508c2ecf20Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C; 5518c2ecf20Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR; 5528c2ecf20Sopenharmony_ci flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK; 5538c2ecf20Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C; 5548c2ecf20Sopenharmony_ci flags |= LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ret = lan743x_intr_register_isr(adapter, 0, flags, 5588c2ecf20Sopenharmony_ci INT_BIT_ALL_RX_ | INT_BIT_ALL_TX_ | 5598c2ecf20Sopenharmony_ci INT_BIT_ALL_OTHER_, 5608c2ecf20Sopenharmony_ci lan743x_intr_shared_isr, adapter); 5618c2ecf20Sopenharmony_ci if (ret) 5628c2ecf20Sopenharmony_ci goto clean_up; 5638c2ecf20Sopenharmony_ci intr->flags |= INTR_FLAG_IRQ_REQUESTED(0); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (intr->using_vectors) 5668c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_SET, 5678c2ecf20Sopenharmony_ci INT_VEC_EN_(0)); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 5708c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG0, LAN743X_INT_MOD); 5718c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG1, LAN743X_INT_MOD); 5728c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG2, LAN743X_INT_MOD); 5738c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG3, LAN743X_INT_MOD); 5748c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG4, LAN743X_INT_MOD); 5758c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG5, LAN743X_INT_MOD); 5768c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG6, LAN743X_INT_MOD); 5778c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_CFG7, LAN743X_INT_MOD); 5788c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP0, 0x00005432); 5798c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP1, 0x00000001); 5808c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_MOD_MAP2, 0x00FFFFFF); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* enable interrupts */ 5848c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_); 5858c2ecf20Sopenharmony_ci ret = lan743x_intr_test_isr(adapter); 5868c2ecf20Sopenharmony_ci if (ret) 5878c2ecf20Sopenharmony_ci goto clean_up; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (intr->number_of_vectors > 1) { 5908c2ecf20Sopenharmony_ci int number_of_tx_vectors = intr->number_of_vectors - 1; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (number_of_tx_vectors > LAN743X_USED_TX_CHANNELS) 5938c2ecf20Sopenharmony_ci number_of_tx_vectors = LAN743X_USED_TX_CHANNELS; 5948c2ecf20Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ | 5958c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C | 5968c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK | 5978c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR | 5988c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR | 5998c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (adapter->csr.flags & 6028c2ecf20Sopenharmony_ci LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) { 6038c2ecf20Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET | 6048c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET | 6058c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR | 6068c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci for (index = 0; index < number_of_tx_vectors; index++) { 6108c2ecf20Sopenharmony_ci u32 int_bit = INT_BIT_DMA_TX_(index); 6118c2ecf20Sopenharmony_ci int vector = index + 1; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* map TX interrupt to vector */ 6148c2ecf20Sopenharmony_ci int_vec_map1 |= INT_VEC_MAP1_TX_VEC_(index, vector); 6158c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP1, int_vec_map1); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Remove TX interrupt from shared mask */ 6188c2ecf20Sopenharmony_ci intr->vector_list[0].int_mask &= ~int_bit; 6198c2ecf20Sopenharmony_ci ret = lan743x_intr_register_isr(adapter, vector, flags, 6208c2ecf20Sopenharmony_ci int_bit, lan743x_tx_isr, 6218c2ecf20Sopenharmony_ci &adapter->tx[index]); 6228c2ecf20Sopenharmony_ci if (ret) 6238c2ecf20Sopenharmony_ci goto clean_up; 6248c2ecf20Sopenharmony_ci intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector); 6258c2ecf20Sopenharmony_ci if (!(flags & 6268c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET)) 6278c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_SET, 6288c2ecf20Sopenharmony_ci INT_VEC_EN_(vector)); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci if ((intr->number_of_vectors - LAN743X_USED_TX_CHANNELS) > 1) { 6328c2ecf20Sopenharmony_ci int number_of_rx_vectors = intr->number_of_vectors - 6338c2ecf20Sopenharmony_ci LAN743X_USED_TX_CHANNELS - 1; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (number_of_rx_vectors > LAN743X_USED_RX_CHANNELS) 6368c2ecf20Sopenharmony_ci number_of_rx_vectors = LAN743X_USED_RX_CHANNELS; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ | 6398c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C | 6408c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK | 6418c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR | 6428c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR | 6438c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (adapter->csr.flags & 6468c2ecf20Sopenharmony_ci LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) { 6478c2ecf20Sopenharmony_ci flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR | 6488c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET | 6498c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET | 6508c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR | 6518c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci for (index = 0; index < number_of_rx_vectors; index++) { 6548c2ecf20Sopenharmony_ci int vector = index + 1 + LAN743X_USED_TX_CHANNELS; 6558c2ecf20Sopenharmony_ci u32 int_bit = INT_BIT_DMA_RX_(index); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* map RX interrupt to vector */ 6588c2ecf20Sopenharmony_ci int_vec_map0 |= INT_VEC_MAP0_RX_VEC_(index, vector); 6598c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_MAP0, int_vec_map0); 6608c2ecf20Sopenharmony_ci if (flags & 6618c2ecf20Sopenharmony_ci LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR) { 6628c2ecf20Sopenharmony_ci int_vec_en_auto_clr |= INT_VEC_EN_(vector); 6638c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_AUTO_CLR, 6648c2ecf20Sopenharmony_ci int_vec_en_auto_clr); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* Remove RX interrupt from shared mask */ 6688c2ecf20Sopenharmony_ci intr->vector_list[0].int_mask &= ~int_bit; 6698c2ecf20Sopenharmony_ci ret = lan743x_intr_register_isr(adapter, vector, flags, 6708c2ecf20Sopenharmony_ci int_bit, lan743x_rx_isr, 6718c2ecf20Sopenharmony_ci &adapter->rx[index]); 6728c2ecf20Sopenharmony_ci if (ret) 6738c2ecf20Sopenharmony_ci goto clean_up; 6748c2ecf20Sopenharmony_ci intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_VEC_EN_SET, 6778c2ecf20Sopenharmony_ci INT_VEC_EN_(vector)); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ciclean_up: 6838c2ecf20Sopenharmony_ci lan743x_intr_close(adapter); 6848c2ecf20Sopenharmony_ci return ret; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic int lan743x_dp_write(struct lan743x_adapter *adapter, 6888c2ecf20Sopenharmony_ci u32 select, u32 addr, u32 length, u32 *buf) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci u32 dp_sel; 6918c2ecf20Sopenharmony_ci int i; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL, DP_SEL_DPRDY_, 6948c2ecf20Sopenharmony_ci 1, 40, 100, 100)) 6958c2ecf20Sopenharmony_ci return -EIO; 6968c2ecf20Sopenharmony_ci dp_sel = lan743x_csr_read(adapter, DP_SEL); 6978c2ecf20Sopenharmony_ci dp_sel &= ~DP_SEL_MASK_; 6988c2ecf20Sopenharmony_ci dp_sel |= select; 6998c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DP_SEL, dp_sel); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 7028c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DP_ADDR, addr + i); 7038c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DP_DATA_0, buf[i]); 7048c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DP_CMD, DP_CMD_WRITE_); 7058c2ecf20Sopenharmony_ci if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL, 7068c2ecf20Sopenharmony_ci DP_SEL_DPRDY_, 7078c2ecf20Sopenharmony_ci 1, 40, 100, 100)) 7088c2ecf20Sopenharmony_ci return -EIO; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic u32 lan743x_mac_mii_access(u16 id, u16 index, int read) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci u32 ret; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) & 7198c2ecf20Sopenharmony_ci MAC_MII_ACC_PHY_ADDR_MASK_; 7208c2ecf20Sopenharmony_ci ret |= (index << MAC_MII_ACC_MIIRINDA_SHIFT_) & 7218c2ecf20Sopenharmony_ci MAC_MII_ACC_MIIRINDA_MASK_; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (read) 7248c2ecf20Sopenharmony_ci ret |= MAC_MII_ACC_MII_READ_; 7258c2ecf20Sopenharmony_ci else 7268c2ecf20Sopenharmony_ci ret |= MAC_MII_ACC_MII_WRITE_; 7278c2ecf20Sopenharmony_ci ret |= MAC_MII_ACC_MII_BUSY_; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return ret; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci u32 data; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, MAC_MII_ACC, data, 7378c2ecf20Sopenharmony_ci !(data & MAC_MII_ACC_MII_BUSY_), 0, 1000000); 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic int lan743x_mdiobus_read(struct mii_bus *bus, int phy_id, int index) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = bus->priv; 7438c2ecf20Sopenharmony_ci u32 val, mii_access; 7448c2ecf20Sopenharmony_ci int ret; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* comfirm MII not busy */ 7478c2ecf20Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 7488c2ecf20Sopenharmony_ci if (ret < 0) 7498c2ecf20Sopenharmony_ci return ret; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* set the address, index & direction (read from PHY) */ 7528c2ecf20Sopenharmony_ci mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_READ); 7538c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mii_access); 7548c2ecf20Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 7558c2ecf20Sopenharmony_ci if (ret < 0) 7568c2ecf20Sopenharmony_ci return ret; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci val = lan743x_csr_read(adapter, MAC_MII_DATA); 7598c2ecf20Sopenharmony_ci return (int)(val & 0xFFFF); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int lan743x_mdiobus_write(struct mii_bus *bus, 7638c2ecf20Sopenharmony_ci int phy_id, int index, u16 regval) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = bus->priv; 7668c2ecf20Sopenharmony_ci u32 val, mii_access; 7678c2ecf20Sopenharmony_ci int ret; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* confirm MII not busy */ 7708c2ecf20Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 7718c2ecf20Sopenharmony_ci if (ret < 0) 7728c2ecf20Sopenharmony_ci return ret; 7738c2ecf20Sopenharmony_ci val = (u32)regval; 7748c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_DATA, val); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* set the address, index & direction (write to PHY) */ 7778c2ecf20Sopenharmony_ci mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_WRITE); 7788c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_MII_ACC, mii_access); 7798c2ecf20Sopenharmony_ci ret = lan743x_mac_mii_wait_till_not_busy(adapter); 7808c2ecf20Sopenharmony_ci return ret; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic void lan743x_mac_set_address(struct lan743x_adapter *adapter, 7848c2ecf20Sopenharmony_ci u8 *addr) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci u32 addr_lo, addr_hi; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci addr_lo = addr[0] | 7898c2ecf20Sopenharmony_ci addr[1] << 8 | 7908c2ecf20Sopenharmony_ci addr[2] << 16 | 7918c2ecf20Sopenharmony_ci addr[3] << 24; 7928c2ecf20Sopenharmony_ci addr_hi = addr[4] | 7938c2ecf20Sopenharmony_ci addr[5] << 8; 7948c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX_ADDRL, addr_lo); 7958c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX_ADDRH, addr_hi); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci ether_addr_copy(adapter->mac_address, addr); 7988c2ecf20Sopenharmony_ci netif_info(adapter, drv, adapter->netdev, 7998c2ecf20Sopenharmony_ci "MAC address set to %pM\n", addr); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int lan743x_mac_init(struct lan743x_adapter *adapter) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci bool mac_address_valid = true; 8058c2ecf20Sopenharmony_ci struct net_device *netdev; 8068c2ecf20Sopenharmony_ci u32 mac_addr_hi = 0; 8078c2ecf20Sopenharmony_ci u32 mac_addr_lo = 0; 8088c2ecf20Sopenharmony_ci u32 data; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci netdev = adapter->netdev; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* disable auto duplex, and speed detection. Phylib does that */ 8138c2ecf20Sopenharmony_ci data = lan743x_csr_read(adapter, MAC_CR); 8148c2ecf20Sopenharmony_ci data &= ~(MAC_CR_ADD_ | MAC_CR_ASD_); 8158c2ecf20Sopenharmony_ci data |= MAC_CR_CNTR_RST_; 8168c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, data); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(adapter->mac_address)) { 8198c2ecf20Sopenharmony_ci mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH); 8208c2ecf20Sopenharmony_ci mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL); 8218c2ecf20Sopenharmony_ci adapter->mac_address[0] = mac_addr_lo & 0xFF; 8228c2ecf20Sopenharmony_ci adapter->mac_address[1] = (mac_addr_lo >> 8) & 0xFF; 8238c2ecf20Sopenharmony_ci adapter->mac_address[2] = (mac_addr_lo >> 16) & 0xFF; 8248c2ecf20Sopenharmony_ci adapter->mac_address[3] = (mac_addr_lo >> 24) & 0xFF; 8258c2ecf20Sopenharmony_ci adapter->mac_address[4] = mac_addr_hi & 0xFF; 8268c2ecf20Sopenharmony_ci adapter->mac_address[5] = (mac_addr_hi >> 8) & 0xFF; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) && 8298c2ecf20Sopenharmony_ci mac_addr_lo == 0xFFFFFFFF) { 8308c2ecf20Sopenharmony_ci mac_address_valid = false; 8318c2ecf20Sopenharmony_ci } else if (!is_valid_ether_addr(adapter->mac_address)) { 8328c2ecf20Sopenharmony_ci mac_address_valid = false; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (!mac_address_valid) 8368c2ecf20Sopenharmony_ci eth_random_addr(adapter->mac_address); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci lan743x_mac_set_address(adapter, adapter->mac_address); 8398c2ecf20Sopenharmony_ci ether_addr_copy(netdev->dev_addr, adapter->mac_address); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic int lan743x_mac_open(struct lan743x_adapter *adapter) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci int ret = 0; 8478c2ecf20Sopenharmony_ci u32 temp; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_RX); 8508c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, temp | MAC_RX_RXEN_); 8518c2ecf20Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_TX); 8528c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_TX, temp | MAC_TX_TXEN_); 8538c2ecf20Sopenharmony_ci return ret; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic void lan743x_mac_close(struct lan743x_adapter *adapter) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci u32 temp; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_TX); 8618c2ecf20Sopenharmony_ci temp &= ~MAC_TX_TXEN_; 8628c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_TX, temp); 8638c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, MAC_TX, MAC_TX_TXD_, 8648c2ecf20Sopenharmony_ci 1, 1000, 20000, 100); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci temp = lan743x_csr_read(adapter, MAC_RX); 8678c2ecf20Sopenharmony_ci temp &= ~MAC_RX_RXEN_; 8688c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, temp); 8698c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, 8708c2ecf20Sopenharmony_ci 1, 1000, 20000, 100); 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter, 8748c2ecf20Sopenharmony_ci bool tx_enable, bool rx_enable) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci u32 flow_setting = 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* set maximum pause time because when fifo space frees 8798c2ecf20Sopenharmony_ci * up a zero value pause frame will be sent to release the pause 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_ci flow_setting = MAC_FLOW_CR_FCPT_MASK_; 8828c2ecf20Sopenharmony_ci if (tx_enable) 8838c2ecf20Sopenharmony_ci flow_setting |= MAC_FLOW_CR_TX_FCEN_; 8848c2ecf20Sopenharmony_ci if (rx_enable) 8858c2ecf20Sopenharmony_ci flow_setting |= MAC_FLOW_CR_RX_FCEN_; 8868c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_FLOW, flow_setting); 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic int lan743x_mac_set_mtu(struct lan743x_adapter *adapter, int new_mtu) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci int enabled = 0; 8928c2ecf20Sopenharmony_ci u32 mac_rx = 0; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci mac_rx = lan743x_csr_read(adapter, MAC_RX); 8958c2ecf20Sopenharmony_ci if (mac_rx & MAC_RX_RXEN_) { 8968c2ecf20Sopenharmony_ci enabled = 1; 8978c2ecf20Sopenharmony_ci if (mac_rx & MAC_RX_RXD_) { 8988c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 8998c2ecf20Sopenharmony_ci mac_rx &= ~MAC_RX_RXD_; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci mac_rx &= ~MAC_RX_RXEN_; 9028c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 9038c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_, 9048c2ecf20Sopenharmony_ci 1, 1000, 20000, 100); 9058c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx | MAC_RX_RXD_); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci mac_rx &= ~(MAC_RX_MAX_SIZE_MASK_); 9098c2ecf20Sopenharmony_ci mac_rx |= (((new_mtu + ETH_HLEN + 4) << MAC_RX_MAX_SIZE_SHIFT_) & 9108c2ecf20Sopenharmony_ci MAC_RX_MAX_SIZE_MASK_); 9118c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (enabled) { 9148c2ecf20Sopenharmony_ci mac_rx |= MAC_RX_RXEN_; 9158c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, mac_rx); 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci return 0; 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/* PHY */ 9218c2ecf20Sopenharmony_cistatic int lan743x_phy_reset(struct lan743x_adapter *adapter) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci u32 data; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Only called with in probe, and before mdiobus_register */ 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci data = lan743x_csr_read(adapter, PMT_CTL); 9288c2ecf20Sopenharmony_ci data |= PMT_CTL_ETH_PHY_RST_; 9298c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, PMT_CTL, data); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, PMT_CTL, data, 9328c2ecf20Sopenharmony_ci (!(data & PMT_CTL_ETH_PHY_RST_) && 9338c2ecf20Sopenharmony_ci (data & PMT_CTL_READY_)), 9348c2ecf20Sopenharmony_ci 50000, 1000000); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic void lan743x_phy_update_flowcontrol(struct lan743x_adapter *adapter, 9388c2ecf20Sopenharmony_ci u16 local_adv, u16 remote_adv) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct lan743x_phy *phy = &adapter->phy; 9418c2ecf20Sopenharmony_ci u8 cap; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (phy->fc_autoneg) 9448c2ecf20Sopenharmony_ci cap = mii_resolve_flowctrl_fdx(local_adv, remote_adv); 9458c2ecf20Sopenharmony_ci else 9468c2ecf20Sopenharmony_ci cap = phy->fc_request_control; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci lan743x_mac_flow_ctrl_set_enables(adapter, 9498c2ecf20Sopenharmony_ci cap & FLOW_CTRL_TX, 9508c2ecf20Sopenharmony_ci cap & FLOW_CTRL_RX); 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic int lan743x_phy_init(struct lan743x_adapter *adapter) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci return lan743x_phy_reset(adapter); 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic void lan743x_phy_link_status_change(struct net_device *netdev) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 9618c2ecf20Sopenharmony_ci struct phy_device *phydev = netdev->phydev; 9628c2ecf20Sopenharmony_ci u32 data; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci phy_print_status(phydev); 9658c2ecf20Sopenharmony_ci if (phydev->state == PHY_RUNNING) { 9668c2ecf20Sopenharmony_ci int remote_advertisement = 0; 9678c2ecf20Sopenharmony_ci int local_advertisement = 0; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci data = lan743x_csr_read(adapter, MAC_CR); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci /* set interface mode */ 9728c2ecf20Sopenharmony_ci if (phy_interface_mode_is_rgmii(adapter->phy_mode)) 9738c2ecf20Sopenharmony_ci /* RGMII */ 9748c2ecf20Sopenharmony_ci data &= ~MAC_CR_MII_EN_; 9758c2ecf20Sopenharmony_ci else 9768c2ecf20Sopenharmony_ci /* GMII */ 9778c2ecf20Sopenharmony_ci data |= MAC_CR_MII_EN_; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* set duplex mode */ 9808c2ecf20Sopenharmony_ci if (phydev->duplex) 9818c2ecf20Sopenharmony_ci data |= MAC_CR_DPX_; 9828c2ecf20Sopenharmony_ci else 9838c2ecf20Sopenharmony_ci data &= ~MAC_CR_DPX_; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* set bus speed */ 9868c2ecf20Sopenharmony_ci switch (phydev->speed) { 9878c2ecf20Sopenharmony_ci case SPEED_10: 9888c2ecf20Sopenharmony_ci data &= ~MAC_CR_CFG_H_; 9898c2ecf20Sopenharmony_ci data &= ~MAC_CR_CFG_L_; 9908c2ecf20Sopenharmony_ci break; 9918c2ecf20Sopenharmony_ci case SPEED_100: 9928c2ecf20Sopenharmony_ci data &= ~MAC_CR_CFG_H_; 9938c2ecf20Sopenharmony_ci data |= MAC_CR_CFG_L_; 9948c2ecf20Sopenharmony_ci break; 9958c2ecf20Sopenharmony_ci case SPEED_1000: 9968c2ecf20Sopenharmony_ci data |= MAC_CR_CFG_H_; 9978c2ecf20Sopenharmony_ci data &= ~MAC_CR_CFG_L_; 9988c2ecf20Sopenharmony_ci break; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, data); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci local_advertisement = 10038c2ecf20Sopenharmony_ci linkmode_adv_to_mii_adv_t(phydev->advertising); 10048c2ecf20Sopenharmony_ci remote_advertisement = 10058c2ecf20Sopenharmony_ci linkmode_adv_to_mii_adv_t(phydev->lp_advertising); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci lan743x_phy_update_flowcontrol(adapter, local_advertisement, 10088c2ecf20Sopenharmony_ci remote_advertisement); 10098c2ecf20Sopenharmony_ci lan743x_ptp_update_latency(adapter, phydev->speed); 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic void lan743x_phy_close(struct lan743x_adapter *adapter) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci phy_stop(netdev->phydev); 10188c2ecf20Sopenharmony_ci phy_disconnect(netdev->phydev); 10198c2ecf20Sopenharmony_ci netdev->phydev = NULL; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int lan743x_phy_open(struct lan743x_adapter *adapter) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci struct lan743x_phy *phy = &adapter->phy; 10258c2ecf20Sopenharmony_ci struct phy_device *phydev = NULL; 10268c2ecf20Sopenharmony_ci struct device_node *phynode; 10278c2ecf20Sopenharmony_ci struct net_device *netdev; 10288c2ecf20Sopenharmony_ci int ret = -EIO; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci netdev = adapter->netdev; 10318c2ecf20Sopenharmony_ci phynode = of_node_get(adapter->pdev->dev.of_node); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (phynode) { 10348c2ecf20Sopenharmony_ci /* try devicetree phy, or fixed link */ 10358c2ecf20Sopenharmony_ci of_get_phy_mode(phynode, &adapter->phy_mode); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (of_phy_is_fixed_link(phynode)) { 10388c2ecf20Sopenharmony_ci ret = of_phy_register_fixed_link(phynode); 10398c2ecf20Sopenharmony_ci if (ret) { 10408c2ecf20Sopenharmony_ci netdev_err(netdev, 10418c2ecf20Sopenharmony_ci "cannot register fixed PHY\n"); 10428c2ecf20Sopenharmony_ci of_node_put(phynode); 10438c2ecf20Sopenharmony_ci goto return_error; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci phydev = of_phy_connect(netdev, phynode, 10478c2ecf20Sopenharmony_ci lan743x_phy_link_status_change, 0, 10488c2ecf20Sopenharmony_ci adapter->phy_mode); 10498c2ecf20Sopenharmony_ci of_node_put(phynode); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (!phydev) { 10538c2ecf20Sopenharmony_ci /* try internal phy */ 10548c2ecf20Sopenharmony_ci phydev = phy_find_first(adapter->mdiobus); 10558c2ecf20Sopenharmony_ci if (!phydev) 10568c2ecf20Sopenharmony_ci goto return_error; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci adapter->phy_mode = PHY_INTERFACE_MODE_GMII; 10598c2ecf20Sopenharmony_ci ret = phy_connect_direct(netdev, phydev, 10608c2ecf20Sopenharmony_ci lan743x_phy_link_status_change, 10618c2ecf20Sopenharmony_ci adapter->phy_mode); 10628c2ecf20Sopenharmony_ci if (ret) 10638c2ecf20Sopenharmony_ci goto return_error; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* MAC doesn't support 1000T Half */ 10678c2ecf20Sopenharmony_ci phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* support both flow controls */ 10708c2ecf20Sopenharmony_ci phy_support_asym_pause(phydev); 10718c2ecf20Sopenharmony_ci phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX); 10728c2ecf20Sopenharmony_ci phy->fc_autoneg = phydev->autoneg; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci phy_start(phydev); 10758c2ecf20Sopenharmony_ci phy_start_aneg(phydev); 10768c2ecf20Sopenharmony_ci return 0; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cireturn_error: 10798c2ecf20Sopenharmony_ci return ret; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic void lan743x_rfe_open(struct lan743x_adapter *adapter) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RFE_RSS_CFG, 10858c2ecf20Sopenharmony_ci RFE_RSS_CFG_UDP_IPV6_EX_ | 10868c2ecf20Sopenharmony_ci RFE_RSS_CFG_TCP_IPV6_EX_ | 10878c2ecf20Sopenharmony_ci RFE_RSS_CFG_IPV6_EX_ | 10888c2ecf20Sopenharmony_ci RFE_RSS_CFG_UDP_IPV6_ | 10898c2ecf20Sopenharmony_ci RFE_RSS_CFG_TCP_IPV6_ | 10908c2ecf20Sopenharmony_ci RFE_RSS_CFG_IPV6_ | 10918c2ecf20Sopenharmony_ci RFE_RSS_CFG_UDP_IPV4_ | 10928c2ecf20Sopenharmony_ci RFE_RSS_CFG_TCP_IPV4_ | 10938c2ecf20Sopenharmony_ci RFE_RSS_CFG_IPV4_ | 10948c2ecf20Sopenharmony_ci RFE_RSS_CFG_VALID_HASH_BITS_ | 10958c2ecf20Sopenharmony_ci RFE_RSS_CFG_RSS_QUEUE_ENABLE_ | 10968c2ecf20Sopenharmony_ci RFE_RSS_CFG_RSS_HASH_STORE_ | 10978c2ecf20Sopenharmony_ci RFE_RSS_CFG_RSS_ENABLE_); 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic void lan743x_rfe_update_mac_address(struct lan743x_adapter *adapter) 11018c2ecf20Sopenharmony_ci{ 11028c2ecf20Sopenharmony_ci u8 *mac_addr; 11038c2ecf20Sopenharmony_ci u32 mac_addr_hi = 0; 11048c2ecf20Sopenharmony_ci u32 mac_addr_lo = 0; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* Add mac address to perfect Filter */ 11078c2ecf20Sopenharmony_ci mac_addr = adapter->mac_address; 11088c2ecf20Sopenharmony_ci mac_addr_lo = ((((u32)(mac_addr[0])) << 0) | 11098c2ecf20Sopenharmony_ci (((u32)(mac_addr[1])) << 8) | 11108c2ecf20Sopenharmony_ci (((u32)(mac_addr[2])) << 16) | 11118c2ecf20Sopenharmony_ci (((u32)(mac_addr[3])) << 24)); 11128c2ecf20Sopenharmony_ci mac_addr_hi = ((((u32)(mac_addr[4])) << 0) | 11138c2ecf20Sopenharmony_ci (((u32)(mac_addr[5])) << 8)); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RFE_ADDR_FILT_LO(0), mac_addr_lo); 11168c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RFE_ADDR_FILT_HI(0), 11178c2ecf20Sopenharmony_ci mac_addr_hi | RFE_ADDR_FILT_HI_VALID_); 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic void lan743x_rfe_set_multicast(struct lan743x_adapter *adapter) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 11238c2ecf20Sopenharmony_ci u32 hash_table[DP_SEL_VHF_HASH_LEN]; 11248c2ecf20Sopenharmony_ci u32 rfctl; 11258c2ecf20Sopenharmony_ci u32 data; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci rfctl = lan743x_csr_read(adapter, RFE_CTL); 11288c2ecf20Sopenharmony_ci rfctl &= ~(RFE_CTL_AU_ | RFE_CTL_AM_ | 11298c2ecf20Sopenharmony_ci RFE_CTL_DA_PERFECT_ | RFE_CTL_MCAST_HASH_); 11308c2ecf20Sopenharmony_ci rfctl |= RFE_CTL_AB_; 11318c2ecf20Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 11328c2ecf20Sopenharmony_ci rfctl |= RFE_CTL_AM_ | RFE_CTL_AU_; 11338c2ecf20Sopenharmony_ci } else { 11348c2ecf20Sopenharmony_ci if (netdev->flags & IFF_ALLMULTI) 11358c2ecf20Sopenharmony_ci rfctl |= RFE_CTL_AM_; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci memset(hash_table, 0, DP_SEL_VHF_HASH_LEN * sizeof(u32)); 11398c2ecf20Sopenharmony_ci if (netdev_mc_count(netdev)) { 11408c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 11418c2ecf20Sopenharmony_ci int i; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci rfctl |= RFE_CTL_DA_PERFECT_; 11448c2ecf20Sopenharmony_ci i = 1; 11458c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 11468c2ecf20Sopenharmony_ci /* set first 32 into Perfect Filter */ 11478c2ecf20Sopenharmony_ci if (i < 33) { 11488c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 11498c2ecf20Sopenharmony_ci RFE_ADDR_FILT_HI(i), 0); 11508c2ecf20Sopenharmony_ci data = ha->addr[3]; 11518c2ecf20Sopenharmony_ci data = ha->addr[2] | (data << 8); 11528c2ecf20Sopenharmony_ci data = ha->addr[1] | (data << 8); 11538c2ecf20Sopenharmony_ci data = ha->addr[0] | (data << 8); 11548c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 11558c2ecf20Sopenharmony_ci RFE_ADDR_FILT_LO(i), data); 11568c2ecf20Sopenharmony_ci data = ha->addr[5]; 11578c2ecf20Sopenharmony_ci data = ha->addr[4] | (data << 8); 11588c2ecf20Sopenharmony_ci data |= RFE_ADDR_FILT_HI_VALID_; 11598c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 11608c2ecf20Sopenharmony_ci RFE_ADDR_FILT_HI(i), data); 11618c2ecf20Sopenharmony_ci } else { 11628c2ecf20Sopenharmony_ci u32 bitnum = (ether_crc(ETH_ALEN, ha->addr) >> 11638c2ecf20Sopenharmony_ci 23) & 0x1FF; 11648c2ecf20Sopenharmony_ci hash_table[bitnum / 32] |= (1 << (bitnum % 32)); 11658c2ecf20Sopenharmony_ci rfctl |= RFE_CTL_MCAST_HASH_; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci i++; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci lan743x_dp_write(adapter, DP_SEL_RFE_RAM, 11728c2ecf20Sopenharmony_ci DP_SEL_VHF_VLAN_LEN, 11738c2ecf20Sopenharmony_ci DP_SEL_VHF_HASH_LEN, hash_table); 11748c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RFE_CTL, rfctl); 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic int lan743x_dmac_init(struct lan743x_adapter *adapter) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci u32 data = 0; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_SWR_); 11828c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, DMAC_CMD, DMAC_CMD_SWR_, 11838c2ecf20Sopenharmony_ci 0, 1000, 20000, 100); 11848c2ecf20Sopenharmony_ci switch (DEFAULT_DMA_DESCRIPTOR_SPACING) { 11858c2ecf20Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_16: 11868c2ecf20Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_16_; 11878c2ecf20Sopenharmony_ci break; 11888c2ecf20Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_32: 11898c2ecf20Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_32_; 11908c2ecf20Sopenharmony_ci break; 11918c2ecf20Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_64: 11928c2ecf20Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_64_; 11938c2ecf20Sopenharmony_ci break; 11948c2ecf20Sopenharmony_ci case DMA_DESCRIPTOR_SPACING_128: 11958c2ecf20Sopenharmony_ci data = DMAC_CFG_MAX_DSPACE_128_; 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci default: 11988c2ecf20Sopenharmony_ci return -EPERM; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) 12018c2ecf20Sopenharmony_ci data |= DMAC_CFG_COAL_EN_; 12028c2ecf20Sopenharmony_ci data |= DMAC_CFG_CH_ARB_SEL_RX_HIGH_; 12038c2ecf20Sopenharmony_ci data |= DMAC_CFG_MAX_READ_REQ_SET_(6); 12048c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CFG, data); 12058c2ecf20Sopenharmony_ci data = DMAC_COAL_CFG_TIMER_LIMIT_SET_(1); 12068c2ecf20Sopenharmony_ci data |= DMAC_COAL_CFG_TIMER_TX_START_; 12078c2ecf20Sopenharmony_ci data |= DMAC_COAL_CFG_FLUSH_INTS_; 12088c2ecf20Sopenharmony_ci data |= DMAC_COAL_CFG_INT_EXIT_COAL_; 12098c2ecf20Sopenharmony_ci data |= DMAC_COAL_CFG_CSR_EXIT_COAL_; 12108c2ecf20Sopenharmony_ci data |= DMAC_COAL_CFG_TX_THRES_SET_(0x0A); 12118c2ecf20Sopenharmony_ci data |= DMAC_COAL_CFG_RX_THRES_SET_(0x0C); 12128c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_COAL_CFG, data); 12138c2ecf20Sopenharmony_ci data = DMAC_OBFF_TX_THRES_SET_(0x08); 12148c2ecf20Sopenharmony_ci data |= DMAC_OBFF_RX_THRES_SET_(0x0A); 12158c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_OBFF_CFG, data); 12168c2ecf20Sopenharmony_ci return 0; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic int lan743x_dmac_tx_get_state(struct lan743x_adapter *adapter, 12208c2ecf20Sopenharmony_ci int tx_channel) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci u32 dmac_cmd = 0; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD); 12258c2ecf20Sopenharmony_ci return DMAC_CHANNEL_STATE_SET((dmac_cmd & 12268c2ecf20Sopenharmony_ci DMAC_CMD_START_T_(tx_channel)), 12278c2ecf20Sopenharmony_ci (dmac_cmd & 12288c2ecf20Sopenharmony_ci DMAC_CMD_STOP_T_(tx_channel))); 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_cistatic int lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter *adapter, 12328c2ecf20Sopenharmony_ci int tx_channel) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci int timeout = 100; 12358c2ecf20Sopenharmony_ci int result = 0; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci while (timeout && 12388c2ecf20Sopenharmony_ci ((result = lan743x_dmac_tx_get_state(adapter, tx_channel)) == 12398c2ecf20Sopenharmony_ci DMAC_CHANNEL_STATE_STOP_PENDING)) { 12408c2ecf20Sopenharmony_ci usleep_range(1000, 20000); 12418c2ecf20Sopenharmony_ci timeout--; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci if (result == DMAC_CHANNEL_STATE_STOP_PENDING) 12448c2ecf20Sopenharmony_ci result = -ENODEV; 12458c2ecf20Sopenharmony_ci return result; 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistatic int lan743x_dmac_rx_get_state(struct lan743x_adapter *adapter, 12498c2ecf20Sopenharmony_ci int rx_channel) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci u32 dmac_cmd = 0; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD); 12548c2ecf20Sopenharmony_ci return DMAC_CHANNEL_STATE_SET((dmac_cmd & 12558c2ecf20Sopenharmony_ci DMAC_CMD_START_R_(rx_channel)), 12568c2ecf20Sopenharmony_ci (dmac_cmd & 12578c2ecf20Sopenharmony_ci DMAC_CMD_STOP_R_(rx_channel))); 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic int lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter *adapter, 12618c2ecf20Sopenharmony_ci int rx_channel) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci int timeout = 100; 12648c2ecf20Sopenharmony_ci int result = 0; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci while (timeout && 12678c2ecf20Sopenharmony_ci ((result = lan743x_dmac_rx_get_state(adapter, rx_channel)) == 12688c2ecf20Sopenharmony_ci DMAC_CHANNEL_STATE_STOP_PENDING)) { 12698c2ecf20Sopenharmony_ci usleep_range(1000, 20000); 12708c2ecf20Sopenharmony_ci timeout--; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci if (result == DMAC_CHANNEL_STATE_STOP_PENDING) 12738c2ecf20Sopenharmony_ci result = -ENODEV; 12748c2ecf20Sopenharmony_ci return result; 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic void lan743x_tx_release_desc(struct lan743x_tx *tx, 12788c2ecf20Sopenharmony_ci int descriptor_index, bool cleanup) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 12818c2ecf20Sopenharmony_ci struct lan743x_tx_descriptor *descriptor = NULL; 12828c2ecf20Sopenharmony_ci u32 descriptor_type = 0; 12838c2ecf20Sopenharmony_ci bool ignore_sync; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci descriptor = &tx->ring_cpu_ptr[descriptor_index]; 12868c2ecf20Sopenharmony_ci buffer_info = &tx->buffer_info[descriptor_index]; 12878c2ecf20Sopenharmony_ci if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_ACTIVE)) 12888c2ecf20Sopenharmony_ci goto done; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci descriptor_type = le32_to_cpu(descriptor->data0) & 12918c2ecf20Sopenharmony_ci TX_DESC_DATA0_DTYPE_MASK_; 12928c2ecf20Sopenharmony_ci if (descriptor_type == TX_DESC_DATA0_DTYPE_DATA_) 12938c2ecf20Sopenharmony_ci goto clean_up_data_descriptor; 12948c2ecf20Sopenharmony_ci else 12958c2ecf20Sopenharmony_ci goto clear_active; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ciclean_up_data_descriptor: 12988c2ecf20Sopenharmony_ci if (buffer_info->dma_ptr) { 12998c2ecf20Sopenharmony_ci if (buffer_info->flags & 13008c2ecf20Sopenharmony_ci TX_BUFFER_INFO_FLAG_SKB_FRAGMENT) { 13018c2ecf20Sopenharmony_ci dma_unmap_page(&tx->adapter->pdev->dev, 13028c2ecf20Sopenharmony_ci buffer_info->dma_ptr, 13038c2ecf20Sopenharmony_ci buffer_info->buffer_length, 13048c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 13058c2ecf20Sopenharmony_ci } else { 13068c2ecf20Sopenharmony_ci dma_unmap_single(&tx->adapter->pdev->dev, 13078c2ecf20Sopenharmony_ci buffer_info->dma_ptr, 13088c2ecf20Sopenharmony_ci buffer_info->buffer_length, 13098c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci buffer_info->dma_ptr = 0; 13128c2ecf20Sopenharmony_ci buffer_info->buffer_length = 0; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci if (!buffer_info->skb) 13158c2ecf20Sopenharmony_ci goto clear_active; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED)) { 13188c2ecf20Sopenharmony_ci dev_kfree_skb_any(buffer_info->skb); 13198c2ecf20Sopenharmony_ci goto clear_skb; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (cleanup) { 13238c2ecf20Sopenharmony_ci lan743x_ptp_unrequest_tx_timestamp(tx->adapter); 13248c2ecf20Sopenharmony_ci dev_kfree_skb_any(buffer_info->skb); 13258c2ecf20Sopenharmony_ci } else { 13268c2ecf20Sopenharmony_ci ignore_sync = (buffer_info->flags & 13278c2ecf20Sopenharmony_ci TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0; 13288c2ecf20Sopenharmony_ci lan743x_ptp_tx_timestamp_skb(tx->adapter, 13298c2ecf20Sopenharmony_ci buffer_info->skb, ignore_sync); 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ciclear_skb: 13338c2ecf20Sopenharmony_ci buffer_info->skb = NULL; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ciclear_active: 13368c2ecf20Sopenharmony_ci buffer_info->flags &= ~TX_BUFFER_INFO_FLAG_ACTIVE; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_cidone: 13398c2ecf20Sopenharmony_ci memset(buffer_info, 0, sizeof(*buffer_info)); 13408c2ecf20Sopenharmony_ci memset(descriptor, 0, sizeof(*descriptor)); 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic int lan743x_tx_next_index(struct lan743x_tx *tx, int index) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci return ((++index) % tx->ring_size); 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic void lan743x_tx_release_completed_descriptors(struct lan743x_tx *tx) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci while (le32_to_cpu(*tx->head_cpu_ptr) != (tx->last_head)) { 13518c2ecf20Sopenharmony_ci lan743x_tx_release_desc(tx, tx->last_head, false); 13528c2ecf20Sopenharmony_ci tx->last_head = lan743x_tx_next_index(tx, tx->last_head); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci} 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cistatic void lan743x_tx_release_all_descriptors(struct lan743x_tx *tx) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci u32 original_head = 0; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci original_head = tx->last_head; 13618c2ecf20Sopenharmony_ci do { 13628c2ecf20Sopenharmony_ci lan743x_tx_release_desc(tx, tx->last_head, true); 13638c2ecf20Sopenharmony_ci tx->last_head = lan743x_tx_next_index(tx, tx->last_head); 13648c2ecf20Sopenharmony_ci } while (tx->last_head != original_head); 13658c2ecf20Sopenharmony_ci memset(tx->ring_cpu_ptr, 0, 13668c2ecf20Sopenharmony_ci sizeof(*tx->ring_cpu_ptr) * (tx->ring_size)); 13678c2ecf20Sopenharmony_ci memset(tx->buffer_info, 0, 13688c2ecf20Sopenharmony_ci sizeof(*tx->buffer_info) * (tx->ring_size)); 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic int lan743x_tx_get_desc_cnt(struct lan743x_tx *tx, 13728c2ecf20Sopenharmony_ci struct sk_buff *skb) 13738c2ecf20Sopenharmony_ci{ 13748c2ecf20Sopenharmony_ci int result = 1; /* 1 for the main skb buffer */ 13758c2ecf20Sopenharmony_ci int nr_frags = 0; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) 13788c2ecf20Sopenharmony_ci result++; /* requires an extension descriptor */ 13798c2ecf20Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 13808c2ecf20Sopenharmony_ci result += nr_frags; /* 1 for each fragment buffer */ 13818c2ecf20Sopenharmony_ci return result; 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic int lan743x_tx_get_avail_desc(struct lan743x_tx *tx) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci int last_head = tx->last_head; 13878c2ecf20Sopenharmony_ci int last_tail = tx->last_tail; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (last_tail >= last_head) 13908c2ecf20Sopenharmony_ci return tx->ring_size - last_tail + last_head - 1; 13918c2ecf20Sopenharmony_ci else 13928c2ecf20Sopenharmony_ci return last_head - last_tail - 1; 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_civoid lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx, 13968c2ecf20Sopenharmony_ci bool enable_timestamping, 13978c2ecf20Sopenharmony_ci bool enable_onestep_sync) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci if (enable_timestamping) 14008c2ecf20Sopenharmony_ci tx->ts_flags |= TX_TS_FLAG_TIMESTAMPING_ENABLED; 14018c2ecf20Sopenharmony_ci else 14028c2ecf20Sopenharmony_ci tx->ts_flags &= ~TX_TS_FLAG_TIMESTAMPING_ENABLED; 14038c2ecf20Sopenharmony_ci if (enable_onestep_sync) 14048c2ecf20Sopenharmony_ci tx->ts_flags |= TX_TS_FLAG_ONE_STEP_SYNC; 14058c2ecf20Sopenharmony_ci else 14068c2ecf20Sopenharmony_ci tx->ts_flags &= ~TX_TS_FLAG_ONE_STEP_SYNC; 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic int lan743x_tx_frame_start(struct lan743x_tx *tx, 14108c2ecf20Sopenharmony_ci unsigned char *first_buffer, 14118c2ecf20Sopenharmony_ci unsigned int first_buffer_length, 14128c2ecf20Sopenharmony_ci unsigned int frame_length, 14138c2ecf20Sopenharmony_ci bool time_stamp, 14148c2ecf20Sopenharmony_ci bool check_sum) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame. 14178c2ecf20Sopenharmony_ci * assuming tx->ring_lock has already been acquired. 14188c2ecf20Sopenharmony_ci */ 14198c2ecf20Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 14208c2ecf20Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 14218c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 14228c2ecf20Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 14238c2ecf20Sopenharmony_ci dma_addr_t dma_ptr; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci tx->frame_flags |= TX_FRAME_FLAG_IN_PROGRESS; 14268c2ecf20Sopenharmony_ci tx->frame_first = tx->last_tail; 14278c2ecf20Sopenharmony_ci tx->frame_tail = tx->frame_first; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 14308c2ecf20Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 14318c2ecf20Sopenharmony_ci dma_ptr = dma_map_single(dev, first_buffer, first_buffer_length, 14328c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14338c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, dma_ptr)) 14348c2ecf20Sopenharmony_ci return -ENOMEM; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr)); 14378c2ecf20Sopenharmony_ci tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr)); 14388c2ecf20Sopenharmony_ci tx_descriptor->data3 = cpu_to_le32((frame_length << 16) & 14398c2ecf20Sopenharmony_ci TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci buffer_info->skb = NULL; 14428c2ecf20Sopenharmony_ci buffer_info->dma_ptr = dma_ptr; 14438c2ecf20Sopenharmony_ci buffer_info->buffer_length = first_buffer_length; 14448c2ecf20Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci tx->frame_data0 = (first_buffer_length & 14478c2ecf20Sopenharmony_ci TX_DESC_DATA0_BUF_LENGTH_MASK_) | 14488c2ecf20Sopenharmony_ci TX_DESC_DATA0_DTYPE_DATA_ | 14498c2ecf20Sopenharmony_ci TX_DESC_DATA0_FS_ | 14508c2ecf20Sopenharmony_ci TX_DESC_DATA0_FCS_; 14518c2ecf20Sopenharmony_ci if (time_stamp) 14528c2ecf20Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_TSE_; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (check_sum) 14558c2ecf20Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_ICE_ | 14568c2ecf20Sopenharmony_ci TX_DESC_DATA0_IPE_ | 14578c2ecf20Sopenharmony_ci TX_DESC_DATA0_TPE_; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* data0 will be programmed in one of other frame assembler functions */ 14608c2ecf20Sopenharmony_ci return 0; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic void lan743x_tx_frame_add_lso(struct lan743x_tx *tx, 14648c2ecf20Sopenharmony_ci unsigned int frame_length, 14658c2ecf20Sopenharmony_ci int nr_frags) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame. 14688c2ecf20Sopenharmony_ci * assuming tx->ring_lock has already been acquired. 14698c2ecf20Sopenharmony_ci */ 14708c2ecf20Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 14718c2ecf20Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci /* wrap up previous descriptor */ 14748c2ecf20Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_EXT_; 14758c2ecf20Sopenharmony_ci if (nr_frags <= 0) { 14768c2ecf20Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_LS_; 14778c2ecf20Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_IOC_; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 14808c2ecf20Sopenharmony_ci tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* move to next descriptor */ 14838c2ecf20Sopenharmony_ci tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); 14848c2ecf20Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 14858c2ecf20Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci /* add extension descriptor */ 14888c2ecf20Sopenharmony_ci tx_descriptor->data1 = 0; 14898c2ecf20Sopenharmony_ci tx_descriptor->data2 = 0; 14908c2ecf20Sopenharmony_ci tx_descriptor->data3 = 0; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci buffer_info->skb = NULL; 14938c2ecf20Sopenharmony_ci buffer_info->dma_ptr = 0; 14948c2ecf20Sopenharmony_ci buffer_info->buffer_length = 0; 14958c2ecf20Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci tx->frame_data0 = (frame_length & TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_) | 14988c2ecf20Sopenharmony_ci TX_DESC_DATA0_DTYPE_EXT_ | 14998c2ecf20Sopenharmony_ci TX_DESC_DATA0_EXT_LSO_; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* data0 will be programmed in one of other frame assembler functions */ 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx, 15058c2ecf20Sopenharmony_ci const skb_frag_t *fragment, 15068c2ecf20Sopenharmony_ci unsigned int frame_length) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame 15098c2ecf20Sopenharmony_ci * assuming tx->ring_lock has already been acquired 15108c2ecf20Sopenharmony_ci */ 15118c2ecf20Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 15128c2ecf20Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 15138c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 15148c2ecf20Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 15158c2ecf20Sopenharmony_ci unsigned int fragment_length = 0; 15168c2ecf20Sopenharmony_ci dma_addr_t dma_ptr; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci fragment_length = skb_frag_size(fragment); 15198c2ecf20Sopenharmony_ci if (!fragment_length) 15208c2ecf20Sopenharmony_ci return 0; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci /* wrap up previous descriptor */ 15238c2ecf20Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 15248c2ecf20Sopenharmony_ci tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* move to next descriptor */ 15278c2ecf20Sopenharmony_ci tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); 15288c2ecf20Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 15298c2ecf20Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 15308c2ecf20Sopenharmony_ci dma_ptr = skb_frag_dma_map(dev, fragment, 15318c2ecf20Sopenharmony_ci 0, fragment_length, 15328c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 15338c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, dma_ptr)) { 15348c2ecf20Sopenharmony_ci int desc_index; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* cleanup all previously setup descriptors */ 15378c2ecf20Sopenharmony_ci desc_index = tx->frame_first; 15388c2ecf20Sopenharmony_ci while (desc_index != tx->frame_tail) { 15398c2ecf20Sopenharmony_ci lan743x_tx_release_desc(tx, desc_index, true); 15408c2ecf20Sopenharmony_ci desc_index = lan743x_tx_next_index(tx, desc_index); 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci dma_wmb(); 15438c2ecf20Sopenharmony_ci tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS; 15448c2ecf20Sopenharmony_ci tx->frame_first = 0; 15458c2ecf20Sopenharmony_ci tx->frame_data0 = 0; 15468c2ecf20Sopenharmony_ci tx->frame_tail = 0; 15478c2ecf20Sopenharmony_ci return -ENOMEM; 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr)); 15518c2ecf20Sopenharmony_ci tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr)); 15528c2ecf20Sopenharmony_ci tx_descriptor->data3 = cpu_to_le32((frame_length << 16) & 15538c2ecf20Sopenharmony_ci TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci buffer_info->skb = NULL; 15568c2ecf20Sopenharmony_ci buffer_info->dma_ptr = dma_ptr; 15578c2ecf20Sopenharmony_ci buffer_info->buffer_length = fragment_length; 15588c2ecf20Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE; 15598c2ecf20Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_SKB_FRAGMENT; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci tx->frame_data0 = (fragment_length & TX_DESC_DATA0_BUF_LENGTH_MASK_) | 15628c2ecf20Sopenharmony_ci TX_DESC_DATA0_DTYPE_DATA_ | 15638c2ecf20Sopenharmony_ci TX_DESC_DATA0_FCS_; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci /* data0 will be programmed in one of other frame assembler functions */ 15668c2ecf20Sopenharmony_ci return 0; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic void lan743x_tx_frame_end(struct lan743x_tx *tx, 15708c2ecf20Sopenharmony_ci struct sk_buff *skb, 15718c2ecf20Sopenharmony_ci bool time_stamp, 15728c2ecf20Sopenharmony_ci bool ignore_sync) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci /* called only from within lan743x_tx_xmit_frame 15758c2ecf20Sopenharmony_ci * assuming tx->ring_lock has already been acquired 15768c2ecf20Sopenharmony_ci */ 15778c2ecf20Sopenharmony_ci struct lan743x_tx_descriptor *tx_descriptor = NULL; 15788c2ecf20Sopenharmony_ci struct lan743x_tx_buffer_info *buffer_info = NULL; 15798c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 15808c2ecf20Sopenharmony_ci u32 tx_tail_flags = 0; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* wrap up previous descriptor */ 15838c2ecf20Sopenharmony_ci if ((tx->frame_data0 & TX_DESC_DATA0_DTYPE_MASK_) == 15848c2ecf20Sopenharmony_ci TX_DESC_DATA0_DTYPE_DATA_) { 15858c2ecf20Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_LS_; 15868c2ecf20Sopenharmony_ci tx->frame_data0 |= TX_DESC_DATA0_IOC_; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; 15908c2ecf20Sopenharmony_ci buffer_info = &tx->buffer_info[tx->frame_tail]; 15918c2ecf20Sopenharmony_ci buffer_info->skb = skb; 15928c2ecf20Sopenharmony_ci if (time_stamp) 15938c2ecf20Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED; 15948c2ecf20Sopenharmony_ci if (ignore_sync) 15958c2ecf20Sopenharmony_ci buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); 15988c2ecf20Sopenharmony_ci tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); 15998c2ecf20Sopenharmony_ci tx->last_tail = tx->frame_tail; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci dma_wmb(); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET) 16048c2ecf20Sopenharmony_ci tx_tail_flags |= TX_TAIL_SET_TOP_INT_VEC_EN_; 16058c2ecf20Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET) 16068c2ecf20Sopenharmony_ci tx_tail_flags |= TX_TAIL_SET_DMAC_INT_EN_ | 16078c2ecf20Sopenharmony_ci TX_TAIL_SET_TOP_INT_EN_; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, TX_TAIL(tx->channel_number), 16108c2ecf20Sopenharmony_ci tx_tail_flags | tx->frame_tail); 16118c2ecf20Sopenharmony_ci tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx, 16158c2ecf20Sopenharmony_ci struct sk_buff *skb) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci int required_number_of_descriptors = 0; 16188c2ecf20Sopenharmony_ci unsigned int start_frame_length = 0; 16198c2ecf20Sopenharmony_ci unsigned int frame_length = 0; 16208c2ecf20Sopenharmony_ci unsigned int head_length = 0; 16218c2ecf20Sopenharmony_ci unsigned long irq_flags = 0; 16228c2ecf20Sopenharmony_ci bool do_timestamp = false; 16238c2ecf20Sopenharmony_ci bool ignore_sync = false; 16248c2ecf20Sopenharmony_ci int nr_frags = 0; 16258c2ecf20Sopenharmony_ci bool gso = false; 16268c2ecf20Sopenharmony_ci int j; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci required_number_of_descriptors = lan743x_tx_get_desc_cnt(tx, skb); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci spin_lock_irqsave(&tx->ring_lock, irq_flags); 16318c2ecf20Sopenharmony_ci if (required_number_of_descriptors > 16328c2ecf20Sopenharmony_ci lan743x_tx_get_avail_desc(tx)) { 16338c2ecf20Sopenharmony_ci if (required_number_of_descriptors > (tx->ring_size - 1)) { 16348c2ecf20Sopenharmony_ci dev_kfree_skb_irq(skb); 16358c2ecf20Sopenharmony_ci } else { 16368c2ecf20Sopenharmony_ci /* save to overflow buffer */ 16378c2ecf20Sopenharmony_ci tx->overflow_skb = skb; 16388c2ecf20Sopenharmony_ci netif_stop_queue(tx->adapter->netdev); 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci goto unlock; 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci /* space available, transmit skb */ 16448c2ecf20Sopenharmony_ci if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && 16458c2ecf20Sopenharmony_ci (tx->ts_flags & TX_TS_FLAG_TIMESTAMPING_ENABLED) && 16468c2ecf20Sopenharmony_ci (lan743x_ptp_request_tx_timestamp(tx->adapter))) { 16478c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 16488c2ecf20Sopenharmony_ci do_timestamp = true; 16498c2ecf20Sopenharmony_ci if (tx->ts_flags & TX_TS_FLAG_ONE_STEP_SYNC) 16508c2ecf20Sopenharmony_ci ignore_sync = true; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci head_length = skb_headlen(skb); 16538c2ecf20Sopenharmony_ci frame_length = skb_pagelen(skb); 16548c2ecf20Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 16558c2ecf20Sopenharmony_ci start_frame_length = frame_length; 16568c2ecf20Sopenharmony_ci gso = skb_is_gso(skb); 16578c2ecf20Sopenharmony_ci if (gso) { 16588c2ecf20Sopenharmony_ci start_frame_length = max(skb_shinfo(skb)->gso_size, 16598c2ecf20Sopenharmony_ci (unsigned short)8); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (lan743x_tx_frame_start(tx, 16638c2ecf20Sopenharmony_ci skb->data, head_length, 16648c2ecf20Sopenharmony_ci start_frame_length, 16658c2ecf20Sopenharmony_ci do_timestamp, 16668c2ecf20Sopenharmony_ci skb->ip_summed == CHECKSUM_PARTIAL)) { 16678c2ecf20Sopenharmony_ci dev_kfree_skb_irq(skb); 16688c2ecf20Sopenharmony_ci goto unlock; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (gso) 16728c2ecf20Sopenharmony_ci lan743x_tx_frame_add_lso(tx, frame_length, nr_frags); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci if (nr_frags <= 0) 16758c2ecf20Sopenharmony_ci goto finish; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci for (j = 0; j < nr_frags; j++) { 16788c2ecf20Sopenharmony_ci const skb_frag_t *frag = &(skb_shinfo(skb)->frags[j]); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci if (lan743x_tx_frame_add_fragment(tx, frag, frame_length)) { 16818c2ecf20Sopenharmony_ci /* upon error no need to call 16828c2ecf20Sopenharmony_ci * lan743x_tx_frame_end 16838c2ecf20Sopenharmony_ci * frame assembler clean up was performed inside 16848c2ecf20Sopenharmony_ci * lan743x_tx_frame_add_fragment 16858c2ecf20Sopenharmony_ci */ 16868c2ecf20Sopenharmony_ci dev_kfree_skb_irq(skb); 16878c2ecf20Sopenharmony_ci goto unlock; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cifinish: 16928c2ecf20Sopenharmony_ci lan743x_tx_frame_end(tx, skb, do_timestamp, ignore_sync); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ciunlock: 16958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tx->ring_lock, irq_flags); 16968c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 16978c2ecf20Sopenharmony_ci} 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_cistatic int lan743x_tx_napi_poll(struct napi_struct *napi, int weight) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci struct lan743x_tx *tx = container_of(napi, struct lan743x_tx, napi); 17028c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 17038c2ecf20Sopenharmony_ci bool start_transmitter = false; 17048c2ecf20Sopenharmony_ci unsigned long irq_flags = 0; 17058c2ecf20Sopenharmony_ci u32 ioc_bit = 0; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number); 17088c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, DMAC_INT_STS); 17098c2ecf20Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C) 17108c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_STS, ioc_bit); 17118c2ecf20Sopenharmony_ci spin_lock_irqsave(&tx->ring_lock, irq_flags); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci /* clean up tx ring */ 17148c2ecf20Sopenharmony_ci lan743x_tx_release_completed_descriptors(tx); 17158c2ecf20Sopenharmony_ci if (netif_queue_stopped(adapter->netdev)) { 17168c2ecf20Sopenharmony_ci if (tx->overflow_skb) { 17178c2ecf20Sopenharmony_ci if (lan743x_tx_get_desc_cnt(tx, tx->overflow_skb) <= 17188c2ecf20Sopenharmony_ci lan743x_tx_get_avail_desc(tx)) 17198c2ecf20Sopenharmony_ci start_transmitter = true; 17208c2ecf20Sopenharmony_ci } else { 17218c2ecf20Sopenharmony_ci netif_wake_queue(adapter->netdev); 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tx->ring_lock, irq_flags); 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci if (start_transmitter) { 17278c2ecf20Sopenharmony_ci /* space is now available, transmit overflow skb */ 17288c2ecf20Sopenharmony_ci lan743x_tx_xmit_frame(tx, tx->overflow_skb); 17298c2ecf20Sopenharmony_ci tx->overflow_skb = NULL; 17308c2ecf20Sopenharmony_ci netif_wake_queue(adapter->netdev); 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (!napi_complete(napi)) 17348c2ecf20Sopenharmony_ci goto done; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci /* enable isr */ 17378c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 17388c2ecf20Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 17398c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, INT_STS); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_cidone: 17428c2ecf20Sopenharmony_ci return 0; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_cistatic void lan743x_tx_ring_cleanup(struct lan743x_tx *tx) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci if (tx->head_cpu_ptr) { 17488c2ecf20Sopenharmony_ci dma_free_coherent(&tx->adapter->pdev->dev, 17498c2ecf20Sopenharmony_ci sizeof(*tx->head_cpu_ptr), tx->head_cpu_ptr, 17508c2ecf20Sopenharmony_ci tx->head_dma_ptr); 17518c2ecf20Sopenharmony_ci tx->head_cpu_ptr = NULL; 17528c2ecf20Sopenharmony_ci tx->head_dma_ptr = 0; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci kfree(tx->buffer_info); 17558c2ecf20Sopenharmony_ci tx->buffer_info = NULL; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (tx->ring_cpu_ptr) { 17588c2ecf20Sopenharmony_ci dma_free_coherent(&tx->adapter->pdev->dev, 17598c2ecf20Sopenharmony_ci tx->ring_allocation_size, tx->ring_cpu_ptr, 17608c2ecf20Sopenharmony_ci tx->ring_dma_ptr); 17618c2ecf20Sopenharmony_ci tx->ring_allocation_size = 0; 17628c2ecf20Sopenharmony_ci tx->ring_cpu_ptr = NULL; 17638c2ecf20Sopenharmony_ci tx->ring_dma_ptr = 0; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci tx->ring_size = 0; 17668c2ecf20Sopenharmony_ci} 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_cistatic int lan743x_tx_ring_init(struct lan743x_tx *tx) 17698c2ecf20Sopenharmony_ci{ 17708c2ecf20Sopenharmony_ci size_t ring_allocation_size = 0; 17718c2ecf20Sopenharmony_ci void *cpu_ptr = NULL; 17728c2ecf20Sopenharmony_ci dma_addr_t dma_ptr; 17738c2ecf20Sopenharmony_ci int ret = -ENOMEM; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci tx->ring_size = LAN743X_TX_RING_SIZE; 17768c2ecf20Sopenharmony_ci if (tx->ring_size & ~TX_CFG_B_TX_RING_LEN_MASK_) { 17778c2ecf20Sopenharmony_ci ret = -EINVAL; 17788c2ecf20Sopenharmony_ci goto cleanup; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(&tx->adapter->pdev->dev, 17818c2ecf20Sopenharmony_ci DMA_BIT_MASK(64))) { 17828c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(&tx->adapter->pdev->dev, 17838c2ecf20Sopenharmony_ci DMA_BIT_MASK(32))) { 17848c2ecf20Sopenharmony_ci dev_warn(&tx->adapter->pdev->dev, 17858c2ecf20Sopenharmony_ci "lan743x_: No suitable DMA available\n"); 17868c2ecf20Sopenharmony_ci ret = -ENOMEM; 17878c2ecf20Sopenharmony_ci goto cleanup; 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci ring_allocation_size = ALIGN(tx->ring_size * 17918c2ecf20Sopenharmony_ci sizeof(struct lan743x_tx_descriptor), 17928c2ecf20Sopenharmony_ci PAGE_SIZE); 17938c2ecf20Sopenharmony_ci dma_ptr = 0; 17948c2ecf20Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev, 17958c2ecf20Sopenharmony_ci ring_allocation_size, &dma_ptr, GFP_KERNEL); 17968c2ecf20Sopenharmony_ci if (!cpu_ptr) { 17978c2ecf20Sopenharmony_ci ret = -ENOMEM; 17988c2ecf20Sopenharmony_ci goto cleanup; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci tx->ring_allocation_size = ring_allocation_size; 18028c2ecf20Sopenharmony_ci tx->ring_cpu_ptr = (struct lan743x_tx_descriptor *)cpu_ptr; 18038c2ecf20Sopenharmony_ci tx->ring_dma_ptr = dma_ptr; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci cpu_ptr = kcalloc(tx->ring_size, sizeof(*tx->buffer_info), GFP_KERNEL); 18068c2ecf20Sopenharmony_ci if (!cpu_ptr) { 18078c2ecf20Sopenharmony_ci ret = -ENOMEM; 18088c2ecf20Sopenharmony_ci goto cleanup; 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci tx->buffer_info = (struct lan743x_tx_buffer_info *)cpu_ptr; 18118c2ecf20Sopenharmony_ci dma_ptr = 0; 18128c2ecf20Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev, 18138c2ecf20Sopenharmony_ci sizeof(*tx->head_cpu_ptr), &dma_ptr, 18148c2ecf20Sopenharmony_ci GFP_KERNEL); 18158c2ecf20Sopenharmony_ci if (!cpu_ptr) { 18168c2ecf20Sopenharmony_ci ret = -ENOMEM; 18178c2ecf20Sopenharmony_ci goto cleanup; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci tx->head_cpu_ptr = cpu_ptr; 18218c2ecf20Sopenharmony_ci tx->head_dma_ptr = dma_ptr; 18228c2ecf20Sopenharmony_ci if (tx->head_dma_ptr & 0x3) { 18238c2ecf20Sopenharmony_ci ret = -ENOMEM; 18248c2ecf20Sopenharmony_ci goto cleanup; 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci return 0; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cicleanup: 18308c2ecf20Sopenharmony_ci lan743x_tx_ring_cleanup(tx); 18318c2ecf20Sopenharmony_ci return ret; 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_cistatic void lan743x_tx_close(struct lan743x_tx *tx) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = tx->adapter; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 18398c2ecf20Sopenharmony_ci DMAC_CMD, 18408c2ecf20Sopenharmony_ci DMAC_CMD_STOP_T_(tx->channel_number)); 18418c2ecf20Sopenharmony_ci lan743x_dmac_tx_wait_till_stopped(adapter, tx->channel_number); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 18448c2ecf20Sopenharmony_ci DMAC_INT_EN_CLR, 18458c2ecf20Sopenharmony_ci DMAC_INT_BIT_TX_IOC_(tx->channel_number)); 18468c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 18478c2ecf20Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 18488c2ecf20Sopenharmony_ci napi_disable(&tx->napi); 18498c2ecf20Sopenharmony_ci netif_napi_del(&tx->napi); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, FCT_TX_CTL, 18528c2ecf20Sopenharmony_ci FCT_TX_CTL_DIS_(tx->channel_number)); 18538c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL, 18548c2ecf20Sopenharmony_ci FCT_TX_CTL_EN_(tx->channel_number), 18558c2ecf20Sopenharmony_ci 0, 1000, 20000, 100); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci lan743x_tx_release_all_descriptors(tx); 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci if (tx->overflow_skb) { 18608c2ecf20Sopenharmony_ci dev_kfree_skb(tx->overflow_skb); 18618c2ecf20Sopenharmony_ci tx->overflow_skb = NULL; 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci lan743x_tx_ring_cleanup(tx); 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic int lan743x_tx_open(struct lan743x_tx *tx) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = NULL; 18708c2ecf20Sopenharmony_ci u32 data = 0; 18718c2ecf20Sopenharmony_ci int ret; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci adapter = tx->adapter; 18748c2ecf20Sopenharmony_ci ret = lan743x_tx_ring_init(tx); 18758c2ecf20Sopenharmony_ci if (ret) 18768c2ecf20Sopenharmony_ci return ret; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci /* initialize fifo */ 18798c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, FCT_TX_CTL, 18808c2ecf20Sopenharmony_ci FCT_TX_CTL_RESET_(tx->channel_number)); 18818c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL, 18828c2ecf20Sopenharmony_ci FCT_TX_CTL_RESET_(tx->channel_number), 18838c2ecf20Sopenharmony_ci 0, 1000, 20000, 100); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci /* enable fifo */ 18868c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, FCT_TX_CTL, 18878c2ecf20Sopenharmony_ci FCT_TX_CTL_EN_(tx->channel_number)); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci /* reset tx channel */ 18908c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 18918c2ecf20Sopenharmony_ci DMAC_CMD_TX_SWR_(tx->channel_number)); 18928c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, DMAC_CMD, 18938c2ecf20Sopenharmony_ci DMAC_CMD_TX_SWR_(tx->channel_number), 18948c2ecf20Sopenharmony_ci 0, 1000, 20000, 100); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci /* Write TX_BASE_ADDR */ 18978c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 18988c2ecf20Sopenharmony_ci TX_BASE_ADDRH(tx->channel_number), 18998c2ecf20Sopenharmony_ci DMA_ADDR_HIGH32(tx->ring_dma_ptr)); 19008c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 19018c2ecf20Sopenharmony_ci TX_BASE_ADDRL(tx->channel_number), 19028c2ecf20Sopenharmony_ci DMA_ADDR_LOW32(tx->ring_dma_ptr)); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci /* Write TX_CFG_B */ 19058c2ecf20Sopenharmony_ci data = lan743x_csr_read(adapter, TX_CFG_B(tx->channel_number)); 19068c2ecf20Sopenharmony_ci data &= ~TX_CFG_B_TX_RING_LEN_MASK_; 19078c2ecf20Sopenharmony_ci data |= ((tx->ring_size) & TX_CFG_B_TX_RING_LEN_MASK_); 19088c2ecf20Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) 19098c2ecf20Sopenharmony_ci data |= TX_CFG_B_TDMABL_512_; 19108c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, TX_CFG_B(tx->channel_number), data); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci /* Write TX_CFG_A */ 19138c2ecf20Sopenharmony_ci data = TX_CFG_A_TX_TMR_HPWB_SEL_IOC_ | TX_CFG_A_TX_HP_WB_EN_; 19148c2ecf20Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 19158c2ecf20Sopenharmony_ci data |= TX_CFG_A_TX_HP_WB_ON_INT_TMR_; 19168c2ecf20Sopenharmony_ci data |= TX_CFG_A_TX_PF_THRES_SET_(0x10); 19178c2ecf20Sopenharmony_ci data |= TX_CFG_A_TX_PF_PRI_THRES_SET_(0x04); 19188c2ecf20Sopenharmony_ci data |= TX_CFG_A_TX_HP_WB_THRES_SET_(0x07); 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, TX_CFG_A(tx->channel_number), data); 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci /* Write TX_HEAD_WRITEBACK_ADDR */ 19238c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 19248c2ecf20Sopenharmony_ci TX_HEAD_WRITEBACK_ADDRH(tx->channel_number), 19258c2ecf20Sopenharmony_ci DMA_ADDR_HIGH32(tx->head_dma_ptr)); 19268c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 19278c2ecf20Sopenharmony_ci TX_HEAD_WRITEBACK_ADDRL(tx->channel_number), 19288c2ecf20Sopenharmony_ci DMA_ADDR_LOW32(tx->head_dma_ptr)); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* set last head */ 19318c2ecf20Sopenharmony_ci tx->last_head = lan743x_csr_read(adapter, TX_HEAD(tx->channel_number)); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci /* write TX_TAIL */ 19348c2ecf20Sopenharmony_ci tx->last_tail = 0; 19358c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, TX_TAIL(tx->channel_number), 19368c2ecf20Sopenharmony_ci (u32)(tx->last_tail)); 19378c2ecf20Sopenharmony_ci tx->vector_flags = lan743x_intr_get_vector_flags(adapter, 19388c2ecf20Sopenharmony_ci INT_BIT_DMA_TX_ 19398c2ecf20Sopenharmony_ci (tx->channel_number)); 19408c2ecf20Sopenharmony_ci netif_tx_napi_add(adapter->netdev, 19418c2ecf20Sopenharmony_ci &tx->napi, lan743x_tx_napi_poll, 19428c2ecf20Sopenharmony_ci tx->ring_size - 1); 19438c2ecf20Sopenharmony_ci napi_enable(&tx->napi); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci data = 0; 19468c2ecf20Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR) 19478c2ecf20Sopenharmony_ci data |= TX_CFG_C_TX_TOP_INT_EN_AUTO_CLR_; 19488c2ecf20Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR) 19498c2ecf20Sopenharmony_ci data |= TX_CFG_C_TX_DMA_INT_STS_AUTO_CLR_; 19508c2ecf20Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C) 19518c2ecf20Sopenharmony_ci data |= TX_CFG_C_TX_INT_STS_R2C_MODE_MASK_; 19528c2ecf20Sopenharmony_ci if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C) 19538c2ecf20Sopenharmony_ci data |= TX_CFG_C_TX_INT_EN_R2C_; 19548c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, TX_CFG_C(tx->channel_number), data); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci if (!(tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET)) 19578c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 19588c2ecf20Sopenharmony_ci INT_BIT_DMA_TX_(tx->channel_number)); 19598c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_EN_SET, 19608c2ecf20Sopenharmony_ci DMAC_INT_BIT_TX_IOC_(tx->channel_number)); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci /* start dmac channel */ 19638c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 19648c2ecf20Sopenharmony_ci DMAC_CMD_START_T_(tx->channel_number)); 19658c2ecf20Sopenharmony_ci return 0; 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_cistatic int lan743x_rx_next_index(struct lan743x_rx *rx, int index) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci return ((++index) % rx->ring_size); 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_cistatic struct sk_buff *lan743x_rx_allocate_skb(struct lan743x_rx *rx, gfp_t gfp) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci int length = 0; 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci length = (LAN743X_MAX_FRAME_SIZE + ETH_HLEN + 4 + RX_HEAD_PADDING); 19788c2ecf20Sopenharmony_ci return __netdev_alloc_skb(rx->adapter->netdev, 19798c2ecf20Sopenharmony_ci length, gfp); 19808c2ecf20Sopenharmony_ci} 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_cistatic void lan743x_rx_update_tail(struct lan743x_rx *rx, int index) 19838c2ecf20Sopenharmony_ci{ 19848c2ecf20Sopenharmony_ci /* update the tail once per 8 descriptors */ 19858c2ecf20Sopenharmony_ci if ((index & 7) == 7) 19868c2ecf20Sopenharmony_ci lan743x_csr_write(rx->adapter, RX_TAIL(rx->channel_number), 19878c2ecf20Sopenharmony_ci index); 19888c2ecf20Sopenharmony_ci} 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_cistatic int lan743x_rx_init_ring_element(struct lan743x_rx *rx, int index, 19918c2ecf20Sopenharmony_ci struct sk_buff *skb) 19928c2ecf20Sopenharmony_ci{ 19938c2ecf20Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 19948c2ecf20Sopenharmony_ci struct lan743x_rx_descriptor *descriptor; 19958c2ecf20Sopenharmony_ci int length = 0; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci length = (LAN743X_MAX_FRAME_SIZE + ETH_HLEN + 4 + RX_HEAD_PADDING); 19988c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 19998c2ecf20Sopenharmony_ci buffer_info = &rx->buffer_info[index]; 20008c2ecf20Sopenharmony_ci buffer_info->skb = skb; 20018c2ecf20Sopenharmony_ci if (!(buffer_info->skb)) 20028c2ecf20Sopenharmony_ci return -ENOMEM; 20038c2ecf20Sopenharmony_ci buffer_info->dma_ptr = dma_map_single(&rx->adapter->pdev->dev, 20048c2ecf20Sopenharmony_ci buffer_info->skb->data, 20058c2ecf20Sopenharmony_ci length, 20068c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 20078c2ecf20Sopenharmony_ci if (dma_mapping_error(&rx->adapter->pdev->dev, 20088c2ecf20Sopenharmony_ci buffer_info->dma_ptr)) { 20098c2ecf20Sopenharmony_ci buffer_info->dma_ptr = 0; 20108c2ecf20Sopenharmony_ci return -ENOMEM; 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci buffer_info->buffer_length = length; 20148c2ecf20Sopenharmony_ci descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr)); 20158c2ecf20Sopenharmony_ci descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr)); 20168c2ecf20Sopenharmony_ci descriptor->data3 = 0; 20178c2ecf20Sopenharmony_ci descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ | 20188c2ecf20Sopenharmony_ci (length & RX_DESC_DATA0_BUF_LENGTH_MASK_))); 20198c2ecf20Sopenharmony_ci skb_reserve(buffer_info->skb, RX_HEAD_PADDING); 20208c2ecf20Sopenharmony_ci lan743x_rx_update_tail(rx, index); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci return 0; 20238c2ecf20Sopenharmony_ci} 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_cistatic void lan743x_rx_reuse_ring_element(struct lan743x_rx *rx, int index) 20268c2ecf20Sopenharmony_ci{ 20278c2ecf20Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 20288c2ecf20Sopenharmony_ci struct lan743x_rx_descriptor *descriptor; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 20318c2ecf20Sopenharmony_ci buffer_info = &rx->buffer_info[index]; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr)); 20348c2ecf20Sopenharmony_ci descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr)); 20358c2ecf20Sopenharmony_ci descriptor->data3 = 0; 20368c2ecf20Sopenharmony_ci descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ | 20378c2ecf20Sopenharmony_ci ((buffer_info->buffer_length) & 20388c2ecf20Sopenharmony_ci RX_DESC_DATA0_BUF_LENGTH_MASK_))); 20398c2ecf20Sopenharmony_ci lan743x_rx_update_tail(rx, index); 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic void lan743x_rx_release_ring_element(struct lan743x_rx *rx, int index) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 20458c2ecf20Sopenharmony_ci struct lan743x_rx_descriptor *descriptor; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 20488c2ecf20Sopenharmony_ci buffer_info = &rx->buffer_info[index]; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci memset(descriptor, 0, sizeof(*descriptor)); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (buffer_info->dma_ptr) { 20538c2ecf20Sopenharmony_ci dma_unmap_single(&rx->adapter->pdev->dev, 20548c2ecf20Sopenharmony_ci buffer_info->dma_ptr, 20558c2ecf20Sopenharmony_ci buffer_info->buffer_length, 20568c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 20578c2ecf20Sopenharmony_ci buffer_info->dma_ptr = 0; 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci if (buffer_info->skb) { 20618c2ecf20Sopenharmony_ci dev_kfree_skb(buffer_info->skb); 20628c2ecf20Sopenharmony_ci buffer_info->skb = NULL; 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci memset(buffer_info, 0, sizeof(*buffer_info)); 20668c2ecf20Sopenharmony_ci} 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_cistatic int lan743x_rx_process_packet(struct lan743x_rx *rx) 20698c2ecf20Sopenharmony_ci{ 20708c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps *hwtstamps = NULL; 20718c2ecf20Sopenharmony_ci int result = RX_PROCESS_RESULT_NOTHING_TO_DO; 20728c2ecf20Sopenharmony_ci int current_head_index = le32_to_cpu(*rx->head_cpu_ptr); 20738c2ecf20Sopenharmony_ci struct lan743x_rx_buffer_info *buffer_info; 20748c2ecf20Sopenharmony_ci struct lan743x_rx_descriptor *descriptor; 20758c2ecf20Sopenharmony_ci int extension_index = -1; 20768c2ecf20Sopenharmony_ci int first_index = -1; 20778c2ecf20Sopenharmony_ci int last_index = -1; 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci if (current_head_index < 0 || current_head_index >= rx->ring_size) 20808c2ecf20Sopenharmony_ci goto done; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci if (rx->last_head < 0 || rx->last_head >= rx->ring_size) 20838c2ecf20Sopenharmony_ci goto done; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci if (rx->last_head != current_head_index) { 20868c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[rx->last_head]; 20878c2ecf20Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_OWN_) 20888c2ecf20Sopenharmony_ci goto done; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci if (!(le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_FS_)) 20918c2ecf20Sopenharmony_ci goto done; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci first_index = rx->last_head; 20948c2ecf20Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_) { 20958c2ecf20Sopenharmony_ci last_index = rx->last_head; 20968c2ecf20Sopenharmony_ci } else { 20978c2ecf20Sopenharmony_ci int index; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci index = lan743x_rx_next_index(rx, first_index); 21008c2ecf20Sopenharmony_ci while (index != current_head_index) { 21018c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 21028c2ecf20Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_OWN_) 21038c2ecf20Sopenharmony_ci goto done; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_) { 21068c2ecf20Sopenharmony_ci last_index = index; 21078c2ecf20Sopenharmony_ci break; 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci index = lan743x_rx_next_index(rx, index); 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci if (last_index >= 0) { 21138c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[last_index]; 21148c2ecf20Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_EXT_) { 21158c2ecf20Sopenharmony_ci /* extension is expected to follow */ 21168c2ecf20Sopenharmony_ci int index = lan743x_rx_next_index(rx, 21178c2ecf20Sopenharmony_ci last_index); 21188c2ecf20Sopenharmony_ci if (index != current_head_index) { 21198c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[index]; 21208c2ecf20Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & 21218c2ecf20Sopenharmony_ci RX_DESC_DATA0_OWN_) { 21228c2ecf20Sopenharmony_ci goto done; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci if (le32_to_cpu(descriptor->data0) & 21258c2ecf20Sopenharmony_ci RX_DESC_DATA0_EXT_) { 21268c2ecf20Sopenharmony_ci extension_index = index; 21278c2ecf20Sopenharmony_ci } else { 21288c2ecf20Sopenharmony_ci goto done; 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci } else { 21318c2ecf20Sopenharmony_ci /* extension is not yet available */ 21328c2ecf20Sopenharmony_ci /* prevent processing of this packet */ 21338c2ecf20Sopenharmony_ci first_index = -1; 21348c2ecf20Sopenharmony_ci last_index = -1; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci if (first_index >= 0 && last_index >= 0) { 21408c2ecf20Sopenharmony_ci int real_last_index = last_index; 21418c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 21428c2ecf20Sopenharmony_ci u32 ts_sec = 0; 21438c2ecf20Sopenharmony_ci u32 ts_nsec = 0; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci /* packet is available */ 21468c2ecf20Sopenharmony_ci if (first_index == last_index) { 21478c2ecf20Sopenharmony_ci /* single buffer packet */ 21488c2ecf20Sopenharmony_ci struct sk_buff *new_skb = NULL; 21498c2ecf20Sopenharmony_ci int packet_length; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci new_skb = lan743x_rx_allocate_skb(rx, 21528c2ecf20Sopenharmony_ci GFP_ATOMIC | GFP_DMA); 21538c2ecf20Sopenharmony_ci if (!new_skb) { 21548c2ecf20Sopenharmony_ci /* failed to allocate next skb. 21558c2ecf20Sopenharmony_ci * Memory is very low. 21568c2ecf20Sopenharmony_ci * Drop this packet and reuse buffer. 21578c2ecf20Sopenharmony_ci */ 21588c2ecf20Sopenharmony_ci lan743x_rx_reuse_ring_element(rx, first_index); 21598c2ecf20Sopenharmony_ci goto process_extension; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci buffer_info = &rx->buffer_info[first_index]; 21638c2ecf20Sopenharmony_ci skb = buffer_info->skb; 21648c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[first_index]; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci /* unmap from dma */ 21678c2ecf20Sopenharmony_ci if (buffer_info->dma_ptr) { 21688c2ecf20Sopenharmony_ci dma_unmap_single(&rx->adapter->pdev->dev, 21698c2ecf20Sopenharmony_ci buffer_info->dma_ptr, 21708c2ecf20Sopenharmony_ci buffer_info->buffer_length, 21718c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 21728c2ecf20Sopenharmony_ci buffer_info->dma_ptr = 0; 21738c2ecf20Sopenharmony_ci buffer_info->buffer_length = 0; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci buffer_info->skb = NULL; 21768c2ecf20Sopenharmony_ci packet_length = RX_DESC_DATA0_FRAME_LENGTH_GET_ 21778c2ecf20Sopenharmony_ci (le32_to_cpu(descriptor->data0)); 21788c2ecf20Sopenharmony_ci skb_put(skb, packet_length - 4); 21798c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, 21808c2ecf20Sopenharmony_ci rx->adapter->netdev); 21818c2ecf20Sopenharmony_ci lan743x_rx_init_ring_element(rx, first_index, new_skb); 21828c2ecf20Sopenharmony_ci } else { 21838c2ecf20Sopenharmony_ci int index = first_index; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci /* multi buffer packet not supported */ 21868c2ecf20Sopenharmony_ci /* this should not happen since 21878c2ecf20Sopenharmony_ci * buffers are allocated to be at least jumbo size 21888c2ecf20Sopenharmony_ci */ 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci /* clean up buffers */ 21918c2ecf20Sopenharmony_ci if (first_index <= last_index) { 21928c2ecf20Sopenharmony_ci while ((index >= first_index) && 21938c2ecf20Sopenharmony_ci (index <= last_index)) { 21948c2ecf20Sopenharmony_ci lan743x_rx_reuse_ring_element(rx, 21958c2ecf20Sopenharmony_ci index); 21968c2ecf20Sopenharmony_ci index = lan743x_rx_next_index(rx, 21978c2ecf20Sopenharmony_ci index); 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci } else { 22008c2ecf20Sopenharmony_ci while ((index >= first_index) || 22018c2ecf20Sopenharmony_ci (index <= last_index)) { 22028c2ecf20Sopenharmony_ci lan743x_rx_reuse_ring_element(rx, 22038c2ecf20Sopenharmony_ci index); 22048c2ecf20Sopenharmony_ci index = lan743x_rx_next_index(rx, 22058c2ecf20Sopenharmony_ci index); 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ciprocess_extension: 22118c2ecf20Sopenharmony_ci if (extension_index >= 0) { 22128c2ecf20Sopenharmony_ci descriptor = &rx->ring_cpu_ptr[extension_index]; 22138c2ecf20Sopenharmony_ci buffer_info = &rx->buffer_info[extension_index]; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci ts_sec = le32_to_cpu(descriptor->data1); 22168c2ecf20Sopenharmony_ci ts_nsec = (le32_to_cpu(descriptor->data2) & 22178c2ecf20Sopenharmony_ci RX_DESC_DATA2_TS_NS_MASK_); 22188c2ecf20Sopenharmony_ci lan743x_rx_reuse_ring_element(rx, extension_index); 22198c2ecf20Sopenharmony_ci real_last_index = extension_index; 22208c2ecf20Sopenharmony_ci } 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (!skb) { 22238c2ecf20Sopenharmony_ci result = RX_PROCESS_RESULT_PACKET_DROPPED; 22248c2ecf20Sopenharmony_ci goto move_forward; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci if (extension_index < 0) 22288c2ecf20Sopenharmony_ci goto pass_packet_to_os; 22298c2ecf20Sopenharmony_ci hwtstamps = skb_hwtstamps(skb); 22308c2ecf20Sopenharmony_ci if (hwtstamps) 22318c2ecf20Sopenharmony_ci hwtstamps->hwtstamp = ktime_set(ts_sec, ts_nsec); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_cipass_packet_to_os: 22348c2ecf20Sopenharmony_ci /* pass packet to OS */ 22358c2ecf20Sopenharmony_ci napi_gro_receive(&rx->napi, skb); 22368c2ecf20Sopenharmony_ci result = RX_PROCESS_RESULT_PACKET_RECEIVED; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_cimove_forward: 22398c2ecf20Sopenharmony_ci /* push tail and head forward */ 22408c2ecf20Sopenharmony_ci rx->last_tail = real_last_index; 22418c2ecf20Sopenharmony_ci rx->last_head = lan743x_rx_next_index(rx, real_last_index); 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_cidone: 22448c2ecf20Sopenharmony_ci return result; 22458c2ecf20Sopenharmony_ci} 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_cistatic int lan743x_rx_napi_poll(struct napi_struct *napi, int weight) 22488c2ecf20Sopenharmony_ci{ 22498c2ecf20Sopenharmony_ci struct lan743x_rx *rx = container_of(napi, struct lan743x_rx, napi); 22508c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 22518c2ecf20Sopenharmony_ci int result = RX_PROCESS_RESULT_NOTHING_TO_DO; 22528c2ecf20Sopenharmony_ci u32 rx_tail_flags = 0; 22538c2ecf20Sopenharmony_ci int count; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C) { 22568c2ecf20Sopenharmony_ci /* clear int status bit before reading packet */ 22578c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_STS, 22588c2ecf20Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 22598c2ecf20Sopenharmony_ci } 22608c2ecf20Sopenharmony_ci for (count = 0; count < weight; count++) { 22618c2ecf20Sopenharmony_ci result = lan743x_rx_process_packet(rx); 22628c2ecf20Sopenharmony_ci if (result == RX_PROCESS_RESULT_NOTHING_TO_DO) 22638c2ecf20Sopenharmony_ci break; 22648c2ecf20Sopenharmony_ci } 22658c2ecf20Sopenharmony_ci rx->frame_count += count; 22668c2ecf20Sopenharmony_ci if (count == weight || result == RX_PROCESS_RESULT_PACKET_RECEIVED) 22678c2ecf20Sopenharmony_ci return weight; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci if (!napi_complete_done(napi, count)) 22708c2ecf20Sopenharmony_ci return count; 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci /* re-arm interrupts, must write to rx tail on some chip variants */ 22738c2ecf20Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET) 22748c2ecf20Sopenharmony_ci rx_tail_flags |= RX_TAIL_SET_TOP_INT_VEC_EN_; 22758c2ecf20Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET) { 22768c2ecf20Sopenharmony_ci rx_tail_flags |= RX_TAIL_SET_TOP_INT_EN_; 22778c2ecf20Sopenharmony_ci } else { 22788c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 22798c2ecf20Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci if (rx_tail_flags) 22838c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RX_TAIL(rx->channel_number), 22848c2ecf20Sopenharmony_ci rx_tail_flags | rx->last_tail); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci return count; 22878c2ecf20Sopenharmony_ci} 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_cistatic void lan743x_rx_ring_cleanup(struct lan743x_rx *rx) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci if (rx->buffer_info && rx->ring_cpu_ptr) { 22928c2ecf20Sopenharmony_ci int index; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci for (index = 0; index < rx->ring_size; index++) 22958c2ecf20Sopenharmony_ci lan743x_rx_release_ring_element(rx, index); 22968c2ecf20Sopenharmony_ci } 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci if (rx->head_cpu_ptr) { 22998c2ecf20Sopenharmony_ci dma_free_coherent(&rx->adapter->pdev->dev, 23008c2ecf20Sopenharmony_ci sizeof(*rx->head_cpu_ptr), rx->head_cpu_ptr, 23018c2ecf20Sopenharmony_ci rx->head_dma_ptr); 23028c2ecf20Sopenharmony_ci rx->head_cpu_ptr = NULL; 23038c2ecf20Sopenharmony_ci rx->head_dma_ptr = 0; 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci kfree(rx->buffer_info); 23078c2ecf20Sopenharmony_ci rx->buffer_info = NULL; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci if (rx->ring_cpu_ptr) { 23108c2ecf20Sopenharmony_ci dma_free_coherent(&rx->adapter->pdev->dev, 23118c2ecf20Sopenharmony_ci rx->ring_allocation_size, rx->ring_cpu_ptr, 23128c2ecf20Sopenharmony_ci rx->ring_dma_ptr); 23138c2ecf20Sopenharmony_ci rx->ring_allocation_size = 0; 23148c2ecf20Sopenharmony_ci rx->ring_cpu_ptr = NULL; 23158c2ecf20Sopenharmony_ci rx->ring_dma_ptr = 0; 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci rx->ring_size = 0; 23198c2ecf20Sopenharmony_ci rx->last_head = 0; 23208c2ecf20Sopenharmony_ci} 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_cistatic int lan743x_rx_ring_init(struct lan743x_rx *rx) 23238c2ecf20Sopenharmony_ci{ 23248c2ecf20Sopenharmony_ci size_t ring_allocation_size = 0; 23258c2ecf20Sopenharmony_ci dma_addr_t dma_ptr = 0; 23268c2ecf20Sopenharmony_ci void *cpu_ptr = NULL; 23278c2ecf20Sopenharmony_ci int ret = -ENOMEM; 23288c2ecf20Sopenharmony_ci int index = 0; 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci rx->ring_size = LAN743X_RX_RING_SIZE; 23318c2ecf20Sopenharmony_ci if (rx->ring_size <= 1) { 23328c2ecf20Sopenharmony_ci ret = -EINVAL; 23338c2ecf20Sopenharmony_ci goto cleanup; 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci if (rx->ring_size & ~RX_CFG_B_RX_RING_LEN_MASK_) { 23368c2ecf20Sopenharmony_ci ret = -EINVAL; 23378c2ecf20Sopenharmony_ci goto cleanup; 23388c2ecf20Sopenharmony_ci } 23398c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(&rx->adapter->pdev->dev, 23408c2ecf20Sopenharmony_ci DMA_BIT_MASK(64))) { 23418c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(&rx->adapter->pdev->dev, 23428c2ecf20Sopenharmony_ci DMA_BIT_MASK(32))) { 23438c2ecf20Sopenharmony_ci dev_warn(&rx->adapter->pdev->dev, 23448c2ecf20Sopenharmony_ci "lan743x_: No suitable DMA available\n"); 23458c2ecf20Sopenharmony_ci ret = -ENOMEM; 23468c2ecf20Sopenharmony_ci goto cleanup; 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci ring_allocation_size = ALIGN(rx->ring_size * 23508c2ecf20Sopenharmony_ci sizeof(struct lan743x_rx_descriptor), 23518c2ecf20Sopenharmony_ci PAGE_SIZE); 23528c2ecf20Sopenharmony_ci dma_ptr = 0; 23538c2ecf20Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev, 23548c2ecf20Sopenharmony_ci ring_allocation_size, &dma_ptr, GFP_KERNEL); 23558c2ecf20Sopenharmony_ci if (!cpu_ptr) { 23568c2ecf20Sopenharmony_ci ret = -ENOMEM; 23578c2ecf20Sopenharmony_ci goto cleanup; 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci rx->ring_allocation_size = ring_allocation_size; 23608c2ecf20Sopenharmony_ci rx->ring_cpu_ptr = (struct lan743x_rx_descriptor *)cpu_ptr; 23618c2ecf20Sopenharmony_ci rx->ring_dma_ptr = dma_ptr; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci cpu_ptr = kcalloc(rx->ring_size, sizeof(*rx->buffer_info), 23648c2ecf20Sopenharmony_ci GFP_KERNEL); 23658c2ecf20Sopenharmony_ci if (!cpu_ptr) { 23668c2ecf20Sopenharmony_ci ret = -ENOMEM; 23678c2ecf20Sopenharmony_ci goto cleanup; 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci rx->buffer_info = (struct lan743x_rx_buffer_info *)cpu_ptr; 23708c2ecf20Sopenharmony_ci dma_ptr = 0; 23718c2ecf20Sopenharmony_ci cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev, 23728c2ecf20Sopenharmony_ci sizeof(*rx->head_cpu_ptr), &dma_ptr, 23738c2ecf20Sopenharmony_ci GFP_KERNEL); 23748c2ecf20Sopenharmony_ci if (!cpu_ptr) { 23758c2ecf20Sopenharmony_ci ret = -ENOMEM; 23768c2ecf20Sopenharmony_ci goto cleanup; 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci rx->head_cpu_ptr = cpu_ptr; 23808c2ecf20Sopenharmony_ci rx->head_dma_ptr = dma_ptr; 23818c2ecf20Sopenharmony_ci if (rx->head_dma_ptr & 0x3) { 23828c2ecf20Sopenharmony_ci ret = -ENOMEM; 23838c2ecf20Sopenharmony_ci goto cleanup; 23848c2ecf20Sopenharmony_ci } 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci rx->last_head = 0; 23878c2ecf20Sopenharmony_ci for (index = 0; index < rx->ring_size; index++) { 23888c2ecf20Sopenharmony_ci struct sk_buff *new_skb = lan743x_rx_allocate_skb(rx, 23898c2ecf20Sopenharmony_ci GFP_KERNEL); 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci ret = lan743x_rx_init_ring_element(rx, index, new_skb); 23928c2ecf20Sopenharmony_ci if (ret) 23938c2ecf20Sopenharmony_ci goto cleanup; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci return 0; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_cicleanup: 23988c2ecf20Sopenharmony_ci lan743x_rx_ring_cleanup(rx); 23998c2ecf20Sopenharmony_ci return ret; 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_cistatic void lan743x_rx_close(struct lan743x_rx *rx) 24038c2ecf20Sopenharmony_ci{ 24048c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, FCT_RX_CTL, 24078c2ecf20Sopenharmony_ci FCT_RX_CTL_DIS_(rx->channel_number)); 24088c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL, 24098c2ecf20Sopenharmony_ci FCT_RX_CTL_EN_(rx->channel_number), 24108c2ecf20Sopenharmony_ci 0, 1000, 20000, 100); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 24138c2ecf20Sopenharmony_ci DMAC_CMD_STOP_R_(rx->channel_number)); 24148c2ecf20Sopenharmony_ci lan743x_dmac_rx_wait_till_stopped(adapter, rx->channel_number); 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_EN_CLR, 24178c2ecf20Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 24188c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 24198c2ecf20Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 24208c2ecf20Sopenharmony_ci napi_disable(&rx->napi); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci netif_napi_del(&rx->napi); 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci lan743x_rx_ring_cleanup(rx); 24258c2ecf20Sopenharmony_ci} 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_cistatic int lan743x_rx_open(struct lan743x_rx *rx) 24288c2ecf20Sopenharmony_ci{ 24298c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = rx->adapter; 24308c2ecf20Sopenharmony_ci u32 data = 0; 24318c2ecf20Sopenharmony_ci int ret; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci rx->frame_count = 0; 24348c2ecf20Sopenharmony_ci ret = lan743x_rx_ring_init(rx); 24358c2ecf20Sopenharmony_ci if (ret) 24368c2ecf20Sopenharmony_ci goto return_error; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci netif_napi_add(adapter->netdev, 24398c2ecf20Sopenharmony_ci &rx->napi, lan743x_rx_napi_poll, 24408c2ecf20Sopenharmony_ci NAPI_POLL_WEIGHT); 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 24438c2ecf20Sopenharmony_ci DMAC_CMD_RX_SWR_(rx->channel_number)); 24448c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, DMAC_CMD, 24458c2ecf20Sopenharmony_ci DMAC_CMD_RX_SWR_(rx->channel_number), 24468c2ecf20Sopenharmony_ci 0, 1000, 20000, 100); 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci /* set ring base address */ 24498c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 24508c2ecf20Sopenharmony_ci RX_BASE_ADDRH(rx->channel_number), 24518c2ecf20Sopenharmony_ci DMA_ADDR_HIGH32(rx->ring_dma_ptr)); 24528c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 24538c2ecf20Sopenharmony_ci RX_BASE_ADDRL(rx->channel_number), 24548c2ecf20Sopenharmony_ci DMA_ADDR_LOW32(rx->ring_dma_ptr)); 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci /* set rx write back address */ 24578c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 24588c2ecf20Sopenharmony_ci RX_HEAD_WRITEBACK_ADDRH(rx->channel_number), 24598c2ecf20Sopenharmony_ci DMA_ADDR_HIGH32(rx->head_dma_ptr)); 24608c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 24618c2ecf20Sopenharmony_ci RX_HEAD_WRITEBACK_ADDRL(rx->channel_number), 24628c2ecf20Sopenharmony_ci DMA_ADDR_LOW32(rx->head_dma_ptr)); 24638c2ecf20Sopenharmony_ci data = RX_CFG_A_RX_HP_WB_EN_; 24648c2ecf20Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) { 24658c2ecf20Sopenharmony_ci data |= (RX_CFG_A_RX_WB_ON_INT_TMR_ | 24668c2ecf20Sopenharmony_ci RX_CFG_A_RX_WB_THRES_SET_(0x7) | 24678c2ecf20Sopenharmony_ci RX_CFG_A_RX_PF_THRES_SET_(16) | 24688c2ecf20Sopenharmony_ci RX_CFG_A_RX_PF_PRI_THRES_SET_(4)); 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci /* set RX_CFG_A */ 24728c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, 24738c2ecf20Sopenharmony_ci RX_CFG_A(rx->channel_number), data); 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci /* set RX_CFG_B */ 24768c2ecf20Sopenharmony_ci data = lan743x_csr_read(adapter, RX_CFG_B(rx->channel_number)); 24778c2ecf20Sopenharmony_ci data &= ~RX_CFG_B_RX_PAD_MASK_; 24788c2ecf20Sopenharmony_ci if (!RX_HEAD_PADDING) 24798c2ecf20Sopenharmony_ci data |= RX_CFG_B_RX_PAD_0_; 24808c2ecf20Sopenharmony_ci else 24818c2ecf20Sopenharmony_ci data |= RX_CFG_B_RX_PAD_2_; 24828c2ecf20Sopenharmony_ci data &= ~RX_CFG_B_RX_RING_LEN_MASK_; 24838c2ecf20Sopenharmony_ci data |= ((rx->ring_size) & RX_CFG_B_RX_RING_LEN_MASK_); 24848c2ecf20Sopenharmony_ci data |= RX_CFG_B_TS_ALL_RX_; 24858c2ecf20Sopenharmony_ci if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) 24868c2ecf20Sopenharmony_ci data |= RX_CFG_B_RDMABL_512_; 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RX_CFG_B(rx->channel_number), data); 24898c2ecf20Sopenharmony_ci rx->vector_flags = lan743x_intr_get_vector_flags(adapter, 24908c2ecf20Sopenharmony_ci INT_BIT_DMA_RX_ 24918c2ecf20Sopenharmony_ci (rx->channel_number)); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci /* set RX_CFG_C */ 24948c2ecf20Sopenharmony_ci data = 0; 24958c2ecf20Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR) 24968c2ecf20Sopenharmony_ci data |= RX_CFG_C_RX_TOP_INT_EN_AUTO_CLR_; 24978c2ecf20Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR) 24988c2ecf20Sopenharmony_ci data |= RX_CFG_C_RX_DMA_INT_STS_AUTO_CLR_; 24998c2ecf20Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C) 25008c2ecf20Sopenharmony_ci data |= RX_CFG_C_RX_INT_STS_R2C_MODE_MASK_; 25018c2ecf20Sopenharmony_ci if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C) 25028c2ecf20Sopenharmony_ci data |= RX_CFG_C_RX_INT_EN_R2C_; 25038c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RX_CFG_C(rx->channel_number), data); 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci rx->last_tail = ((u32)(rx->ring_size - 1)); 25068c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RX_TAIL(rx->channel_number), 25078c2ecf20Sopenharmony_ci rx->last_tail); 25088c2ecf20Sopenharmony_ci rx->last_head = lan743x_csr_read(adapter, RX_HEAD(rx->channel_number)); 25098c2ecf20Sopenharmony_ci if (rx->last_head) { 25108c2ecf20Sopenharmony_ci ret = -EIO; 25118c2ecf20Sopenharmony_ci goto napi_delete; 25128c2ecf20Sopenharmony_ci } 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci napi_enable(&rx->napi); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, 25178c2ecf20Sopenharmony_ci INT_BIT_DMA_RX_(rx->channel_number)); 25188c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_STS, 25198c2ecf20Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 25208c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_INT_EN_SET, 25218c2ecf20Sopenharmony_ci DMAC_INT_BIT_RXFRM_(rx->channel_number)); 25228c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, DMAC_CMD, 25238c2ecf20Sopenharmony_ci DMAC_CMD_START_R_(rx->channel_number)); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci /* initialize fifo */ 25268c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, FCT_RX_CTL, 25278c2ecf20Sopenharmony_ci FCT_RX_CTL_RESET_(rx->channel_number)); 25288c2ecf20Sopenharmony_ci lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL, 25298c2ecf20Sopenharmony_ci FCT_RX_CTL_RESET_(rx->channel_number), 25308c2ecf20Sopenharmony_ci 0, 1000, 20000, 100); 25318c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, FCT_FLOW(rx->channel_number), 25328c2ecf20Sopenharmony_ci FCT_FLOW_CTL_REQ_EN_ | 25338c2ecf20Sopenharmony_ci FCT_FLOW_CTL_ON_THRESHOLD_SET_(0x2A) | 25348c2ecf20Sopenharmony_ci FCT_FLOW_CTL_OFF_THRESHOLD_SET_(0xA)); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci /* enable fifo */ 25378c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, FCT_RX_CTL, 25388c2ecf20Sopenharmony_ci FCT_RX_CTL_EN_(rx->channel_number)); 25398c2ecf20Sopenharmony_ci return 0; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_cinapi_delete: 25428c2ecf20Sopenharmony_ci netif_napi_del(&rx->napi); 25438c2ecf20Sopenharmony_ci lan743x_rx_ring_cleanup(rx); 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_cireturn_error: 25468c2ecf20Sopenharmony_ci return ret; 25478c2ecf20Sopenharmony_ci} 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_cistatic int lan743x_netdev_close(struct net_device *netdev) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 25528c2ecf20Sopenharmony_ci int index; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci lan743x_tx_close(&adapter->tx[0]); 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) 25578c2ecf20Sopenharmony_ci lan743x_rx_close(&adapter->rx[index]); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci lan743x_ptp_close(adapter); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci lan743x_phy_close(adapter); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci lan743x_mac_close(adapter); 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci lan743x_intr_close(adapter); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci return 0; 25688c2ecf20Sopenharmony_ci} 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_cistatic int lan743x_netdev_open(struct net_device *netdev) 25718c2ecf20Sopenharmony_ci{ 25728c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 25738c2ecf20Sopenharmony_ci int index; 25748c2ecf20Sopenharmony_ci int ret; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci ret = lan743x_intr_open(adapter); 25778c2ecf20Sopenharmony_ci if (ret) 25788c2ecf20Sopenharmony_ci goto return_error; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci ret = lan743x_mac_open(adapter); 25818c2ecf20Sopenharmony_ci if (ret) 25828c2ecf20Sopenharmony_ci goto close_intr; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci ret = lan743x_phy_open(adapter); 25858c2ecf20Sopenharmony_ci if (ret) 25868c2ecf20Sopenharmony_ci goto close_mac; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci ret = lan743x_ptp_open(adapter); 25898c2ecf20Sopenharmony_ci if (ret) 25908c2ecf20Sopenharmony_ci goto close_phy; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci lan743x_rfe_open(adapter); 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) { 25958c2ecf20Sopenharmony_ci ret = lan743x_rx_open(&adapter->rx[index]); 25968c2ecf20Sopenharmony_ci if (ret) 25978c2ecf20Sopenharmony_ci goto close_rx; 25988c2ecf20Sopenharmony_ci } 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci ret = lan743x_tx_open(&adapter->tx[0]); 26018c2ecf20Sopenharmony_ci if (ret) 26028c2ecf20Sopenharmony_ci goto close_rx; 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci return 0; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ciclose_rx: 26078c2ecf20Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) { 26088c2ecf20Sopenharmony_ci if (adapter->rx[index].ring_cpu_ptr) 26098c2ecf20Sopenharmony_ci lan743x_rx_close(&adapter->rx[index]); 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci lan743x_ptp_close(adapter); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ciclose_phy: 26148c2ecf20Sopenharmony_ci lan743x_phy_close(adapter); 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ciclose_mac: 26178c2ecf20Sopenharmony_ci lan743x_mac_close(adapter); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ciclose_intr: 26208c2ecf20Sopenharmony_ci lan743x_intr_close(adapter); 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_cireturn_error: 26238c2ecf20Sopenharmony_ci netif_warn(adapter, ifup, adapter->netdev, 26248c2ecf20Sopenharmony_ci "Error opening LAN743x\n"); 26258c2ecf20Sopenharmony_ci return ret; 26268c2ecf20Sopenharmony_ci} 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_cistatic netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb, 26298c2ecf20Sopenharmony_ci struct net_device *netdev) 26308c2ecf20Sopenharmony_ci{ 26318c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci return lan743x_tx_xmit_frame(&adapter->tx[0], skb); 26348c2ecf20Sopenharmony_ci} 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_cistatic int lan743x_netdev_ioctl(struct net_device *netdev, 26378c2ecf20Sopenharmony_ci struct ifreq *ifr, int cmd) 26388c2ecf20Sopenharmony_ci{ 26398c2ecf20Sopenharmony_ci if (!netif_running(netdev)) 26408c2ecf20Sopenharmony_ci return -EINVAL; 26418c2ecf20Sopenharmony_ci if (cmd == SIOCSHWTSTAMP) 26428c2ecf20Sopenharmony_ci return lan743x_ptp_ioctl(netdev, ifr, cmd); 26438c2ecf20Sopenharmony_ci return phy_mii_ioctl(netdev->phydev, ifr, cmd); 26448c2ecf20Sopenharmony_ci} 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_cistatic void lan743x_netdev_set_multicast(struct net_device *netdev) 26478c2ecf20Sopenharmony_ci{ 26488c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci lan743x_rfe_set_multicast(adapter); 26518c2ecf20Sopenharmony_ci} 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_cistatic int lan743x_netdev_change_mtu(struct net_device *netdev, int new_mtu) 26548c2ecf20Sopenharmony_ci{ 26558c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 26568c2ecf20Sopenharmony_ci int ret = 0; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci ret = lan743x_mac_set_mtu(adapter, new_mtu); 26598c2ecf20Sopenharmony_ci if (!ret) 26608c2ecf20Sopenharmony_ci netdev->mtu = new_mtu; 26618c2ecf20Sopenharmony_ci return ret; 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic void lan743x_netdev_get_stats64(struct net_device *netdev, 26658c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 26668c2ecf20Sopenharmony_ci{ 26678c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci stats->rx_packets = lan743x_csr_read(adapter, STAT_RX_TOTAL_FRAMES); 26708c2ecf20Sopenharmony_ci stats->tx_packets = lan743x_csr_read(adapter, STAT_TX_TOTAL_FRAMES); 26718c2ecf20Sopenharmony_ci stats->rx_bytes = lan743x_csr_read(adapter, 26728c2ecf20Sopenharmony_ci STAT_RX_UNICAST_BYTE_COUNT) + 26738c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26748c2ecf20Sopenharmony_ci STAT_RX_BROADCAST_BYTE_COUNT) + 26758c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26768c2ecf20Sopenharmony_ci STAT_RX_MULTICAST_BYTE_COUNT); 26778c2ecf20Sopenharmony_ci stats->tx_bytes = lan743x_csr_read(adapter, 26788c2ecf20Sopenharmony_ci STAT_TX_UNICAST_BYTE_COUNT) + 26798c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26808c2ecf20Sopenharmony_ci STAT_TX_BROADCAST_BYTE_COUNT) + 26818c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26828c2ecf20Sopenharmony_ci STAT_TX_MULTICAST_BYTE_COUNT); 26838c2ecf20Sopenharmony_ci stats->rx_errors = lan743x_csr_read(adapter, STAT_RX_FCS_ERRORS) + 26848c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26858c2ecf20Sopenharmony_ci STAT_RX_ALIGNMENT_ERRORS) + 26868c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, STAT_RX_JABBER_ERRORS) + 26878c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26888c2ecf20Sopenharmony_ci STAT_RX_UNDERSIZE_FRAME_ERRORS) + 26898c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26908c2ecf20Sopenharmony_ci STAT_RX_OVERSIZE_FRAME_ERRORS); 26918c2ecf20Sopenharmony_ci stats->tx_errors = lan743x_csr_read(adapter, STAT_TX_FCS_ERRORS) + 26928c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 26938c2ecf20Sopenharmony_ci STAT_TX_EXCESS_DEFERRAL_ERRORS) + 26948c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, STAT_TX_CARRIER_ERRORS); 26958c2ecf20Sopenharmony_ci stats->rx_dropped = lan743x_csr_read(adapter, 26968c2ecf20Sopenharmony_ci STAT_RX_DROPPED_FRAMES); 26978c2ecf20Sopenharmony_ci stats->tx_dropped = lan743x_csr_read(adapter, 26988c2ecf20Sopenharmony_ci STAT_TX_EXCESSIVE_COLLISION); 26998c2ecf20Sopenharmony_ci stats->multicast = lan743x_csr_read(adapter, 27008c2ecf20Sopenharmony_ci STAT_RX_MULTICAST_FRAMES) + 27018c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 27028c2ecf20Sopenharmony_ci STAT_TX_MULTICAST_FRAMES); 27038c2ecf20Sopenharmony_ci stats->collisions = lan743x_csr_read(adapter, 27048c2ecf20Sopenharmony_ci STAT_TX_SINGLE_COLLISIONS) + 27058c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 27068c2ecf20Sopenharmony_ci STAT_TX_MULTIPLE_COLLISIONS) + 27078c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 27088c2ecf20Sopenharmony_ci STAT_TX_LATE_COLLISIONS); 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_cistatic int lan743x_netdev_set_mac_address(struct net_device *netdev, 27128c2ecf20Sopenharmony_ci void *addr) 27138c2ecf20Sopenharmony_ci{ 27148c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 27158c2ecf20Sopenharmony_ci struct sockaddr *sock_addr = addr; 27168c2ecf20Sopenharmony_ci int ret; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci ret = eth_prepare_mac_addr_change(netdev, sock_addr); 27198c2ecf20Sopenharmony_ci if (ret) 27208c2ecf20Sopenharmony_ci return ret; 27218c2ecf20Sopenharmony_ci ether_addr_copy(netdev->dev_addr, sock_addr->sa_data); 27228c2ecf20Sopenharmony_ci lan743x_mac_set_address(adapter, sock_addr->sa_data); 27238c2ecf20Sopenharmony_ci lan743x_rfe_update_mac_address(adapter); 27248c2ecf20Sopenharmony_ci return 0; 27258c2ecf20Sopenharmony_ci} 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_cistatic const struct net_device_ops lan743x_netdev_ops = { 27288c2ecf20Sopenharmony_ci .ndo_open = lan743x_netdev_open, 27298c2ecf20Sopenharmony_ci .ndo_stop = lan743x_netdev_close, 27308c2ecf20Sopenharmony_ci .ndo_start_xmit = lan743x_netdev_xmit_frame, 27318c2ecf20Sopenharmony_ci .ndo_do_ioctl = lan743x_netdev_ioctl, 27328c2ecf20Sopenharmony_ci .ndo_set_rx_mode = lan743x_netdev_set_multicast, 27338c2ecf20Sopenharmony_ci .ndo_change_mtu = lan743x_netdev_change_mtu, 27348c2ecf20Sopenharmony_ci .ndo_get_stats64 = lan743x_netdev_get_stats64, 27358c2ecf20Sopenharmony_ci .ndo_set_mac_address = lan743x_netdev_set_mac_address, 27368c2ecf20Sopenharmony_ci}; 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_cistatic void lan743x_hardware_cleanup(struct lan743x_adapter *adapter) 27398c2ecf20Sopenharmony_ci{ 27408c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF); 27418c2ecf20Sopenharmony_ci} 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_cistatic void lan743x_mdiobus_cleanup(struct lan743x_adapter *adapter) 27448c2ecf20Sopenharmony_ci{ 27458c2ecf20Sopenharmony_ci mdiobus_unregister(adapter->mdiobus); 27468c2ecf20Sopenharmony_ci} 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_cistatic void lan743x_full_cleanup(struct lan743x_adapter *adapter) 27498c2ecf20Sopenharmony_ci{ 27508c2ecf20Sopenharmony_ci unregister_netdev(adapter->netdev); 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci lan743x_mdiobus_cleanup(adapter); 27538c2ecf20Sopenharmony_ci lan743x_hardware_cleanup(adapter); 27548c2ecf20Sopenharmony_ci lan743x_pci_cleanup(adapter); 27558c2ecf20Sopenharmony_ci} 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_cistatic int lan743x_hardware_init(struct lan743x_adapter *adapter, 27588c2ecf20Sopenharmony_ci struct pci_dev *pdev) 27598c2ecf20Sopenharmony_ci{ 27608c2ecf20Sopenharmony_ci struct lan743x_tx *tx; 27618c2ecf20Sopenharmony_ci int index; 27628c2ecf20Sopenharmony_ci int ret; 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci adapter->intr.irq = adapter->pdev->irq; 27658c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF); 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci ret = lan743x_gpio_init(adapter); 27688c2ecf20Sopenharmony_ci if (ret) 27698c2ecf20Sopenharmony_ci return ret; 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci ret = lan743x_mac_init(adapter); 27728c2ecf20Sopenharmony_ci if (ret) 27738c2ecf20Sopenharmony_ci return ret; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci ret = lan743x_phy_init(adapter); 27768c2ecf20Sopenharmony_ci if (ret) 27778c2ecf20Sopenharmony_ci return ret; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci ret = lan743x_ptp_init(adapter); 27808c2ecf20Sopenharmony_ci if (ret) 27818c2ecf20Sopenharmony_ci return ret; 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci lan743x_rfe_update_mac_address(adapter); 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_ci ret = lan743x_dmac_init(adapter); 27868c2ecf20Sopenharmony_ci if (ret) 27878c2ecf20Sopenharmony_ci return ret; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) { 27908c2ecf20Sopenharmony_ci adapter->rx[index].adapter = adapter; 27918c2ecf20Sopenharmony_ci adapter->rx[index].channel_number = index; 27928c2ecf20Sopenharmony_ci } 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci tx = &adapter->tx[0]; 27958c2ecf20Sopenharmony_ci tx->adapter = adapter; 27968c2ecf20Sopenharmony_ci tx->channel_number = 0; 27978c2ecf20Sopenharmony_ci spin_lock_init(&tx->ring_lock); 27988c2ecf20Sopenharmony_ci return 0; 27998c2ecf20Sopenharmony_ci} 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_cistatic int lan743x_mdiobus_init(struct lan743x_adapter *adapter) 28028c2ecf20Sopenharmony_ci{ 28038c2ecf20Sopenharmony_ci int ret; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci adapter->mdiobus = devm_mdiobus_alloc(&adapter->pdev->dev); 28068c2ecf20Sopenharmony_ci if (!(adapter->mdiobus)) { 28078c2ecf20Sopenharmony_ci ret = -ENOMEM; 28088c2ecf20Sopenharmony_ci goto return_error; 28098c2ecf20Sopenharmony_ci } 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci adapter->mdiobus->priv = (void *)adapter; 28128c2ecf20Sopenharmony_ci adapter->mdiobus->read = lan743x_mdiobus_read; 28138c2ecf20Sopenharmony_ci adapter->mdiobus->write = lan743x_mdiobus_write; 28148c2ecf20Sopenharmony_ci adapter->mdiobus->name = "lan743x-mdiobus"; 28158c2ecf20Sopenharmony_ci snprintf(adapter->mdiobus->id, MII_BUS_ID_SIZE, 28168c2ecf20Sopenharmony_ci "pci-%s", pci_name(adapter->pdev)); 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci if ((adapter->csr.id_rev & ID_REV_ID_MASK_) == ID_REV_ID_LAN7430_) 28198c2ecf20Sopenharmony_ci /* LAN7430 uses internal phy at address 1 */ 28208c2ecf20Sopenharmony_ci adapter->mdiobus->phy_mask = ~(u32)BIT(1); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci /* register mdiobus */ 28238c2ecf20Sopenharmony_ci ret = mdiobus_register(adapter->mdiobus); 28248c2ecf20Sopenharmony_ci if (ret < 0) 28258c2ecf20Sopenharmony_ci goto return_error; 28268c2ecf20Sopenharmony_ci return 0; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_cireturn_error: 28298c2ecf20Sopenharmony_ci return ret; 28308c2ecf20Sopenharmony_ci} 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci/* lan743x_pcidev_probe - Device Initialization Routine 28338c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 28348c2ecf20Sopenharmony_ci * @id: entry in lan743x_pci_tbl 28358c2ecf20Sopenharmony_ci * 28368c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 28378c2ecf20Sopenharmony_ci * 28388c2ecf20Sopenharmony_ci * initializes an adapter identified by a pci_dev structure. 28398c2ecf20Sopenharmony_ci * The OS initialization, configuring of the adapter private structure, 28408c2ecf20Sopenharmony_ci * and a hardware reset occur. 28418c2ecf20Sopenharmony_ci **/ 28428c2ecf20Sopenharmony_cistatic int lan743x_pcidev_probe(struct pci_dev *pdev, 28438c2ecf20Sopenharmony_ci const struct pci_device_id *id) 28448c2ecf20Sopenharmony_ci{ 28458c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = NULL; 28468c2ecf20Sopenharmony_ci struct net_device *netdev = NULL; 28478c2ecf20Sopenharmony_ci const void *mac_addr; 28488c2ecf20Sopenharmony_ci int ret = -ENODEV; 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci netdev = devm_alloc_etherdev(&pdev->dev, 28518c2ecf20Sopenharmony_ci sizeof(struct lan743x_adapter)); 28528c2ecf20Sopenharmony_ci if (!netdev) 28538c2ecf20Sopenharmony_ci goto return_error; 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 28568c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, netdev); 28578c2ecf20Sopenharmony_ci adapter = netdev_priv(netdev); 28588c2ecf20Sopenharmony_ci adapter->netdev = netdev; 28598c2ecf20Sopenharmony_ci adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE | 28608c2ecf20Sopenharmony_ci NETIF_MSG_LINK | NETIF_MSG_IFUP | 28618c2ecf20Sopenharmony_ci NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED; 28628c2ecf20Sopenharmony_ci netdev->max_mtu = LAN743X_MAX_FRAME_SIZE; 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci mac_addr = of_get_mac_address(pdev->dev.of_node); 28658c2ecf20Sopenharmony_ci if (!IS_ERR(mac_addr)) 28668c2ecf20Sopenharmony_ci ether_addr_copy(adapter->mac_address, mac_addr); 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci ret = lan743x_pci_init(adapter, pdev); 28698c2ecf20Sopenharmony_ci if (ret) 28708c2ecf20Sopenharmony_ci goto return_error; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci ret = lan743x_csr_init(adapter); 28738c2ecf20Sopenharmony_ci if (ret) 28748c2ecf20Sopenharmony_ci goto cleanup_pci; 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci ret = lan743x_hardware_init(adapter, pdev); 28778c2ecf20Sopenharmony_ci if (ret) 28788c2ecf20Sopenharmony_ci goto cleanup_pci; 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci ret = lan743x_mdiobus_init(adapter); 28818c2ecf20Sopenharmony_ci if (ret) 28828c2ecf20Sopenharmony_ci goto cleanup_hardware; 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci adapter->netdev->netdev_ops = &lan743x_netdev_ops; 28858c2ecf20Sopenharmony_ci adapter->netdev->ethtool_ops = &lan743x_ethtool_ops; 28868c2ecf20Sopenharmony_ci adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM; 28878c2ecf20Sopenharmony_ci adapter->netdev->hw_features = adapter->netdev->features; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci /* carrier off reporting is important to ethtool even BEFORE open */ 28908c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci ret = register_netdev(adapter->netdev); 28938c2ecf20Sopenharmony_ci if (ret < 0) 28948c2ecf20Sopenharmony_ci goto cleanup_mdiobus; 28958c2ecf20Sopenharmony_ci return 0; 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_cicleanup_mdiobus: 28988c2ecf20Sopenharmony_ci lan743x_mdiobus_cleanup(adapter); 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_cicleanup_hardware: 29018c2ecf20Sopenharmony_ci lan743x_hardware_cleanup(adapter); 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_cicleanup_pci: 29048c2ecf20Sopenharmony_ci lan743x_pci_cleanup(adapter); 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_cireturn_error: 29078c2ecf20Sopenharmony_ci pr_warn("Initialization failed\n"); 29088c2ecf20Sopenharmony_ci return ret; 29098c2ecf20Sopenharmony_ci} 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci/** 29128c2ecf20Sopenharmony_ci * lan743x_pcidev_remove - Device Removal Routine 29138c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 29148c2ecf20Sopenharmony_ci * 29158c2ecf20Sopenharmony_ci * this is called by the PCI subsystem to alert the driver 29168c2ecf20Sopenharmony_ci * that it should release a PCI device. This could be caused by a 29178c2ecf20Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from 29188c2ecf20Sopenharmony_ci * memory. 29198c2ecf20Sopenharmony_ci **/ 29208c2ecf20Sopenharmony_cistatic void lan743x_pcidev_remove(struct pci_dev *pdev) 29218c2ecf20Sopenharmony_ci{ 29228c2ecf20Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 29238c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci lan743x_full_cleanup(adapter); 29268c2ecf20Sopenharmony_ci} 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_cistatic void lan743x_pcidev_shutdown(struct pci_dev *pdev) 29298c2ecf20Sopenharmony_ci{ 29308c2ecf20Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 29318c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci rtnl_lock(); 29348c2ecf20Sopenharmony_ci netif_device_detach(netdev); 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci /* close netdev when netdev is at running state. 29378c2ecf20Sopenharmony_ci * For instance, it is true when system goes to sleep by pm-suspend 29388c2ecf20Sopenharmony_ci * However, it is false when system goes to sleep by suspend GUI menu 29398c2ecf20Sopenharmony_ci */ 29408c2ecf20Sopenharmony_ci if (netif_running(netdev)) 29418c2ecf20Sopenharmony_ci lan743x_netdev_close(netdev); 29428c2ecf20Sopenharmony_ci rtnl_unlock(); 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 29458c2ecf20Sopenharmony_ci pci_save_state(pdev); 29468c2ecf20Sopenharmony_ci#endif 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci /* clean up lan743x portion */ 29498c2ecf20Sopenharmony_ci lan743x_hardware_cleanup(adapter); 29508c2ecf20Sopenharmony_ci} 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 29538c2ecf20Sopenharmony_cistatic u16 lan743x_pm_wakeframe_crc16(const u8 *buf, int len) 29548c2ecf20Sopenharmony_ci{ 29558c2ecf20Sopenharmony_ci return bitrev16(crc16(0xFFFF, buf, len)); 29568c2ecf20Sopenharmony_ci} 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_cistatic void lan743x_pm_set_wol(struct lan743x_adapter *adapter) 29598c2ecf20Sopenharmony_ci{ 29608c2ecf20Sopenharmony_ci const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E }; 29618c2ecf20Sopenharmony_ci const u8 ipv6_multicast[3] = { 0x33, 0x33 }; 29628c2ecf20Sopenharmony_ci const u8 arp_type[2] = { 0x08, 0x06 }; 29638c2ecf20Sopenharmony_ci int mask_index; 29648c2ecf20Sopenharmony_ci u32 pmtctl; 29658c2ecf20Sopenharmony_ci u32 wucsr; 29668c2ecf20Sopenharmony_ci u32 macrx; 29678c2ecf20Sopenharmony_ci u16 crc; 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci for (mask_index = 0; mask_index < MAC_NUM_OF_WUF_CFG; mask_index++) 29708c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 0); 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci /* clear wake settings */ 29738c2ecf20Sopenharmony_ci pmtctl = lan743x_csr_read(adapter, PMT_CTL); 29748c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_WUPS_MASK_; 29758c2ecf20Sopenharmony_ci pmtctl &= ~(PMT_CTL_GPIO_WAKEUP_EN_ | PMT_CTL_EEE_WAKEUP_EN_ | 29768c2ecf20Sopenharmony_ci PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ | 29778c2ecf20Sopenharmony_ci PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ | PMT_CTL_ETH_PHY_WAKE_EN_); 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci macrx = lan743x_csr_read(adapter, MAC_RX); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci wucsr = 0; 29828c2ecf20Sopenharmony_ci mask_index = 0; 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_ETH_PHY_D3_COLD_OVR_ | PMT_CTL_ETH_PHY_D3_OVR_; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci if (adapter->wolopts & WAKE_PHY) { 29878c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_ETH_PHY_EDPD_PLL_CTL_; 29888c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_ETH_PHY_WAKE_EN_; 29898c2ecf20Sopenharmony_ci } 29908c2ecf20Sopenharmony_ci if (adapter->wolopts & WAKE_MAGIC) { 29918c2ecf20Sopenharmony_ci wucsr |= MAC_WUCSR_MPEN_; 29928c2ecf20Sopenharmony_ci macrx |= MAC_RX_RXEN_; 29938c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 29948c2ecf20Sopenharmony_ci } 29958c2ecf20Sopenharmony_ci if (adapter->wolopts & WAKE_UCAST) { 29968c2ecf20Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_PFDA_EN_; 29978c2ecf20Sopenharmony_ci macrx |= MAC_RX_RXEN_; 29988c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 29998c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 30008c2ecf20Sopenharmony_ci } 30018c2ecf20Sopenharmony_ci if (adapter->wolopts & WAKE_BCAST) { 30028c2ecf20Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_BCST_EN_; 30038c2ecf20Sopenharmony_ci macrx |= MAC_RX_RXEN_; 30048c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 30058c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 30068c2ecf20Sopenharmony_ci } 30078c2ecf20Sopenharmony_ci if (adapter->wolopts & WAKE_MCAST) { 30088c2ecf20Sopenharmony_ci /* IPv4 multicast */ 30098c2ecf20Sopenharmony_ci crc = lan743x_pm_wakeframe_crc16(ipv4_multicast, 3); 30108c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 30118c2ecf20Sopenharmony_ci MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ | 30128c2ecf20Sopenharmony_ci (0 << MAC_WUF_CFG_OFFSET_SHIFT_) | 30138c2ecf20Sopenharmony_ci (crc & MAC_WUF_CFG_CRC16_MASK_)); 30148c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 7); 30158c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0); 30168c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0); 30178c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0); 30188c2ecf20Sopenharmony_ci mask_index++; 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci /* IPv6 multicast */ 30218c2ecf20Sopenharmony_ci crc = lan743x_pm_wakeframe_crc16(ipv6_multicast, 2); 30228c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 30238c2ecf20Sopenharmony_ci MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ | 30248c2ecf20Sopenharmony_ci (0 << MAC_WUF_CFG_OFFSET_SHIFT_) | 30258c2ecf20Sopenharmony_ci (crc & MAC_WUF_CFG_CRC16_MASK_)); 30268c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 3); 30278c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0); 30288c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0); 30298c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0); 30308c2ecf20Sopenharmony_ci mask_index++; 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_; 30338c2ecf20Sopenharmony_ci macrx |= MAC_RX_RXEN_; 30348c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 30358c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 30368c2ecf20Sopenharmony_ci } 30378c2ecf20Sopenharmony_ci if (adapter->wolopts & WAKE_ARP) { 30388c2ecf20Sopenharmony_ci /* set MAC_WUF_CFG & WUF_MASK 30398c2ecf20Sopenharmony_ci * for packettype (offset 12,13) = ARP (0x0806) 30408c2ecf20Sopenharmony_ci */ 30418c2ecf20Sopenharmony_ci crc = lan743x_pm_wakeframe_crc16(arp_type, 2); 30428c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 30438c2ecf20Sopenharmony_ci MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_ALL_ | 30448c2ecf20Sopenharmony_ci (0 << MAC_WUF_CFG_OFFSET_SHIFT_) | 30458c2ecf20Sopenharmony_ci (crc & MAC_WUF_CFG_CRC16_MASK_)); 30468c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 0x3000); 30478c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0); 30488c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0); 30498c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0); 30508c2ecf20Sopenharmony_ci mask_index++; 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_; 30538c2ecf20Sopenharmony_ci macrx |= MAC_RX_RXEN_; 30548c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_; 30558c2ecf20Sopenharmony_ci pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_; 30568c2ecf20Sopenharmony_ci } 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUCSR, wucsr); 30598c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, PMT_CTL, pmtctl); 30608c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_RX, macrx); 30618c2ecf20Sopenharmony_ci} 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_cistatic int lan743x_pm_suspend(struct device *dev) 30648c2ecf20Sopenharmony_ci{ 30658c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 30668c2ecf20Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 30678c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci lan743x_pcidev_shutdown(pdev); 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci /* clear all wakes */ 30728c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUCSR, 0); 30738c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WUCSR2, 0); 30748c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_WK_SRC, 0xFFFFFFFF); 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci if (adapter->wolopts) 30778c2ecf20Sopenharmony_ci lan743x_pm_set_wol(adapter); 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci /* Host sets PME_En, put D3hot */ 30808c2ecf20Sopenharmony_ci return pci_prepare_to_sleep(pdev);; 30818c2ecf20Sopenharmony_ci} 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_cistatic int lan743x_pm_resume(struct device *dev) 30848c2ecf20Sopenharmony_ci{ 30858c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 30868c2ecf20Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 30878c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 30888c2ecf20Sopenharmony_ci int ret; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 30918c2ecf20Sopenharmony_ci pci_restore_state(pdev); 30928c2ecf20Sopenharmony_ci pci_save_state(pdev); 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci ret = lan743x_hardware_init(adapter, pdev); 30958c2ecf20Sopenharmony_ci if (ret) { 30968c2ecf20Sopenharmony_ci netif_err(adapter, probe, adapter->netdev, 30978c2ecf20Sopenharmony_ci "lan743x_hardware_init returned %d\n", ret); 30988c2ecf20Sopenharmony_ci lan743x_pci_cleanup(adapter); 30998c2ecf20Sopenharmony_ci return ret; 31008c2ecf20Sopenharmony_ci } 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci /* open netdev when netdev is at running state while resume. 31038c2ecf20Sopenharmony_ci * For instance, it is true when system wakesup after pm-suspend 31048c2ecf20Sopenharmony_ci * However, it is false when system wakes up after suspend GUI menu 31058c2ecf20Sopenharmony_ci */ 31068c2ecf20Sopenharmony_ci if (netif_running(netdev)) 31078c2ecf20Sopenharmony_ci lan743x_netdev_open(netdev); 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci netif_device_attach(netdev); 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci return 0; 31128c2ecf20Sopenharmony_ci} 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_cistatic const struct dev_pm_ops lan743x_pm_ops = { 31158c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(lan743x_pm_suspend, lan743x_pm_resume) 31168c2ecf20Sopenharmony_ci}; 31178c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_cistatic const struct pci_device_id lan743x_pcidev_tbl[] = { 31208c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7430) }, 31218c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7431) }, 31228c2ecf20Sopenharmony_ci { 0, } 31238c2ecf20Sopenharmony_ci}; 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, lan743x_pcidev_tbl); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_cistatic struct pci_driver lan743x_pcidev_driver = { 31288c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 31298c2ecf20Sopenharmony_ci .id_table = lan743x_pcidev_tbl, 31308c2ecf20Sopenharmony_ci .probe = lan743x_pcidev_probe, 31318c2ecf20Sopenharmony_ci .remove = lan743x_pcidev_remove, 31328c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 31338c2ecf20Sopenharmony_ci .driver.pm = &lan743x_pm_ops, 31348c2ecf20Sopenharmony_ci#endif 31358c2ecf20Sopenharmony_ci .shutdown = lan743x_pcidev_shutdown, 31368c2ecf20Sopenharmony_ci}; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_cimodule_pci_driver(lan743x_pcidev_driver); 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 31418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 31428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3143